diff --git a/Makefile b/Makefile index b9cd4775d7..a4cb08fc73 100644 --- a/Makefile +++ b/Makefile @@ -374,6 +374,7 @@ generate-e2e-templates-main: $(KUSTOMIZE) ## Generate test templates for the mai cp "$(RELEASE_DIR)/main/cluster-template-ignition.yaml" "$(E2E_GOVMOMI_TEMPLATE_DIR)/main/base/cluster-template-ignition.yaml" "$(KUSTOMIZE)" --load-restrictor LoadRestrictionsNone build "$(E2E_GOVMOMI_TEMPLATE_DIR)/main/base" > "$(E2E_GOVMOMI_TEMPLATE_DIR)/main/cluster-template.yaml" "$(KUSTOMIZE)" --load-restrictor LoadRestrictionsNone build "$(E2E_GOVMOMI_TEMPLATE_DIR)/main/hw-upgrade" > "$(E2E_GOVMOMI_TEMPLATE_DIR)/main/cluster-template-hw-upgrade.yaml" + "$(KUSTOMIZE)" --load-restrictor LoadRestrictionsNone build "$(E2E_GOVMOMI_TEMPLATE_DIR)/main/multi-disk" > "$(E2E_GOVMOMI_TEMPLATE_DIR)/main/cluster-template-multi-disk.yaml" "$(KUSTOMIZE)" --load-restrictor LoadRestrictionsNone build "$(E2E_GOVMOMI_TEMPLATE_DIR)/main/storage-policy" > "$(E2E_GOVMOMI_TEMPLATE_DIR)/main/cluster-template-storage-policy.yaml" "$(KUSTOMIZE)" --load-restrictor LoadRestrictionsNone build "$(E2E_GOVMOMI_TEMPLATE_DIR)/main/conformance" > "$(E2E_GOVMOMI_TEMPLATE_DIR)/main/cluster-template-conformance.yaml" # Since CAPI uses different flavor names for KCP and MD remediation using MHC diff --git a/test/e2e/config/vsphere.yaml b/test/e2e/config/vsphere.yaml index 8e91e48e3b..3ccda45e9f 100644 --- a/test/e2e/config/vsphere.yaml +++ b/test/e2e/config/vsphere.yaml @@ -173,6 +173,7 @@ providers: - sourcePath: "../../../test/e2e/data/infrastructure-vsphere-govmomi/main/cluster-template-ipam.yaml" - sourcePath: "../../../test/e2e/data/infrastructure-vsphere-govmomi/main/cluster-template-kcp-remediation.yaml" - sourcePath: "../../../test/e2e/data/infrastructure-vsphere-govmomi/main/cluster-template-md-remediation.yaml" + - sourcePath: "../../../test/e2e/data/infrastructure-vsphere-govmomi/main/cluster-template-multi-disk.yaml" - sourcePath: "../../../test/e2e/data/infrastructure-vsphere-govmomi/main/cluster-template-node-drain.yaml" - sourcePath: "../../../test/e2e/data/infrastructure-vsphere-govmomi/main/cluster-template-ownerrefs-finalizers.yaml" - sourcePath: "../../../test/e2e/data/infrastructure-vsphere-govmomi/main/cluster-template-pci.yaml" diff --git a/test/e2e/data/infrastructure-vsphere-govmomi/main/multi-disk/data-disks-patch.yaml b/test/e2e/data/infrastructure-vsphere-govmomi/main/multi-disk/data-disks-patch.yaml new file mode 100644 index 0000000000..1e58792edb --- /dev/null +++ b/test/e2e/data/infrastructure-vsphere-govmomi/main/multi-disk/data-disks-patch.yaml @@ -0,0 +1,25 @@ +apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 +kind: VSphereMachineTemplate +metadata: + name: '${CLUSTER_NAME}' + namespace: '${NAMESPACE}' +spec: + template: + spec: + dataDisks: + - name: "etcd" + sizeGiB: 10 + - name: "container-images" + sizeGiB: 20 +--- +apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 +kind: VSphereMachineTemplate +metadata: + name: '${CLUSTER_NAME}-worker' + namespace: '${NAMESPACE}' +spec: + template: + spec: + dataDisks: + - name: "container-images" + sizeGiB: 20 diff --git a/test/e2e/data/infrastructure-vsphere-govmomi/main/multi-disk/kustomization.yaml b/test/e2e/data/infrastructure-vsphere-govmomi/main/multi-disk/kustomization.yaml new file mode 100644 index 0000000000..e9b47748cb --- /dev/null +++ b/test/e2e/data/infrastructure-vsphere-govmomi/main/multi-disk/kustomization.yaml @@ -0,0 +1,6 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ../base +patchesStrategicMerge: + - data-disks-patch.yaml diff --git a/test/e2e/multi-disk_test.go b/test/e2e/multi-disk_test.go new file mode 100644 index 0000000000..832b8fdaec --- /dev/null +++ b/test/e2e/multi-disk_test.go @@ -0,0 +1,121 @@ +/* +Copyright 2022 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package e2e + +import ( + "context" + "fmt" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/vmware/govmomi/vim25/types" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/cluster-api/test/framework/clusterctl" + . "sigs.k8s.io/cluster-api/test/framework/ginkgoextensions" + capiutil "sigs.k8s.io/cluster-api/util" +) + +type DiskSpecInput struct { + InfraClients + Global GlobalInput + SpecName string + Namespace *corev1.Namespace + Template string + ToVersion string +} + +var _ = Describe("Multi-Disk support", func() { + const specName = "multi-disk" + Setup(specName, func(testSpecificSettingsGetter func() testSettings) { + var ( + namespace *corev1.Namespace + ) + + BeforeEach(func() { + Expect(bootstrapClusterProxy).NotTo(BeNil(), "BootstrapClusterProxy can't be nil") + namespace = setupSpecNamespace(specName, testSpecificSettingsGetter().PostNamespaceCreatedFunc) + }) + + AfterEach(func() { + cleanupSpecNamespace(namespace) + }) + + It("should create control plane with multiple disks", func() { + Expect(e2eConfig.GetVariable("VSPHERE_TEMPLATE")).NotTo(BeEmpty()) + + VerifyDisks(ctx, DiskSpecInput{ + SpecName: specName, + Namespace: namespace, + Template: e2eConfig.GetVariable("VSPHERE_TEMPLATE"), + ToVersion: "vmx-17", + InfraClients: InfraClients{ + Client: vsphereClient, + RestClient: restClient, + Finder: vsphereFinder, + }, + Global: GlobalInput{ + BootstrapClusterProxy: bootstrapClusterProxy, + ClusterctlConfigPath: testSpecificSettingsGetter().ClusterctlConfigPath, + E2EConfig: e2eConfig, + ArtifactFolder: artifactFolder, + }, + }) + }) + }) +}) + +func VerifyDisks(ctx context.Context, input DiskSpecInput) { + var ( + specName = input.SpecName + namespace = input.Namespace + clusterResources = new(clusterctl.ApplyClusterTemplateAndWaitResult) + ) + + clusterName := fmt.Sprintf("%s-%s", specName, capiutil.RandomString(6)) + By("Creating a cluster") + configCluster := defaultConfigCluster(clusterName, namespace.Name, specName, 1, 1, input.Global) + + clusterctl.ApplyClusterTemplateAndWait(ctx, clusterctl.ApplyClusterTemplateAndWaitInput{ + ClusterProxy: input.Global.BootstrapClusterProxy, + ConfigCluster: configCluster, + WaitForClusterIntervals: input.Global.E2EConfig.GetIntervals(specName, "wait-cluster"), + WaitForControlPlaneIntervals: input.Global.E2EConfig.GetIntervals(specName, "wait-control-plane"), + WaitForMachineDeployments: input.Global.E2EConfig.GetIntervals(specName, "wait-worker-nodes"), + }, clusterResources) + + Byf("Fetching the VSphereVM objects for the cluster %s", clusterName) + vms := getVSphereVMsForCluster(clusterName, namespace.Name) + + By("Verifying the disks attached to the VMs") + for _, vm := range vms.Items { + // vSphere machine object should have the data disks configured. We will add +1 to the count since the os image + // needs to be included for comparison. + Byf("VM %s Spec has %d DataDisks defined", vm.Name, len(vm.Spec.DataDisks)) + diskCount := 1 + len(vm.Spec.DataDisks) + Expect(diskCount).ToNot(Equal(1), "Total disk count should be larger than 1 for this test") + + vmObj, err := input.Finder.VirtualMachine(ctx, vm.Name) + Expect(err).NotTo(HaveOccurred()) + + devices, err := vmObj.Device(ctx) + Expect(err).NotTo(HaveOccurred()) + + // We expect control plane VMs to have 3 disks, and the compute VMs will have 2. + disks := devices.SelectByType((*types.VirtualDisk)(nil)) + Expect(disks).To(HaveLen(diskCount), fmt.Sprintf("Disk count of VM should be %d", diskCount)) + } +}