From d18f305e889b24a83cd8b5a93e23078761e1a733 Mon Sep 17 00:00:00 2001 From: Hitesh Pattanayak <48874082+HiteshRepo@users.noreply.github.com> Date: Wed, 6 Sep 2023 21:06:13 +0530 Subject: [PATCH] check existence of machine config before further operations (#6171) --- ...r_tinkerbell_mismatched_external_etcd.yaml | 214 ++++++++++++++++++ ..._tinkerbell_mismatched_machine_config.yaml | 56 +++++ pkg/providers/tinkerbell/tinkerbell.go | 40 ++++ pkg/providers/tinkerbell/tinkerbell_test.go | 98 ++++++++ 4 files changed, 408 insertions(+) create mode 100644 pkg/providers/tinkerbell/testdata/cluster_tinkerbell_mismatched_external_etcd.yaml create mode 100644 pkg/providers/tinkerbell/testdata/cluster_tinkerbell_mismatched_machine_config.yaml diff --git a/pkg/providers/tinkerbell/testdata/cluster_tinkerbell_mismatched_external_etcd.yaml b/pkg/providers/tinkerbell/testdata/cluster_tinkerbell_mismatched_external_etcd.yaml new file mode 100644 index 000000000000..6c5bef09412a --- /dev/null +++ b/pkg/providers/tinkerbell/testdata/cluster_tinkerbell_mismatched_external_etcd.yaml @@ -0,0 +1,214 @@ +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: Cluster +metadata: + name: test + namespace: test-namespace +spec: + clusterNetwork: + cni: cilium + pods: + cidrBlocks: + - 192.168.0.0/16 + services: + cidrBlocks: + - 10.96.0.0/12 + controlPlaneConfiguration: + upgradeRolloutStrategy: + type: "RollingUpdate" + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + count: 1 + endpoint: + host: 1.2.3.4 + machineGroupRef: + name: test-cp + kind: TinkerbellMachineConfig + datacenterRef: + kind: TinkerbellDatacenterConfig + name: test + externalEtcdConfiguration: + count: 1 + machineGroupRef: + name: test-etcd + kind: TinkerbellMachineConfig + kubernetesVersion: "1.21" + managementCluster: + name: test + workerNodeGroupConfigurations: + - count: 1 + machineGroupRef: + name: test-md + kind: TinkerbellMachineConfig + upgradeRolloutStrategy: + type: "RollingUpdate" + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + +--- +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: TinkerbellDatacenterConfig +metadata: + name: test + namespace: test-namespace +spec: + tinkerbellIP: "5.6.7.8" + osImageURL: "https://ubuntu.gz" + +--- +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: TinkerbellMachineConfig +metadata: + name: test-cp + namespace: test-namespace +spec: + hardwareSelector: + type: "cp" + osFamily: ubuntu + templateRef: + kind: TinkerbellTemplateConfig + name: tink-test + users: + - name: tink-user + sshAuthorizedKeys: + - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC1BK73XhIzjX+meUr7pIYh6RHbvI3tmHeQIXY5lv7aztN1UoX+bhPo3dwo2sfSQn5kuxgQdnxIZ/CTzy0p0GkEYVv3gwspCeurjmu0XmrdmaSGcGxCEWT/65NtvYrQtUE5ELxJ+N/aeZNlK2B7IWANnw/82913asXH4VksV1NYNduP0o1/G4XcwLLSyVFB078q/oEnmvdNIoS61j4/o36HVtENJgYr0idcBvwJdvcGxGnPaqOhx477t+kfJAa5n5dSA5wilIaoXH5i1Tf/HsTCM52L+iNCARvQzJYZhzbWI1MDQwzILtIBEQCJsl2XSqIupleY8CxqQ6jCXt2mhae+wPc3YmbO5rFvr2/EvC57kh3yDs1Nsuj8KOvD78KeeujbR8n8pScm3WDp62HFQ8lEKNdeRNj6kB8WnuaJvPnyZfvzOhwG65/9w13IBl7B1sWxbFnq2rMpm5uHVK7mAmjL0Tt8zoDhcE1YJEnp9xte3/pvmKPkST5Q/9ZtR9P5sI+02jY0fvPkPyC03j2gsPixG7rpOCwpOdbny4dcj0TDeeXJX8er+oVfJuLYz0pNWJcT2raDdFfcqvYA0B0IyNYlj5nWX4RuEcyT3qocLReWPnZojetvAG/H8XwOh7fEVGqHAKOVSnPXCSQJPl6s0H12jPJBDJMTydtYPEszl4/CeQ==" +--- +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: TinkerbellMachineConfig +metadata: + name: test-md + namespace: test-namespace +spec: + hardwareSelector: + type: "worker" + osFamily: ubuntu + templateRef: + kind: TinkerbellTemplateConfig + name: tink-test + users: + - name: tink-user + sshAuthorizedKeys: + - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC1BK73XhIzjX+meUr7pIYh6RHbvI3tmHeQIXY5lv7aztN1UoX+bhPo3dwo2sfSQn5kuxgQdnxIZ/CTzy0p0GkEYVv3gwspCeurjmu0XmrdmaSGcGxCEWT/65NtvYrQtUE5ELxJ+N/aeZNlK2B7IWANnw/82913asXH4VksV1NYNduP0o1/G4XcwLLSyVFB078q/oEnmvdNIoS61j4/o36HVtENJgYr0idcBvwJdvcGxGnPaqOhx477t+kfJAa5n5dSA5wilIaoXH5i1Tf/HsTCM52L+iNCARvQzJYZhzbWI1MDQwzILtIBEQCJsl2XSqIupleY8CxqQ6jCXt2mhae+wPc3YmbO5rFvr2/EvC57kh3yDs1Nsuj8KOvD78KeeujbR8n8pScm3WDp62HFQ8lEKNdeRNj6kB8WnuaJvPnyZfvzOhwG65/9w13IBl7B1sWxbFnq2rMpm5uHVK7mAmjL0Tt8zoDhcE1YJEnp9xte3/pvmKPkST5Q/9ZtR9P5sI+02jY0fvPkPyC03j2gsPixG7rpOCwpOdbny4dcj0TDeeXJX8er+oVfJuLYz0pNWJcT2raDdFfcqvYA0B0IyNYlj5nWX4RuEcyT3qocLReWPnZojetvAG/H8XwOh7fEVGqHAKOVSnPXCSQJPl6s0H12jPJBDJMTydtYPEszl4/CeQ== testemail@test.com" +--- +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: TinkerbellMachineConfig +metadata: + name: test-etcd-1 + namespace: test-namespace +spec: + hardwareSelector: + type: "etcd" + osFamily: ubuntu + templateRef: + kind: TinkerbellTemplateConfig + name: tink-test + users: + - name: tink-user + sshAuthorizedKeys: + - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC1BK73XhIzjX+meUr7pIYh6RHbvI3tmHeQIXY5lv7aztN1UoX+bhPo3dwo2sfSQn5kuxgQdnxIZ/CTzy0p0GkEYVv3gwspCeurjmu0XmrdmaSGcGxCEWT/65NtvYrQtUE5ELxJ+N/aeZNlK2B7IWANnw/82913asXH4VksV1NYNduP0o1/G4XcwLLSyVFB078q/oEnmvdNIoS61j4/o36HVtENJgYr0idcBvwJdvcGxGnPaqOhx477t+kfJAa5n5dSA5wilIaoXH5i1Tf/HsTCM52L+iNCARvQzJYZhzbWI1MDQwzILtIBEQCJsl2XSqIupleY8CxqQ6jCXt2mhae+wPc3YmbO5rFvr2/EvC57kh3yDs1Nsuj8KOvD78KeeujbR8n8pScm3WDp62HFQ8lEKNdeRNj6kB8WnuaJvPnyZfvzOhwG65/9w13IBl7B1sWxbFnq2rMpm5uHVK7mAmjL0Tt8zoDhcE1YJEnp9xte3/pvmKPkST5Q/9ZtR9P5sI+02jY0fvPkPyC03j2gsPixG7rpOCwpOdbny4dcj0TDeeXJX8er+oVfJuLYz0pNWJcT2raDdFfcqvYA0B0IyNYlj5nWX4RuEcyT3qocLReWPnZojetvAG/H8XwOh7fEVGqHAKOVSnPXCSQJPl6s0H12jPJBDJMTydtYPEszl4/CeQ== testemail@test.com" +--- +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: TinkerbellTemplateConfig +metadata: + name: tink-test +spec: + template: + global_timeout: 6000 + id: "" + name: tink-test + tasks: + - actions: + - environment: + COMPRESSED: "true" + DEST_DISK: /dev/sda + IMG_URL: "" + image: image2disk:v1.0.0 + name: stream-image + timeout: 360 + - environment: + BLOCK_DEVICE: /dev/sda2 + CHROOT: "y" + CMD_LINE: apt -y update && apt -y install openssl + DEFAULT_INTERPRETER: /bin/sh -c + FS_TYPE: ext4 + image: cexec:v1.0.0 + name: install-openssl + timeout: 90 + - environment: + CONTENTS: | + network: + version: 2 + renderer: networkd + ethernets: + eno1: + dhcp4: true + eno2: + dhcp4: true + eno3: + dhcp4: true + eno4: + dhcp4: true + DEST_DISK: /dev/sda2 + DEST_PATH: /etc/netplan/config.yaml + DIRMODE: "0755" + FS_TYPE: ext4 + GID: "0" + MODE: "0644" + UID: "0" + image: writefile:v1.0.0 + name: write-netplan + timeout: 90 + - environment: + CONTENTS: | + datasource: + Ec2: + metadata_urls: [] + strict_id: false + system_info: + default_user: + name: tink + groups: [wheel, adm] + sudo: ["ALL=(ALL) NOPASSWD:ALL"] + shell: /bin/bash + manage_etc_hosts: localhost + warnings: + dsid_missing_source: off + DEST_DISK: /dev/sda2 + DEST_PATH: /etc/cloud/cloud.cfg.d/10_tinkerbell.cfg + DIRMODE: "0700" + FS_TYPE: ext4 + GID: "0" + MODE: "0600" + image: writefile:v1.0.0 + name: add-tink-cloud-init-config + timeout: 90 + - environment: + CONTENTS: | + datasource: Ec2 + DEST_DISK: /dev/sda2 + DEST_PATH: /etc/cloud/ds-identify.cfg + DIRMODE: "0700" + FS_TYPE: ext4 + GID: "0" + MODE: "0600" + UID: "0" + image: writefile:v1.0.0 + name: add-tink-cloud-init-ds-config + timeout: 90 + - environment: + BLOCK_DEVICE: /dev/sda2 + FS_TYPE: ext4 + image: kexec:v1.0.0 + name: kexec-image + pid: host + timeout: 90 + name: tink-test + volumes: + - /dev:/dev + - /dev/console:/dev/console + - /lib/firmware:/lib/firmware:ro + worker: "{{.device_1}}" + version: "0.1" +--- + diff --git a/pkg/providers/tinkerbell/testdata/cluster_tinkerbell_mismatched_machine_config.yaml b/pkg/providers/tinkerbell/testdata/cluster_tinkerbell_mismatched_machine_config.yaml new file mode 100644 index 000000000000..d48dd0626400 --- /dev/null +++ b/pkg/providers/tinkerbell/testdata/cluster_tinkerbell_mismatched_machine_config.yaml @@ -0,0 +1,56 @@ +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: Cluster +metadata: + name: single-node +spec: + clusterNetwork: + cniConfig: + cilium: {} + pods: + cidrBlocks: + - 192.168.0.0/16 + services: + cidrBlocks: + - 10.96.0.0/12 + controlPlaneConfiguration: + count: 1 + upgradeRolloutStrategy: + type: "RollingUpdate" + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + endpoint: + host: 1.2.3.4 + machineGroupRef: + kind: TinkerbellMachineConfig + name: single-node-cp + taints: [] + datacenterRef: + kind: TinkerbellDatacenterConfig + name: single-node + kubernetesVersion: "1.21" + managementCluster: + name: single-node +--- +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: TinkerbellDatacenterConfig +metadata: + name: single-node +spec: + tinkerbellIP: "5.6.7.8" + osImageURL: "https://ubuntu.gz" +--- +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: TinkerbellMachineConfig +metadata: + name: single-node-cp-1 +spec: + hardwareSelector: + type: cp + osFamily: ubuntu + templateRef: {} + users: + - name: tink-user + sshAuthorizedKeys: + - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC1BK73XhIzjX+meUr7pIYh6RHbvI3tmHeQIXY5lv7aztN1UoX+bhPo3dwo2sfSQn5kuxgQdnxIZ/CTzy0p0GkEYVv3gwspCeurjmu0XmrdmaSGcGxCEWT/65NtvYrQtUE5ELxJ+N/aeZNlK2B7IWANnw/82913asXH4VksV1NYNduP0o1/G4XcwLLSyVFB078q/oEnmvdNIoS61j4/o36HVtENJgYr0idcBvwJdvcGxGnPaqOhx477t+kfJAa5n5dSA5wilIaoXH5i1Tf/HsTCM52L+iNCARvQzJYZhzbWI1MDQwzILtIBEQCJsl2XSqIupleY8CxqQ6jCXt2mhae+wPc3YmbO5rFvr2/EvC57kh3yDs1Nsuj8KOvD78KeeujbR8n8pScm3WDp62HFQ8lEKNdeRNj6kB8WnuaJvPnyZfvzOhwG65/9w13IBl7B1sWxbFnq2rMpm5uHVK7mAmjL0Tt8zoDhcE1YJEnp9xte3/pvmKPkST5Q/9ZtR9P5sI+02jY0fvPkPyC03j2gsPixG7rpOCwpOdbny4dcj0TDeeXJX8er+oVfJuLYz0pNWJcT2raDdFfcqvYA0B0IyNYlj5nWX4RuEcyT3qocLReWPnZojetvAG/H8XwOh7fEVGqHAKOVSnPXCSQJPl6s0H12jPJBDJMTydtYPEszl4/CeQ== testemail@test.com" +--- diff --git a/pkg/providers/tinkerbell/tinkerbell.go b/pkg/providers/tinkerbell/tinkerbell.go index f6601bd4340b..edf1b7967aea 100644 --- a/pkg/providers/tinkerbell/tinkerbell.go +++ b/pkg/providers/tinkerbell/tinkerbell.go @@ -43,6 +43,8 @@ var ( // errExternalEtcdUnsupported is returned from create or update when the user attempts to create // or upgrade a cluster with an external etcd configuration. errExternalEtcdUnsupported = errors.New("external etcd configuration is unsupported") + + referrencedMachineConfigsAvailabilityErrMsg = "some machine configs (%s) referenced in cluster config are not provided" ) type Provider struct { @@ -114,6 +116,11 @@ func NewProvider( skipIpCheck bool, ) (*Provider, error) { var controlPlaneMachineSpec, workerNodeGroupMachineSpec, etcdMachineSpec *v1alpha1.TinkerbellMachineConfigSpec + + if err := validateRefrencedMachineConfigsAvailability(machineConfigs, clusterConfig); err != nil { + return nil, err + } + if clusterConfig.Spec.ControlPlaneConfiguration.MachineGroupRef != nil && machineConfigs[clusterConfig.Spec.ControlPlaneConfiguration.MachineGroupRef.Name] != nil { controlPlaneMachineSpec = &machineConfigs[clusterConfig.Spec.ControlPlaneConfiguration.MachineGroupRef.Name].Spec } @@ -311,3 +318,36 @@ func (p *Provider) ChangeDiff(currentSpec, newSpec *cluster.Spec) *types.Compone func (p *Provider) InstallCustomProviderComponents(ctx context.Context, kubeconfigFile string) error { return nil } + +func validateRefrencedMachineConfigsAvailability(machineConfigs map[string]*v1alpha1.TinkerbellMachineConfig, clusterConfig *v1alpha1.Cluster) error { + unavailableMachineConfigNames := "" + + controlPlaneMachineName := clusterConfig.Spec.ControlPlaneConfiguration.MachineGroupRef.Name + if _, ok := machineConfigs[controlPlaneMachineName]; !ok { + unavailableMachineConfigNames = fmt.Sprintf("%s, %s", unavailableMachineConfigNames, controlPlaneMachineName) + } + + for _, workerNodeGroupConfiguration := range clusterConfig.Spec.WorkerNodeGroupConfigurations { + if workerNodeGroupConfiguration.MachineGroupRef == nil { + continue + } + workerMachineName := workerNodeGroupConfiguration.MachineGroupRef.Name + if _, ok := machineConfigs[workerMachineName]; !ok { + unavailableMachineConfigNames = fmt.Sprintf("%s, %s", unavailableMachineConfigNames, workerMachineName) + } + } + + if clusterConfig.Spec.ExternalEtcdConfiguration != nil { + etcdMachineName := clusterConfig.Spec.ExternalEtcdConfiguration.MachineGroupRef.Name + if _, ok := machineConfigs[etcdMachineName]; !ok { + unavailableMachineConfigNames = fmt.Sprintf("%s, %s", unavailableMachineConfigNames, etcdMachineName) + } + } + + if len(unavailableMachineConfigNames) > 2 { + unavailableMachineConfigNames = unavailableMachineConfigNames[2:] + return fmt.Errorf(referrencedMachineConfigsAvailabilityErrMsg, unavailableMachineConfigNames) + } + + return nil +} diff --git a/pkg/providers/tinkerbell/tinkerbell_test.go b/pkg/providers/tinkerbell/tinkerbell_test.go index 5142411632b3..66c96638c5b0 100644 --- a/pkg/providers/tinkerbell/tinkerbell_test.go +++ b/pkg/providers/tinkerbell/tinkerbell_test.go @@ -1946,6 +1946,104 @@ func TestTinkerbellProvider_GenerateCAPISpecForUpgrade_RegistryMirror(t *testing test.AssertContentToFile(t, string(cp), "testdata/expected_results_cluster_tinkerbell_upgrade_registry_mirror.yaml") } +func TestTinkerbellProviderGetMachineConfigsWithMismatchedAndExternalEtcd(t *testing.T) { + clusterSpecManifest := "cluster_tinkerbell_mismatched_external_etcd.yaml" + mockCtrl := gomock.NewController(t) + docker := stackmocks.NewMockDocker(mockCtrl) + helm := stackmocks.NewMockHelm(mockCtrl) + kubectl := mocks.NewMockProviderKubectlClient(mockCtrl) + writer := filewritermocks.NewMockFileWriter(mockCtrl) + forceCleanup := false + + clusterSpec := givenClusterSpec(t, clusterSpecManifest) + datacenterConfig := givenDatacenterConfig(t, clusterSpecManifest) + machineConfigs := givenMachineConfigs(t, clusterSpecManifest) + + hardwareFile := "./testdata/hardware.csv" + _, err := NewProvider( + datacenterConfig, + machineConfigs, + clusterSpec.Cluster, + hardwareFile, + writer, + docker, + helm, + kubectl, + testIP, + test.FakeNow, + forceCleanup, + false, + ) + + expectedErrorMessage := fmt.Sprintf(referrencedMachineConfigsAvailabilityErrMsg, "test-etcd") + + assertError(t, expectedErrorMessage, err) +} + +func TestTinkerbellProviderGetMachineConfigsWithMatchedAndExternalEtcd(t *testing.T) { + clusterSpecManifest := "cluster_tinkerbell_external_etcd.yaml" + mockCtrl := gomock.NewController(t) + docker := stackmocks.NewMockDocker(mockCtrl) + helm := stackmocks.NewMockHelm(mockCtrl) + kubectl := mocks.NewMockProviderKubectlClient(mockCtrl) + stackInstaller := stackmocks.NewMockStackInstaller(mockCtrl) + writer := filewritermocks.NewMockFileWriter(mockCtrl) + forceCleanup := false + + clusterSpec := givenClusterSpec(t, clusterSpecManifest) + datacenterConfig := givenDatacenterConfig(t, clusterSpecManifest) + machineConfigs := givenMachineConfigs(t, clusterSpecManifest) + + provider := newProvider(datacenterConfig, machineConfigs, clusterSpec.Cluster, writer, docker, helm, kubectl, forceCleanup) + provider.stackInstaller = stackInstaller + + numberOfMatchingMachineConfigs := 3 + + got := provider.MachineConfigs(clusterSpec) + assert.Equal(t, numberOfMatchingMachineConfigs, len(got)) + + gotMachineConfigNames := make([]string, 0) + for _, mc := range got { + gotMachineConfigNames = append(gotMachineConfigNames, mc.GetName()) + } + + assert.Equal(t, numberOfMatchingMachineConfigs, len(gotMachineConfigNames)) +} + +func TestTinkerbellProviderGetMachineConfigsWithMismatchedMachineConfig(t *testing.T) { + clusterSpecManifest := "cluster_tinkerbell_mismatched_machine_config.yaml" + mockCtrl := gomock.NewController(t) + docker := stackmocks.NewMockDocker(mockCtrl) + helm := stackmocks.NewMockHelm(mockCtrl) + kubectl := mocks.NewMockProviderKubectlClient(mockCtrl) + writer := filewritermocks.NewMockFileWriter(mockCtrl) + forceCleanup := false + + clusterSpec := givenClusterSpec(t, clusterSpecManifest) + datacenterConfig := givenDatacenterConfig(t, clusterSpecManifest) + machineConfigs := givenMachineConfigs(t, clusterSpecManifest) + + hardwareFile := "./testdata/hardware.csv" + _, err := NewProvider( + datacenterConfig, + machineConfigs, + clusterSpec.Cluster, + hardwareFile, + writer, + docker, + helm, + kubectl, + testIP, + test.FakeNow, + forceCleanup, + false, + ) + + expectedErrorMessage := fmt.Sprintf(referrencedMachineConfigsAvailabilityErrMsg, "single-node-cp") + + assertError(t, expectedErrorMessage, err) +} + func TestTinkerbellProvider_GenerateCAPISpecForUpgrade_CertBundles(t *testing.T) { clusterSpecManifest := "cluster_bottlerocket_cert_bundles_config.yaml" mockCtrl := gomock.NewController(t)