diff --git a/Makefile b/Makefile index 59d93e713..a4c5528b0 100644 --- a/Makefile +++ b/Makefile @@ -55,7 +55,7 @@ unit: .localtestenv ## Run unit tests .PHONY: e2e e2e: ## Run e2e tests against active kubeconfig - ./hack/test.sh "./e2e/..." 120m + ./hack/test.sh "./e2e/..." 180m run: ## Run the operator against the configured Kubernetes cluster oc -n openshift-cluster-api patch lease cluster-capi-operator-leader -p '{"spec":{"acquireTime": null, "holderIdentity": null, "renewTime": null}}' --type=merge diff --git a/e2e/machine_migration_capi_authoritative_test.go b/e2e/machine_migration_capi_authoritative_test.go index e78b53c95..9dafe9d30 100644 --- a/e2e/machine_migration_capi_authoritative_test.go +++ b/e2e/machine_migration_capi_authoritative_test.go @@ -15,6 +15,21 @@ import ( ) var _ = Describe("[sig-cluster-lifecycle][OCPFeatureGate:MachineAPIMigration] Machine Migration CAPI Authoritative Tests", Ordered, func() { + var capiMachineAuthCAPISameName *clusterv1.Machine + var mapiMachineAuthCAPISameName *mapiv1beta1.Machine + + var mapiMachineAuthCAPI *mapiv1beta1.Machine + var capiMachineMirrorAuthCAPI *clusterv1.Machine + + var mapiMachineDeleteMAPI *mapiv1beta1.Machine + var capiMachineMirrorDeleteMAPI *clusterv1.Machine + + var mapiMachineDeleteCAPI *mapiv1beta1.Machine + var capiMachineMirrorDeleteCAPI *clusterv1.Machine + + var mapiMachineRoundTrip *mapiv1beta1.Machine + var capiMachineMirrorRoundTrip *clusterv1.Machine + BeforeAll(func() { if platform != configv1.AWSPlatformType { Skip(fmt.Sprintf("Skipping tests on %s, this is only supported on AWS", platform)) @@ -23,146 +38,133 @@ var _ = Describe("[sig-cluster-lifecycle][OCPFeatureGate:MachineAPIMigration] Ma if !capiframework.IsMachineAPIMigrationEnabled(ctx, cl) { Skip("Skipping, this feature is only supported on MachineAPIMigration enabled clusters") } + + By("Creating CAPI Machine first for same-name scenario") + capiMachineAuthCAPISameName = createCAPIMachine(ctx, cl, UniqueName("capi-auth-capi")) + + By("Creating MAPI Machine with AuthoritativeAPI: ClusterAPI and existing CAPI Machine with same name") + mapiMachineAuthCAPISameName = createMAPIMachineWithAuthority(ctx, cl, capiMachineAuthCAPISameName.Name, mapiv1beta1.MachineAuthorityClusterAPI) + + By("Creating MAPI Machines with AuthoritativeAPI: ClusterAPI") + mapiMachineAuthCAPI = createMAPIMachineWithAuthority(ctx, cl, UniqueName("capi-auth-capi-no-existing"), mapiv1beta1.MachineAuthorityClusterAPI) + mapiMachineDeleteMAPI = createMAPIMachineWithAuthority(ctx, cl, UniqueName("capi-delete-mapi"), mapiv1beta1.MachineAuthorityClusterAPI) + mapiMachineDeleteCAPI = createMAPIMachineWithAuthority(ctx, cl, UniqueName("capi-delete-capi"), mapiv1beta1.MachineAuthorityClusterAPI) + mapiMachineRoundTrip = createMAPIMachineWithAuthority(ctx, cl, UniqueName("capi-roundtrip"), mapiv1beta1.MachineAuthorityClusterAPI) + + By("Getting all CAPI Machine mirrors") + capiMachineMirrorAuthCAPI = capiframework.GetMachine(cl, mapiMachineAuthCAPI.Name, capiframework.CAPINamespace) + capiMachineMirrorDeleteMAPI = capiframework.GetMachine(cl, mapiMachineDeleteMAPI.Name, capiframework.CAPINamespace) + capiMachineMirrorDeleteCAPI = capiframework.GetMachine(cl, mapiMachineDeleteCAPI.Name, capiframework.CAPINamespace) + capiMachineMirrorRoundTrip = capiframework.GetMachine(cl, mapiMachineRoundTrip.Name, capiframework.CAPINamespace) + + By("Waiting for CAPI Machines to reach Running state") + verifyMachineRunning(cl, capiMachineAuthCAPISameName) + verifyMachineRunning(cl, capiMachineMirrorAuthCAPI) + verifyMachineRunning(cl, capiMachineMirrorDeleteMAPI) + verifyMachineRunning(cl, capiMachineMirrorDeleteCAPI) + verifyMachineRunning(cl, capiMachineMirrorRoundTrip) }) var _ = Describe("Create MAPI Machine", Ordered, func() { - var mapiMachineAuthCAPIName = "machine-authoritativeapi-capi" - var newCapiMachine *clusterv1.Machine - var newMapiMachine *mapiv1beta1.Machine + AfterAll(func() { + By("Cleaning up Create test resources") + cleanupMachineResources( + ctx, + cl, + []*clusterv1.Machine{capiMachineAuthCAPISameName, capiMachineMirrorAuthCAPI}, + []*mapiv1beta1.Machine{mapiMachineAuthCAPISameName, mapiMachineAuthCAPI}, + ) + }) Context("with spec.authoritativeAPI: ClusterAPI and already existing CAPI Machine with same name", func() { - BeforeAll(func() { - newCapiMachine = createCAPIMachine(ctx, cl, mapiMachineAuthCAPIName) - newMapiMachine = createMAPIMachineWithAuthority(ctx, cl, mapiMachineAuthCAPIName, mapiv1beta1.MachineAuthorityClusterAPI) - - DeferCleanup(func() { - By("Cleaning up machine resources") - cleanupMachineResources( - ctx, - cl, - []*clusterv1.Machine{newCapiMachine}, - []*mapiv1beta1.Machine{newMapiMachine}, - ) - }) - }) - It("should find MAPI Machine .status.authoritativeAPI to equal ClusterAPI", func() { - verifyMachineAuthoritative(newMapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachineAuthoritative(mapiMachineAuthCAPISameName, mapiv1beta1.MachineAuthorityClusterAPI) }) + It("should verify MAPI Machine Synchronized condition is True", func() { - verifyMAPIMachineSynchronizedCondition(newMapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMAPIMachineSynchronizedCondition(mapiMachineAuthCAPISameName, mapiv1beta1.MachineAuthorityClusterAPI) }) + It("should verify MAPI Machine Paused condition is True", func() { - verifyMachinePausedCondition(newMapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachinePausedCondition(mapiMachineAuthCAPISameName, mapiv1beta1.MachineAuthorityClusterAPI) }) + It("should verify CAPI Machine Paused condition is False", func() { - verifyMachinePausedCondition(newCapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachinePausedCondition(capiMachineAuthCAPISameName, mapiv1beta1.MachineAuthorityClusterAPI) }) }) Context("with spec.authoritativeAPI: ClusterAPI and no existing CAPI Machine with same name", func() { - BeforeAll(func() { - newMapiMachine = createMAPIMachineWithAuthority(ctx, cl, mapiMachineAuthCAPIName, mapiv1beta1.MachineAuthorityClusterAPI) - - DeferCleanup(func() { - By("Cleaning up machine resources") - cleanupMachineResources( - ctx, - cl, - []*clusterv1.Machine{}, - []*mapiv1beta1.Machine{newMapiMachine}, - ) - }) - }) - It("should verify CAPI Machine gets created and becomes Running", func() { - newCapiMachine = capiframework.GetMachine(cl, newMapiMachine.Name, capiframework.CAPINamespace) - verifyMachineRunning(cl, newCapiMachine) + capiMachineMirrorAuthCAPI = capiframework.GetMachine(cl, mapiMachineAuthCAPI.Name, capiframework.CAPINamespace) + verifyMachineRunning(cl, capiMachineMirrorAuthCAPI) }) It("should find MAPI Machine .status.authoritativeAPI to equal ClusterAPI", func() { - verifyMachineAuthoritative(newMapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachineAuthoritative(mapiMachineAuthCAPI, mapiv1beta1.MachineAuthorityClusterAPI) }) + It("should verify MAPI Machine Synchronized condition is True", func() { - verifyMAPIMachineSynchronizedCondition(newMapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMAPIMachineSynchronizedCondition(mapiMachineAuthCAPI, mapiv1beta1.MachineAuthorityClusterAPI) }) + It("should verify MAPI Machine Paused condition is True", func() { - verifyMachinePausedCondition(newMapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachinePausedCondition(mapiMachineAuthCAPI, mapiv1beta1.MachineAuthorityClusterAPI) }) It("should verify that the non-authoritative MAPI Machine has an authoritative CAPI Machine mirror", func() { - newCapiMachine = capiframework.GetMachine(cl, mapiMachineAuthCAPIName, capiframework.CAPINamespace) + capiMachineMirrorAuthCAPI = capiframework.GetMachine(cl, mapiMachineAuthCAPI.Name, capiframework.CAPINamespace) }) + It("should verify CAPI Machine Paused condition is False", func() { - verifyMachinePausedCondition(newCapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachinePausedCondition(capiMachineMirrorAuthCAPI, mapiv1beta1.MachineAuthorityClusterAPI) }) }) }) var _ = Describe("Deleting CAPI Machines", Ordered, func() { - var mapiMachineAuthCAPINameDeletion = "machine-authoritativeapi-capi-deletion" - var newCapiMachine *clusterv1.Machine - var newMapiMachine *mapiv1beta1.Machine + AfterAll(func() { + By("Cleaning up Delete test resources") + cleanupMachineResources( + ctx, + cl, + []*clusterv1.Machine{capiMachineMirrorDeleteMAPI, capiMachineMirrorDeleteCAPI}, + []*mapiv1beta1.Machine{mapiMachineDeleteMAPI, mapiMachineDeleteCAPI}, + ) + }) Context("with spec.authoritativeAPI: ClusterAPI", func() { Context("when deleting the non-authoritative MAPI Machine", func() { - BeforeAll(func() { - newMapiMachine = createMAPIMachineWithAuthority(ctx, cl, mapiMachineAuthCAPINameDeletion, mapiv1beta1.MachineAuthorityClusterAPI) - newCapiMachine = capiframework.GetMachine(cl, newMapiMachine.Name, capiframework.CAPINamespace) - verifyMachineRunning(cl, newCapiMachine) - - DeferCleanup(func() { - By("Cleaning up machine resources") - cleanupMachineResources( - ctx, - cl, - []*clusterv1.Machine{newCapiMachine}, - []*mapiv1beta1.Machine{newMapiMachine}, - ) - }) - }) It("should delete MAPI Machine", func() { - mapiframework.DeleteMachines(ctx, cl, newMapiMachine) - mapiframework.WaitForMachinesDeleted(cl, newMapiMachine) + mapiframework.DeleteMachines(ctx, cl, mapiMachineDeleteMAPI) + mapiframework.WaitForMachinesDeleted(cl, mapiMachineDeleteMAPI) }) It("should verify the CAPI machine is deleted", func() { - verifyResourceRemoved(newCapiMachine) + verifyResourceRemoved(capiMachineMirrorDeleteMAPI) }) + It("should verify the AWS machine is deleted", func() { verifyResourceRemoved(&awsv1.AWSMachine{ TypeMeta: metav1.TypeMeta{Kind: "AWSMachine", APIVersion: awsv1.GroupVersion.String()}, - ObjectMeta: metav1.ObjectMeta{Name: mapiMachineAuthCAPINameDeletion, Namespace: capiframework.CAPINamespace}, + ObjectMeta: metav1.ObjectMeta{Name: mapiMachineDeleteMAPI.Name, Namespace: capiframework.CAPINamespace}, }) }) }) - Context("when deleting the authoritative CAPI Machine", func() { - BeforeAll(func() { - newMapiMachine = createMAPIMachineWithAuthority(ctx, cl, mapiMachineAuthCAPINameDeletion, mapiv1beta1.MachineAuthorityClusterAPI) - newCapiMachine = capiframework.GetMachine(cl, newMapiMachine.Name, capiframework.CAPINamespace) - verifyMachineRunning(cl, newCapiMachine) - DeferCleanup(func() { - By("Cleaning up machine resources") - cleanupMachineResources( - ctx, - cl, - []*clusterv1.Machine{newCapiMachine}, - []*mapiv1beta1.Machine{newMapiMachine}, - ) - }) - }) + Context("when deleting the authoritative CAPI Machine", func() { It("should delete CAPI Machine", func() { - capiframework.DeleteMachines(ctx, cl, capiframework.CAPINamespace, newCapiMachine) + capiframework.DeleteMachines(ctx, cl, capiframework.CAPINamespace, capiMachineMirrorDeleteCAPI) }) It("should verify the MAPI machine is deleted", func() { - verifyResourceRemoved(newMapiMachine) + verifyResourceRemoved(mapiMachineDeleteCAPI) }) + It("should verify the AWS machine is deleted", func() { verifyResourceRemoved(&awsv1.AWSMachine{ TypeMeta: metav1.TypeMeta{Kind: "AWSMachine", APIVersion: awsv1.GroupVersion.String()}, - ObjectMeta: metav1.ObjectMeta{Name: mapiMachineAuthCAPINameDeletion, Namespace: capiframework.CAPINamespace}, + ObjectMeta: metav1.ObjectMeta{Name: mapiMachineDeleteCAPI.Name, Namespace: capiframework.CAPINamespace}, }) }) }) @@ -170,68 +172,60 @@ var _ = Describe("[sig-cluster-lifecycle][OCPFeatureGate:MachineAPIMigration] Ma }) var _ = Describe("Machine Migration Round Trip Tests", Ordered, func() { - var capiMapiCapiRoundTripName = "machine-capi-mapi-capi-roundtrip" - var newMapiMachine *mapiv1beta1.Machine - var newCapiMachine *clusterv1.Machine + AfterAll(func() { + By("Cleaning up Round Trip test resources") + cleanupMachineResources( + ctx, + cl, + []*clusterv1.Machine{capiMachineMirrorRoundTrip}, + []*mapiv1beta1.Machine{mapiMachineRoundTrip}, + ) + }) Context("CAPI (and no existing CAPI Machine with same name) -> MAPI -> CAPI round trip", func() { - BeforeAll(func() { - By("Creating a MAPI machine with spec.authoritativeAPI: ClusterAPI and no existing CAPI Machine with same name") - newMapiMachine = createMAPIMachineWithAuthority(ctx, cl, capiMapiCapiRoundTripName, mapiv1beta1.MachineAuthorityClusterAPI) - DeferCleanup(func() { - By("Cleaning up machine resources") - cleanupMachineResources( - ctx, - cl, - []*clusterv1.Machine{newCapiMachine}, - []*mapiv1beta1.Machine{newMapiMachine}, - ) - }) - }) - It("should create a CAPI mirror machine", func() { - newCapiMachine = capiframework.GetMachine(cl, capiMapiCapiRoundTripName, capiframework.CAPINamespace) - verifyMachineRunning(cl, newCapiMachine) + capiMachineMirrorRoundTrip = capiframework.GetMachine(cl, mapiMachineRoundTrip.Name, capiframework.CAPINamespace) + verifyMachineRunning(cl, capiMachineMirrorRoundTrip) }) It("should set the paused conditions and synchronised generation correctly", func() { - verifyMachineAuthoritative(newMapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) - verifyMAPIMachineSynchronizedCondition(newMapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) - verifyMachineSynchronizedGeneration(cl, newMapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) - verifyMachinePausedCondition(newMapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) - verifyMachinePausedCondition(newCapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachineAuthoritative(mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMAPIMachineSynchronizedCondition(mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachineSynchronizedGeneration(cl, mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachinePausedCondition(mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachinePausedCondition(capiMachineMirrorRoundTrip, mapiv1beta1.MachineAuthorityClusterAPI) }) It("should set the paused conditions and synchronised generation correctly after changing spec.authoritativeAPI: MachineAPI", func() { By("Updating spec.authoritativeAPI: MachineAPI") - updateMachineAuthoritativeAPI(newMapiMachine, mapiv1beta1.MachineAuthorityMachineAPI) - verifyMachineRunning(cl, newMapiMachine) - verifyMachineAuthoritative(newMapiMachine, mapiv1beta1.MachineAuthorityMachineAPI) - verifyMAPIMachineSynchronizedCondition(newMapiMachine, mapiv1beta1.MachineAuthorityMachineAPI) - verifyMachineSynchronizedGeneration(cl, newMapiMachine, mapiv1beta1.MachineAuthorityMachineAPI) - verifyMachinePausedCondition(newMapiMachine, mapiv1beta1.MachineAuthorityMachineAPI) - verifyMachinePausedCondition(newCapiMachine, mapiv1beta1.MachineAuthorityMachineAPI) + updateMachineAuthoritativeAPI(mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMachineRunning(cl, mapiMachineRoundTrip) + verifyMachineAuthoritative(mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMAPIMachineSynchronizedCondition(mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMachineSynchronizedGeneration(cl, mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMachinePausedCondition(mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMachinePausedCondition(capiMachineMirrorRoundTrip, mapiv1beta1.MachineAuthorityMachineAPI) }) It("should set the paused conditions and synchronised generation correctly after changing back spec.authoritativeAPI: ClusterAPI", func() { By("Updating spec.authoritativeAPI: ClusterAPI") - updateMachineAuthoritativeAPI(newMapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) - verifyMachineRunning(cl, newCapiMachine) - verifyMachineAuthoritative(newMapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) - verifyMAPIMachineSynchronizedCondition(newMapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) - verifyMachineSynchronizedGeneration(cl, newMapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) - verifyMachinePausedCondition(newMapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) - verifyMachinePausedCondition(newCapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) + updateMachineAuthoritativeAPI(mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachineRunning(cl, capiMachineMirrorRoundTrip) + verifyMachineAuthoritative(mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMAPIMachineSynchronizedCondition(mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachineSynchronizedGeneration(cl, mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachinePausedCondition(mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachinePausedCondition(capiMachineMirrorRoundTrip, mapiv1beta1.MachineAuthorityClusterAPI) }) It("should verify mirror machines are deleted when deleting CAPI machine", func() { By("Deleting CAPI machine") - capiframework.DeleteMachines(ctx, cl, capiframework.CAPINamespace, newCapiMachine) - verifyResourceRemoved(newMapiMachine) - verifyResourceRemoved(newCapiMachine) + capiframework.DeleteMachines(ctx, cl, capiframework.CAPINamespace, capiMachineMirrorRoundTrip) + verifyResourceRemoved(mapiMachineRoundTrip) + verifyResourceRemoved(capiMachineMirrorRoundTrip) verifyResourceRemoved(&awsv1.AWSMachine{ TypeMeta: metav1.TypeMeta{Kind: "AWSMachine", APIVersion: awsv1.GroupVersion.String()}, - ObjectMeta: metav1.ObjectMeta{Name: capiMapiCapiRoundTripName, Namespace: capiframework.CAPINamespace}, + ObjectMeta: metav1.ObjectMeta{Name: mapiMachineRoundTrip.Name, Namespace: capiframework.CAPINamespace}, }) }) }) diff --git a/e2e/machine_migration_helpers.go b/e2e/machine_migration_helpers.go index 89f231edc..57af1b1a6 100644 --- a/e2e/machine_migration_helpers.go +++ b/e2e/machine_migration_helpers.go @@ -19,9 +19,11 @@ import ( clusterv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/envtest/komega" + yaml "sigs.k8s.io/yaml" ) func createCAPIMachine(ctx context.Context, cl client.Client, machineName string) *clusterv1.Machine { + GinkgoHelper() Expect(machineName).NotTo(BeEmpty(), "Machine name cannot be empty") workerLabelSelector := metav1.LabelSelector{ @@ -96,6 +98,7 @@ func createCAPIMachine(ctx context.Context, cl client.Client, machineName string } func createMAPIMachineWithAuthority(ctx context.Context, cl client.Client, machineName string, authority mapiv1beta1.MachineAuthority) *mapiv1beta1.Machine { + GinkgoHelper() Expect(machineName).NotTo(BeEmpty(), "Machine name cannot be empty") workerLabelSelector := metav1.LabelSelector{ MatchLabels: map[string]string{ @@ -140,6 +143,7 @@ func createMAPIMachineWithAuthority(ctx context.Context, cl client.Client, machi // verifyMachineRunning verifies that a machine reaches Running state using the machine object directly. func verifyMachineRunning(cl client.Client, machine client.Object) { + GinkgoHelper() Expect(machine).NotTo(BeNil(), "Machine parameter cannot be nil") Expect(machine.GetName()).NotTo(BeEmpty(), "Machine name cannot be empty") Eventually(func(g Gomega) string { @@ -162,6 +166,7 @@ func verifyMachineRunning(cl client.Client, machine client.Object) { } func verifyMachineAuthoritative(mapiMachine *mapiv1beta1.Machine, authority mapiv1beta1.MachineAuthority) { + GinkgoHelper() By(fmt.Sprintf("Verify the Machine authority is %s", authority)) Eventually(komega.Object(mapiMachine), capiframework.WaitMedium, capiframework.RetryMedium).Should( HaveField("Status.AuthoritativeAPI", Equal(authority)), @@ -170,6 +175,7 @@ func verifyMachineAuthoritative(mapiMachine *mapiv1beta1.Machine, authority mapi } func verifyMAPIMachineSynchronizedCondition(mapiMachine *mapiv1beta1.Machine, authority mapiv1beta1.MachineAuthority) { + GinkgoHelper() By("Verify the MAPI Machine synchronized condition is True") var expectedMessage string switch authority { @@ -202,6 +208,7 @@ func verifyMAPIMachineSynchronizedCondition(mapiMachine *mapiv1beta1.Machine, au // verifyResourceRemoved verifies that a resource has been removed. // This is a generic function that works with any client.Object type. func verifyResourceRemoved(resource client.Object) { + GinkgoHelper() Expect(resource).NotTo(BeNil(), "Resource parameter cannot be nil") Expect(resource.GetName()).NotTo(BeEmpty(), "Resource name cannot be empty") gvk := resource.GetObjectKind().GroupVersionKind() @@ -214,6 +221,7 @@ func verifyResourceRemoved(resource client.Object) { // verifyMachinePausedCondition verifies the Paused condition for either MAPI or CAPI machines. // This unified function determines the machine type and expected pause state based on the authority. func verifyMachinePausedCondition(machine client.Object, authority mapiv1beta1.MachineAuthority) { + GinkgoHelper() Expect(machine).NotTo(BeNil(), "Machine parameter cannot be nil") Expect(machine.GetName()).NotTo(BeEmpty(), "Machine name cannot be empty") var conditionMatcher types.GomegaMatcher @@ -298,12 +306,14 @@ func cleanupMachineResources(ctx context.Context, cl client.Client, capiMachines } func updateMachineAuthoritativeAPI(mapiMachine *mapiv1beta1.Machine, newAuthority mapiv1beta1.MachineAuthority) { + GinkgoHelper() Eventually(komega.Update(mapiMachine, func() { mapiMachine.Spec.AuthoritativeAPI = newAuthority }), capiframework.WaitShort, capiframework.RetryShort).Should(Succeed(), "Failed to update MAPI Machine AuthoritativeAPI to %s", newAuthority) } func verifyMachineSynchronizedGeneration(cl client.Client, mapiMachine *mapiv1beta1.Machine, authority mapiv1beta1.MachineAuthority) { + GinkgoHelper() Eventually(komega.Object(mapiMachine), capiframework.WaitMedium, capiframework.RetryMedium).Should( HaveField("Status.SynchronizedGeneration", Not(BeZero())), "MAPI Machine SynchronizedGeneration should not be zero", @@ -333,3 +343,22 @@ func verifyMachineSynchronizedGeneration(cl client.Client, mapiMachine *mapiv1be fmt.Sprintf("MAPI Machine SynchronizedGeneration should equal %s Machine Generation (%d)", authoritativeMachineType, expectedGeneration), ) } + +// verifyMAPIMachineProviderStatus verifies that a MAPI Machine's providerStatus matches the given Gomega matcher. +func verifyMAPIMachineProviderStatus(mapiMachine *mapiv1beta1.Machine, matcher types.GomegaMatcher) { + GinkgoHelper() + By(fmt.Sprintf("Verifying MAPI Machine %s providerStatus matches AWSMachine status", mapiMachine.Name)) + Eventually(komega.Object(mapiMachine), capiframework.WaitMedium, capiframework.RetryMedium).Should( + WithTransform(getAWSProviderStatusFromMachine, matcher), + ) +} + +// getAWSProviderStatusFromMachine extracts and unmarshals the AWSMachineProviderStatus from a MAPI Machine. +func getAWSProviderStatusFromMachine(mapiMachine *mapiv1beta1.Machine) *mapiv1beta1.AWSMachineProviderStatus { + Expect(mapiMachine.Status.ProviderStatus.Raw).ToNot(BeNil()) + + providerStatus := &mapiv1beta1.AWSMachineProviderStatus{} + Expect(yaml.Unmarshal(mapiMachine.Status.ProviderStatus.Raw, providerStatus)).To(Succeed()) + + return providerStatus +} diff --git a/e2e/machine_migration_mapi_authoritative_test.go b/e2e/machine_migration_mapi_authoritative_test.go index 1d470f4c3..a21e2af79 100644 --- a/e2e/machine_migration_mapi_authoritative_test.go +++ b/e2e/machine_migration_mapi_authoritative_test.go @@ -14,6 +14,18 @@ import ( ) var _ = Describe("[sig-cluster-lifecycle][OCPFeatureGate:MachineAPIMigration] Machine Migration MAPI Authoritative Tests", Ordered, func() { + var mapiMachineAuthMAPI *mapiv1beta1.Machine + var capiMachineMirrorAuthMAPI *clusterv1.Machine + + var mapiMachineDeleteMAPI *mapiv1beta1.Machine + var capiMachineMirrorDeleteMAPI *clusterv1.Machine + + var mapiMachineDeleteCAPI *mapiv1beta1.Machine + var capiMachineMirrorDeleteCAPI *clusterv1.Machine + + var mapiMachineRoundTrip *mapiv1beta1.Machine + var capiMachineMirrorRoundTrip *clusterv1.Machine + BeforeAll(func() { if platform != configv1.AWSPlatformType { Skip(fmt.Sprintf("Skipping tests on %s, this is only supported on AWS", platform)) @@ -22,111 +34,103 @@ var _ = Describe("[sig-cluster-lifecycle][OCPFeatureGate:MachineAPIMigration] Ma if !capiframework.IsMachineAPIMigrationEnabled(ctx, cl) { Skip("Skipping, this feature is only supported on MachineAPIMigration enabled clusters") } + + By("Creating all MAPI Machines with AuthoritativeAPI: MachineAPI") + mapiMachineAuthMAPI = createMAPIMachineWithAuthority(ctx, cl, UniqueName("mapi-auth-mapi"), mapiv1beta1.MachineAuthorityMachineAPI) + mapiMachineDeleteMAPI = createMAPIMachineWithAuthority(ctx, cl, UniqueName("mapi-delete-mapi"), mapiv1beta1.MachineAuthorityMachineAPI) + mapiMachineDeleteCAPI = createMAPIMachineWithAuthority(ctx, cl, UniqueName("mapi-delete-capi"), mapiv1beta1.MachineAuthorityMachineAPI) + mapiMachineRoundTrip = createMAPIMachineWithAuthority(ctx, cl, UniqueName("mapi-roundtrip"), mapiv1beta1.MachineAuthorityMachineAPI) + + By("Waiting for all MAPI Machines to reach Running state") + verifyMachineRunning(cl, mapiMachineAuthMAPI) + verifyMachineRunning(cl, mapiMachineDeleteMAPI) + verifyMachineRunning(cl, mapiMachineDeleteCAPI) + verifyMachineRunning(cl, mapiMachineRoundTrip) + + By("Getting all CAPI Machine mirrors") + capiMachineMirrorAuthMAPI = capiframework.GetMachine(cl, mapiMachineAuthMAPI.Name, capiframework.CAPINamespace) + capiMachineMirrorDeleteMAPI = capiframework.GetMachine(cl, mapiMachineDeleteMAPI.Name, capiframework.CAPINamespace) + capiMachineMirrorDeleteCAPI = capiframework.GetMachine(cl, mapiMachineDeleteCAPI.Name, capiframework.CAPINamespace) + capiMachineMirrorRoundTrip = capiframework.GetMachine(cl, mapiMachineRoundTrip.Name, capiframework.CAPINamespace) }) var _ = Describe("Create standalone MAPI Machine", Ordered, func() { - var mapiMachineAuthMAPIName = "machine-authoritativeapi-mapi" - var newCapiMachine *clusterv1.Machine - var newMapiMachine *mapiv1beta1.Machine + AfterAll(func() { + By("Cleaning up Create test resources") + cleanupMachineResources( + ctx, + cl, + []*clusterv1.Machine{capiMachineMirrorAuthMAPI}, + []*mapiv1beta1.Machine{mapiMachineAuthMAPI}, + ) + }) Context("With spec.authoritativeAPI: MachineAPI and no existing CAPI Machine with that name", func() { - BeforeAll(func() { - newMapiMachine = createMAPIMachineWithAuthority(ctx, cl, mapiMachineAuthMAPIName, mapiv1beta1.MachineAuthorityMachineAPI) - - DeferCleanup(func() { - By("Cleaning up machine resources") - cleanupMachineResources( - ctx, - cl, - []*clusterv1.Machine{}, - []*mapiv1beta1.Machine{newMapiMachine}, - ) - }) - }) - It("should find MAPI Machine .status.authoritativeAPI to equal MachineAPI", func() { - verifyMachineAuthoritative(newMapiMachine, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMachineAuthoritative(mapiMachineAuthMAPI, mapiv1beta1.MachineAuthorityMachineAPI) }) + It("should verify MAPI Machine Synchronized condition is True", func() { - verifyMAPIMachineSynchronizedCondition(newMapiMachine, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMAPIMachineSynchronizedCondition(mapiMachineAuthMAPI, mapiv1beta1.MachineAuthorityMachineAPI) }) + It("should verify MAPI Machine Paused condition is False", func() { - verifyMachinePausedCondition(newMapiMachine, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMachinePausedCondition(mapiMachineAuthMAPI, mapiv1beta1.MachineAuthorityMachineAPI) }) + It("should verify that the MAPI Machine has a CAPI Machine", func() { - newCapiMachine = capiframework.GetMachine(cl, mapiMachineAuthMAPIName, capiframework.CAPINamespace) + capiMachineMirrorAuthMAPI = capiframework.GetMachine(cl, mapiMachineAuthMAPI.Name, capiframework.CAPINamespace) }) + It("should verify CAPI Machine Paused condition is True", func() { - verifyMachinePausedCondition(newCapiMachine, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMachinePausedCondition(capiMachineMirrorAuthMAPI, mapiv1beta1.MachineAuthorityMachineAPI) }) }) }) var _ = Describe("Deleting MAPI Machines", Ordered, func() { - var mapiMachineAuthMAPINameDeleteMAPIMachine = "machine-authoritativeapi-mapi-delete-mapi" - var mapiMachineAuthMAPINameDeleteCAPIMachine = "machine-authoritativeapi-mapi-delete-capi" - var newCapiMachine *clusterv1.Machine - var newMapiMachine *mapiv1beta1.Machine + AfterAll(func() { + By("Cleaning up Delete test resources") + cleanupMachineResources( + ctx, + cl, + []*clusterv1.Machine{capiMachineMirrorDeleteMAPI, capiMachineMirrorDeleteCAPI}, + []*mapiv1beta1.Machine{mapiMachineDeleteMAPI, mapiMachineDeleteCAPI}, + ) + }) Context("with spec.authoritativeAPI: MachineAPI", func() { Context("when deleting the authoritative MAPI Machine", func() { - BeforeAll(func() { - newMapiMachine = createMAPIMachineWithAuthority(ctx, cl, mapiMachineAuthMAPINameDeleteMAPIMachine, mapiv1beta1.MachineAuthorityMachineAPI) - newCapiMachine = capiframework.GetMachine(cl, newMapiMachine.Name, capiframework.CAPINamespace) - verifyMachineRunning(cl, newMapiMachine) - - DeferCleanup(func() { - By("Cleaning up machine resources") - cleanupMachineResources( - ctx, - cl, - []*clusterv1.Machine{newCapiMachine}, - []*mapiv1beta1.Machine{newMapiMachine}, - ) - }) - }) It("should delete MAPI Machine", func() { - mapiframework.DeleteMachines(ctx, cl, newMapiMachine) - mapiframework.WaitForMachinesDeleted(cl, newMapiMachine) + mapiframework.DeleteMachines(ctx, cl, mapiMachineDeleteMAPI) + mapiframework.WaitForMachinesDeleted(cl, mapiMachineDeleteMAPI) }) It("should verify the CAPI machine is deleted", func() { - verifyResourceRemoved(newCapiMachine) + verifyResourceRemoved(capiMachineMirrorDeleteMAPI) }) + It("should verify the AWS machine is deleted", func() { verifyResourceRemoved(&awsv1.AWSMachine{ TypeMeta: metav1.TypeMeta{Kind: "AWSMachine", APIVersion: awsv1.GroupVersion.String()}, - ObjectMeta: metav1.ObjectMeta{Name: mapiMachineAuthMAPINameDeleteMAPIMachine, Namespace: capiframework.CAPINamespace}, + ObjectMeta: metav1.ObjectMeta{Name: mapiMachineDeleteMAPI.Name, Namespace: capiframework.CAPINamespace}, }) }) }) + Context("when deleting the non-authoritative CAPI Machine", func() { - BeforeAll(func() { - newMapiMachine = createMAPIMachineWithAuthority(ctx, cl, mapiMachineAuthMAPINameDeleteCAPIMachine, mapiv1beta1.MachineAuthorityMachineAPI) - verifyMachineRunning(cl, newMapiMachine) - newCapiMachine = capiframework.GetMachine(cl, newMapiMachine.Name, capiframework.CAPINamespace) - - DeferCleanup(func() { - By("Cleaning up machine resources") - cleanupMachineResources( - ctx, - cl, - []*clusterv1.Machine{newCapiMachine}, - []*mapiv1beta1.Machine{newMapiMachine}, - ) - }) - }) It("should delete CAPI Machine", func() { - capiframework.DeleteMachines(ctx, cl, capiframework.CAPINamespace, newCapiMachine) + capiframework.DeleteMachines(ctx, cl, capiframework.CAPINamespace, capiMachineMirrorDeleteCAPI) }) It("should verify the MAPI machine is deleted", func() { - verifyResourceRemoved(newMapiMachine) + verifyResourceRemoved(mapiMachineDeleteCAPI) }) + It("should verify the AWS machine is deleted", func() { verifyResourceRemoved(&awsv1.AWSMachine{ TypeMeta: metav1.TypeMeta{Kind: "AWSMachine", APIVersion: awsv1.GroupVersion.String()}, - ObjectMeta: metav1.ObjectMeta{Name: mapiMachineAuthMAPINameDeleteCAPIMachine, Namespace: capiframework.CAPINamespace}, + ObjectMeta: metav1.ObjectMeta{Name: mapiMachineDeleteCAPI.Name, Namespace: capiframework.CAPINamespace}, }) }) }) @@ -134,70 +138,60 @@ var _ = Describe("[sig-cluster-lifecycle][OCPFeatureGate:MachineAPIMigration] Ma }) var _ = Describe("Machine Migration Round Trip Tests", Ordered, func() { - var mapiCapiMapiRoundTripName = "machine-mapi-capi-mapi-roundtrip" - var newMapiMachine *mapiv1beta1.Machine - var newCapiMachine *clusterv1.Machine + AfterAll(func() { + By("Cleaning up Round Trip test resources") + cleanupMachineResources( + ctx, + cl, + []*clusterv1.Machine{capiMachineMirrorRoundTrip}, + []*mapiv1beta1.Machine{mapiMachineRoundTrip}, + ) + }) Context("MAPI -> CAPI -> MAPI round trip", func() { - BeforeAll(func() { - By("Creating a MAPI machine with spec.authoritativeAPI: MachineAPI") - newMapiMachine = createMAPIMachineWithAuthority(ctx, cl, mapiCapiMapiRoundTripName, mapiv1beta1.MachineAuthorityMachineAPI) - verifyMachineRunning(cl, newMapiMachine) - - DeferCleanup(func() { - By("Cleaning up machine resources") - cleanupMachineResources( - ctx, - cl, - []*clusterv1.Machine{newCapiMachine}, - []*mapiv1beta1.Machine{newMapiMachine}, - ) - }) - }) - It("should create a CAPI mirror machine", func() { - newCapiMachine = capiframework.GetMachine(cl, mapiCapiMapiRoundTripName, capiframework.CAPINamespace) + capiMachineMirrorRoundTrip = capiframework.GetMachine(cl, mapiMachineRoundTrip.Name, capiframework.CAPINamespace) }) It("should set the paused conditions and synchronised generation correctly", func() { - verifyMachineAuthoritative(newMapiMachine, mapiv1beta1.MachineAuthorityMachineAPI) - verifyMAPIMachineSynchronizedCondition(newMapiMachine, mapiv1beta1.MachineAuthorityMachineAPI) - verifyMachineSynchronizedGeneration(cl, newMapiMachine, mapiv1beta1.MachineAuthorityMachineAPI) - verifyMachinePausedCondition(newMapiMachine, mapiv1beta1.MachineAuthorityMachineAPI) - verifyMachinePausedCondition(newCapiMachine, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMachineAuthoritative(mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMAPIMachineSynchronizedCondition(mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMachineSynchronizedGeneration(cl, mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMachinePausedCondition(mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMachinePausedCondition(capiMachineMirrorRoundTrip, mapiv1beta1.MachineAuthorityMachineAPI) }) It("should set the paused conditions and synchronised generation correctly after changing spec.authoritativeAPI: ClusterAPI", func() { By("Updating spec.authoritativeAPI: ClusterAPI") - updateMachineAuthoritativeAPI(newMapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) - verifyMachineRunning(cl, newCapiMachine) - verifyMachineAuthoritative(newMapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) - verifyMAPIMachineSynchronizedCondition(newMapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) - verifyMachineSynchronizedGeneration(cl, newMapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) - verifyMachinePausedCondition(newMapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) - verifyMachinePausedCondition(newCapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) + updateMachineAuthoritativeAPI(mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachineRunning(cl, capiMachineMirrorRoundTrip) + verifyMachineAuthoritative(mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMAPIMachineSynchronizedCondition(mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachineSynchronizedGeneration(cl, mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachinePausedCondition(mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachinePausedCondition(capiMachineMirrorRoundTrip, mapiv1beta1.MachineAuthorityClusterAPI) }) It("should set the paused conditions and synchronised generation correctly after changing back spec.authoritativeAPI: MachineAPI", func() { By("Updating spec.authoritativeAPI: MachineAPI") - updateMachineAuthoritativeAPI(newMapiMachine, mapiv1beta1.MachineAuthorityMachineAPI) - verifyMachineRunning(cl, newMapiMachine) - verifyMachineAuthoritative(newMapiMachine, mapiv1beta1.MachineAuthorityMachineAPI) - verifyMAPIMachineSynchronizedCondition(newMapiMachine, mapiv1beta1.MachineAuthorityMachineAPI) - verifyMachineSynchronizedGeneration(cl, newMapiMachine, mapiv1beta1.MachineAuthorityMachineAPI) - verifyMachinePausedCondition(newMapiMachine, mapiv1beta1.MachineAuthorityMachineAPI) - verifyMachinePausedCondition(newCapiMachine, mapiv1beta1.MachineAuthorityMachineAPI) + updateMachineAuthoritativeAPI(mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMachineRunning(cl, mapiMachineRoundTrip) + verifyMachineAuthoritative(mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMAPIMachineSynchronizedCondition(mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMachineSynchronizedGeneration(cl, mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMachinePausedCondition(mapiMachineRoundTrip, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMachinePausedCondition(capiMachineMirrorRoundTrip, mapiv1beta1.MachineAuthorityMachineAPI) }) It("should verify mirror machines are deleted when deleting MAPI machine", func() { By("Deleting MAPI machine") - mapiframework.DeleteMachines(ctx, cl, newMapiMachine) - mapiframework.WaitForMachinesDeleted(cl, newMapiMachine) - verifyResourceRemoved(newMapiMachine) - verifyResourceRemoved(newCapiMachine) + mapiframework.DeleteMachines(ctx, cl, mapiMachineRoundTrip) + mapiframework.WaitForMachinesDeleted(cl, mapiMachineRoundTrip) + verifyResourceRemoved(mapiMachineRoundTrip) + verifyResourceRemoved(capiMachineMirrorRoundTrip) verifyResourceRemoved(&awsv1.AWSMachine{ TypeMeta: metav1.TypeMeta{Kind: "AWSMachine", APIVersion: awsv1.GroupVersion.String()}, - ObjectMeta: metav1.ObjectMeta{Name: mapiCapiMapiRoundTripName, Namespace: capiframework.CAPINamespace}, + ObjectMeta: metav1.ObjectMeta{Name: mapiMachineRoundTrip.Name, Namespace: capiframework.CAPINamespace}, }) }) }) diff --git a/e2e/machineset_migration_capi_authoritative_test.go b/e2e/machineset_migration_capi_authoritative_test.go index 43bb5b023..2da52067c 100644 --- a/e2e/machineset_migration_capi_authoritative_test.go +++ b/e2e/machineset_migration_capi_authoritative_test.go @@ -15,6 +15,26 @@ import ( ) var _ = Describe("[sig-cluster-lifecycle][OCPFeatureGate:MachineAPIMigration] MachineSet Migration CAPI Authoritative Tests", Ordered, func() { + var capiMSAuthCAPISameName *clusterv1.MachineSet + var mapiMSAuthCAPISameName *mapiv1beta1.MachineSet + var awsMachineTemplateAuthCAPISameName *awsv1.AWSMachineTemplate + + var mapiMSAuthCAPI *mapiv1beta1.MachineSet + var capiMSMirrorAuthCAPI *clusterv1.MachineSet + var awsMachineTemplateAuthCAPI *awsv1.AWSMachineTemplate + + var mapiMSScale *mapiv1beta1.MachineSet + var capiMSMirrorScale *clusterv1.MachineSet + var awsMachineTemplateScale *awsv1.AWSMachineTemplate + var firstMAPIMachine *mapiv1beta1.Machine + var secondMAPIMachine *mapiv1beta1.Machine + + var mapiMSDelete *mapiv1beta1.MachineSet + var capiMSMirrorDelete *clusterv1.MachineSet + var awsMachineTemplateDelete *awsv1.AWSMachineTemplate + + var instanceType = "m5.large" + BeforeAll(func() { if platform != configv1.AWSPlatformType { Skip(fmt.Sprintf("Skipping tests on %s, this is only supported on AWS", platform)) @@ -23,168 +43,196 @@ var _ = Describe("[sig-cluster-lifecycle][OCPFeatureGate:MachineAPIMigration] Ma if !capiframework.IsMachineAPIMigrationEnabled(ctx, cl) { Skip("Skipping, this feature is only supported on MachineAPIMigration enabled clusters") } + + // Creating all MachineSets without waiting (parallel creation)" + By("Creating CAPI MachineSet first for existing CAPI MachineSet scenario") + capiMSAuthCAPISameName = createCAPIMachineSetSkipWait(ctx, cl, 0, UniqueName("capi-machineset-authoritativeapi-capi"), instanceType, true) + + By("Creating MAPI MachineSet with same name as existing CAPI MachineSet") + mapiMSAuthCAPISameName = createMAPIMachineSetWithAuthoritativeAPISkipWait( + ctx, cl, 0, + capiMSAuthCAPISameName.Name, + mapiv1beta1.MachineAuthorityClusterAPI, + mapiv1beta1.MachineAuthorityClusterAPI, + true, // skipWait=true + ) + + By("Creating MAPI MachineSet with AuthoritativeAPI: ClusterAPI and no existing CAPI MachineSet with same name") + mapiMSAuthCAPI = createMAPIMachineSetWithAuthoritativeAPISkipWait( + ctx, cl, 0, + UniqueName("ms-authoritativeapi-capi"), + mapiv1beta1.MachineAuthorityClusterAPI, + mapiv1beta1.MachineAuthorityClusterAPI, + true, // skipWait=true + ) + + By("Creating MachineSet for Scale tests with spec.authoritativeAPI: ClusterAPI") + mapiMSScale = createMAPIMachineSetWithAuthoritativeAPISkipWait( + ctx, cl, 1, + UniqueName("ms-authoritativeapi-capi-scale"), + mapiv1beta1.MachineAuthorityClusterAPI, + mapiv1beta1.MachineAuthorityClusterAPI, + true, // skipWait=true + ) + By("Creating MachineSet for Delete tests with spec.authoritativeAPI: MachineAPI") + mapiMSDelete = createMAPIMachineSetWithAuthoritativeAPISkipWait( + ctx, cl, 1, + UniqueName("ms-authoritativeapi-mapi-delete"), + mapiv1beta1.MachineAuthorityMachineAPI, + mapiv1beta1.MachineAuthorityMachineAPI, + true, // skipWait=true + ) + + By("Waiting for all MachineSets to become ready (parallel waiting)") + capiframework.WaitForMachineSet(cl, capiMSAuthCAPISameName.Name, capiframework.CAPINamespace) + waitForMAPIMachineSetReady(ctx, cl, mapiMSAuthCAPISameName.Name, mapiv1beta1.MachineAuthorityClusterAPI) + waitForMAPIMachineSetReady(ctx, cl, mapiMSAuthCAPI.Name, mapiv1beta1.MachineAuthorityClusterAPI) + waitForMAPIMachineSetReady(ctx, cl, mapiMSScale.Name, mapiv1beta1.MachineAuthorityClusterAPI) + waitForMAPIMachineSetReady(ctx, cl, mapiMSDelete.Name, mapiv1beta1.MachineAuthorityMachineAPI) + + By("Getting all MachineSet mirrors and templates") + awsMachineTemplateAuthCAPISameName = waitForAWSMachineTemplate(cl, capiMSAuthCAPISameName.Name) + capiMSMirrorAuthCAPI = waitForCAPIMachineSetMirror(cl, mapiMSAuthCAPI.Name) + awsMachineTemplateAuthCAPI = waitForAWSMachineTemplate(cl, mapiMSAuthCAPI.Name) + capiMSMirrorScale, awsMachineTemplateScale = waitForMAPIMachineSetMirrors(cl, mapiMSScale.Name) + capiMSMirrorDelete, awsMachineTemplateDelete = waitForMAPIMachineSetMirrors(cl, mapiMSDelete.Name) + + By("Getting Machines from MachineSets") + mapiMachines, err := mapiframework.GetMachinesFromMachineSet(ctx, cl, mapiMSScale) + Expect(err).ToNot(HaveOccurred(), "Should have successfully got MAPI Machines from MachineSet") + Expect(mapiMachines).ToNot(BeEmpty(), "Should have found MAPI Machines") + + capiMachines := capiframework.GetMachinesFromMachineSet(cl, capiMSMirrorScale) + Expect(capiMachines).ToNot(BeEmpty(), "Should have found CAPI Machines") + Expect(capiMachines[0].Name).To(Equal(mapiMachines[0].Name), "Should have CAPI Machine name match MAPI Machine name") + firstMAPIMachine = mapiMachines[0] + + mapiMachinesDelete, err := mapiframework.GetMachinesFromMachineSet(ctx, cl, mapiMSDelete) + Expect(mapiMachinesDelete).ToNot(BeEmpty(), "Should have found MAPI Machines") + Expect(err).ToNot(HaveOccurred(), "Should have successfully got MAPI Machines from MachineSet") + + capiMachinesDelete := capiframework.GetMachinesFromMachineSet(cl, capiMSMirrorDelete) + Expect(capiMachinesDelete).ToNot(BeEmpty(), "Should have found CAPI Machines") + Expect(capiMachinesDelete[0].Name).To(Equal(mapiMachinesDelete[0].Name), "Should have CAPI Machine name match MAPI Machine name") + }) var _ = Describe("Create MAPI MachineSets", Ordered, func() { - var mapiMSAuthCAPIName = "ms-authoritativeapi-capi" - var existingCAPIMSAuthorityCAPIName = "capi-machineset-authoritativeapi-capi" - - var awsMachineTemplate *awsv1.AWSMachineTemplate - var capiMachineSet *clusterv1.MachineSet - var mapiMachineSet *mapiv1beta1.MachineSet - var instanceType = "m5.large" + AfterAll(func() { + By("Cleaning up Create test resources") + cleanupMachineSetTestResources( + ctx, + cl, + []*clusterv1.MachineSet{capiMSAuthCAPISameName, capiMSMirrorAuthCAPI}, + []*awsv1.AWSMachineTemplate{awsMachineTemplateAuthCAPISameName, awsMachineTemplateAuthCAPI}, + []*mapiv1beta1.MachineSet{mapiMSAuthCAPISameName, mapiMSAuthCAPI}, + ) + }) Context("with spec.authoritativeAPI: ClusterAPI and existing CAPI MachineSet with same name", func() { - BeforeAll(func() { - capiMachineSet = createCAPIMachineSet(ctx, cl, 0, existingCAPIMSAuthorityCAPIName, instanceType) - - By("Creating a same name MAPI MachineSet") - mapiMachineSet = createMAPIMachineSetWithAuthoritativeAPI(ctx, cl, 0, existingCAPIMSAuthorityCAPIName, mapiv1beta1.MachineAuthorityClusterAPI, mapiv1beta1.MachineAuthorityClusterAPI) - awsMachineTemplate = waitForAWSMachineTemplate(cl, existingCAPIMSAuthorityCAPIName) - - DeferCleanup(func() { - By("Cleaning up Context 'with spec.authoritativeAPI: ClusterAPI and existing CAPI MachineSet with same name' resources") - cleanupMachineSetTestResources( - ctx, - cl, - []*clusterv1.MachineSet{capiMachineSet}, - []*awsv1.AWSMachineTemplate{awsMachineTemplate}, - []*mapiv1beta1.MachineSet{mapiMachineSet}, - ) - }) - }) - It("should verify that MAPI MachineSet has Paused condition True", func() { - verifyMachineSetPausedCondition(mapiMachineSet, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachineSetPausedCondition(mapiMSAuthCAPISameName, mapiv1beta1.MachineAuthorityClusterAPI) }) // bug https://issues.redhat.com/browse/OCPBUGS-55337 PIt("should verify that the non-authoritative MAPI MachineSet providerSpec has been updated to reflect the authoritative CAPI MachineSet mirror values", func() { - verifyMAPIMachineSetProviderSpec(mapiMachineSet, HaveField("InstanceType", Equal(instanceType))) + verifyMAPIMachineSetProviderSpec(mapiMSAuthCAPISameName, HaveField("InstanceType", Equal(instanceType))) }) }) Context("with spec.authoritativeAPI: ClusterAPI and no existing CAPI MachineSet with same name", func() { - BeforeAll(func() { - mapiMachineSet = createMAPIMachineSetWithAuthoritativeAPI(ctx, cl, 0, mapiMSAuthCAPIName, mapiv1beta1.MachineAuthorityClusterAPI, mapiv1beta1.MachineAuthorityClusterAPI) - capiMachineSet = waitForCAPIMachineSetMirror(cl, mapiMSAuthCAPIName) - awsMachineTemplate = waitForAWSMachineTemplate(cl, mapiMSAuthCAPIName) - - DeferCleanup(func() { - By("Cleaning up Context 'with spec.authoritativeAPI: ClusterAPI and no existing CAPI MachineSet with same name' resources") - cleanupMachineSetTestResources( - ctx, - cl, - []*clusterv1.MachineSet{capiMachineSet}, - []*awsv1.AWSMachineTemplate{awsMachineTemplate}, - []*mapiv1beta1.MachineSet{mapiMachineSet}, - ) - }) - }) - It("should find MAPI MachineSet .status.authoritativeAPI to equal CAPI", func() { - verifyMachineSetAuthoritative(mapiMachineSet, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachineSetAuthoritative(mapiMSAuthCAPI, mapiv1beta1.MachineAuthorityClusterAPI) }) It("should verify that MAPI MachineSet Paused condition is True", func() { - verifyMachineSetPausedCondition(mapiMachineSet, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachineSetPausedCondition(mapiMSAuthCAPI, mapiv1beta1.MachineAuthorityClusterAPI) }) It("should verify that MAPI MachineSet Synchronized condition is True", func() { - verifyMAPIMachineSetSynchronizedCondition(mapiMachineSet, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMAPIMachineSetSynchronizedCondition(mapiMSAuthCAPI, mapiv1beta1.MachineAuthorityClusterAPI) }) It("should verify that the non-authoritative MAPI MachineSet has an authoritative CAPI MachineSet mirror", func() { - waitForCAPIMachineSetMirror(cl, mapiMSAuthCAPIName) + waitForCAPIMachineSetMirror(cl, mapiMSAuthCAPI.Name) }) It("should verify that CAPI MachineSet has Paused condition False", func() { - verifyMachineSetPausedCondition(capiMachineSet, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachineSetPausedCondition(capiMSMirrorAuthCAPI, mapiv1beta1.MachineAuthorityClusterAPI) }) }) }) var _ = Describe("Scale MAPI MachineSets", Ordered, func() { - var mapiMSAuthCAPIName = "ms-authoritativeapi-capi" - - var awsMachineTemplate *awsv1.AWSMachineTemplate - var capiMachineSet *clusterv1.MachineSet - var mapiMachineSet *mapiv1beta1.MachineSet - var firstMAPIMachine *mapiv1beta1.Machine - var secondMAPIMachine *mapiv1beta1.Machine + AfterAll(func() { + By("Cleaning up Scale test resources") + cleanupMachineSetTestResources( + ctx, + cl, + []*clusterv1.MachineSet{capiMSMirrorScale}, + []*awsv1.AWSMachineTemplate{awsMachineTemplateScale}, + []*mapiv1beta1.MachineSet{mapiMSScale}, + ) + }) Context("with spec.authoritativeAPI: ClusterAPI", Ordered, func() { - BeforeAll(func() { - mapiMachineSet = createMAPIMachineSetWithAuthoritativeAPI(ctx, cl, 1, mapiMSAuthCAPIName, mapiv1beta1.MachineAuthorityClusterAPI, mapiv1beta1.MachineAuthorityClusterAPI) - capiMachineSet, awsMachineTemplate = waitForMAPIMachineSetMirrors(cl, mapiMSAuthCAPIName) - - mapiMachines, err := mapiframework.GetMachinesFromMachineSet(ctx, cl, mapiMachineSet) - Expect(err).ToNot(HaveOccurred(), "failed to get MAPI Machines from MachineSet") - Expect(mapiMachines).ToNot(BeEmpty(), "no MAPI Machines found") - - capiMachines := capiframework.GetMachinesFromMachineSet(cl, capiMachineSet) - Expect(capiMachines).ToNot(BeEmpty(), "no CAPI Machines found") - Expect(capiMachines[0].Name).To(Equal(mapiMachines[0].Name)) - firstMAPIMachine = mapiMachines[0] - - DeferCleanup(func() { - By("Cleaning up Context 'with spec.authoritativeAPI: ClusterAPI' resources") - cleanupMachineSetTestResources( - ctx, - cl, - []*clusterv1.MachineSet{capiMachineSet}, - []*awsv1.AWSMachineTemplate{awsMachineTemplate}, - []*mapiv1beta1.MachineSet{mapiMachineSet}, - ) - }) - }) - It("should succeed scaling CAPI MachineSet to 2 replicas", func() { By("Scaling up CAPI MachineSet to 2 replicas") - capiframework.ScaleCAPIMachineSet(mapiMSAuthCAPIName, 2, capiframework.CAPINamespace) + capiframework.ScaleCAPIMachineSet(mapiMSScale.Name, 2, capiframework.CAPINamespace) By("Verifying MachineSet status.replicas is set to 2") - verifyMachinesetReplicas(capiMachineSet, 2) - verifyMachinesetReplicas(mapiMachineSet, 2) + verifyMachinesetReplicas(capiMSMirrorScale, 2) + verifyMachinesetReplicas(mapiMSScale, 2) By("Verifying a new CAPI Machine is created and Paused condition is False") - capiMachineSet = capiframework.GetMachineSet(cl, mapiMSAuthCAPIName, capiframework.CAPINamespace) - capiMachine := capiframework.GetNewestMachineFromMachineSet(cl, capiMachineSet) + Eventually(func(g Gomega) { + capiMSMirrorScale = capiframework.GetMachineSet(cl, mapiMSScale.Name, capiframework.CAPINamespace) + g.Expect(capiMSMirrorScale).NotTo(BeNil(), "Should have found CAPI MachineSet") + }, capiframework.WaitShort, capiframework.RetryShort).Should(Succeed(), "Should have refreshed CAPI MachineSet") + capiMachine := capiframework.GetNewestMachineFromMachineSet(cl, capiMSMirrorScale) verifyMachineRunning(cl, capiMachine) verifyMachinePausedCondition(capiMachine, mapiv1beta1.MachineAuthorityClusterAPI) By("Verifying there is a non-authoritative, paused MAPI Machine mirror for the new CAPI Machine") var err error - secondMAPIMachine, err = mapiframework.GetLatestMachineFromMachineSet(ctx, cl, mapiMachineSet) - Expect(err).ToNot(HaveOccurred(), "failed to get MAPI Machines from MachineSet") + Eventually(func(g Gomega) { + secondMAPIMachine, err = mapiframework.GetLatestMachineFromMachineSet(ctx, cl, mapiMSScale) + g.Expect(err).ToNot(HaveOccurred(), "Should have successfully got MAPI Machines from MachineSet") + }, capiframework.WaitMedium, capiframework.RetryMedium).Should(Succeed(), "Should have found latest MAPI Machine from MachineSet") verifyMachineAuthoritative(secondMAPIMachine, mapiv1beta1.MachineAuthorityClusterAPI) verifyMachinePausedCondition(secondMAPIMachine, mapiv1beta1.MachineAuthorityClusterAPI) }) It("should succeed switching MachineSet's AuthoritativeAPI to MachineAPI", func() { - switchMachineSetAuthoritativeAPI(mapiMachineSet, mapiv1beta1.MachineAuthorityMachineAPI, mapiv1beta1.MachineAuthorityMachineAPI) - verifyMachineSetPausedCondition(mapiMachineSet, mapiv1beta1.MachineAuthorityMachineAPI) - verifyMachineSetPausedCondition(capiMachineSet, mapiv1beta1.MachineAuthorityMachineAPI) - verifyMAPIMachineSetSynchronizedCondition(mapiMachineSet, mapiv1beta1.MachineAuthorityMachineAPI) + switchMachineSetAuthoritativeAPI(mapiMSScale, mapiv1beta1.MachineAuthorityMachineAPI, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMachineSetPausedCondition(mapiMSScale, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMachineSetPausedCondition(capiMSMirrorScale, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMAPIMachineSetSynchronizedCondition(mapiMSScale, mapiv1beta1.MachineAuthorityMachineAPI) }) It("should succeed scaling up MAPI MachineSet to 3, after switching AuthoritativeAPI to MachineAPI", func() { By("Scaling up MAPI MachineSet to 3 replicas") - Expect(mapiframework.ScaleMachineSet(mapiMSAuthCAPIName, 3)).To(Succeed(), "should be able to scale up MAPI MachineSet") + Eventually(func() error { + return mapiframework.ScaleMachineSet(mapiMSScale.Name, 3) + }, capiframework.WaitShort, capiframework.RetryShort).Should(Succeed(), "Should be able to scale up MAPI MachineSet") By("Verifying MachineSet status.replicas is set to 3") - verifyMachinesetReplicas(mapiMachineSet, 3) - verifyMachinesetReplicas(capiMachineSet, 3) + verifyMachinesetReplicas(mapiMSScale, 3) + verifyMachinesetReplicas(capiMSMirrorScale, 3) By("Verifying the newly requested MAPI Machine has been created and its status.authoritativeAPI is MachineAPI and its Paused condition is False") - mapiMachine, err := mapiframework.GetLatestMachineFromMachineSet(ctx, cl, mapiMachineSet) - Expect(err).ToNot(HaveOccurred(), "failed to get MAPI Machines from MachineSet") + var mapiMachine *mapiv1beta1.Machine + var err error + Eventually(func(g Gomega) { + mapiMachine, err = mapiframework.GetLatestMachineFromMachineSet(ctx, cl, mapiMSScale) + g.Expect(err).ToNot(HaveOccurred(), "Should have successfully got MAPI Machines from MachineSet") + }, capiframework.WaitMedium, capiframework.RetryMedium).Should(Succeed(), "Should have found latest MAPI Machine from MachineSet") verifyMachineRunning(cl, mapiMachine) verifyMachineAuthoritative(mapiMachine, mapiv1beta1.MachineAuthorityMachineAPI) verifyMachinePausedCondition(mapiMachine, mapiv1beta1.MachineAuthorityMachineAPI) By("Verifying there is a non-authoritative, paused CAPI Machine mirror for the new MAPI Machine") - capiMachine := capiframework.GetNewestMachineFromMachineSet(cl, capiMachineSet) + capiMachine := capiframework.GetNewestMachineFromMachineSet(cl, capiMSMirrorScale) verifyMachinePausedCondition(capiMachine, mapiv1beta1.MachineAuthorityMachineAPI) By("Verifying old Machines still exist and authority on them is still ClusterAPI") @@ -194,96 +242,88 @@ var _ = Describe("[sig-cluster-lifecycle][OCPFeatureGate:MachineAPIMigration] Ma It("should succeed scaling down MAPI MachineSet to 1, after the switch of AuthoritativeAPI to MachineAPI", func() { By("Scaling down MAPI MachineSet to 1 replicas") - Expect(mapiframework.ScaleMachineSet(mapiMSAuthCAPIName, 1)).To(Succeed(), "should be able to scale down MAPI MachineSet") - verifyMachinesetReplicas(mapiMachineSet, 1) - verifyMachinesetReplicas(capiMachineSet, 1) + Eventually(func() error { + return mapiframework.ScaleMachineSet(mapiMSScale.Name, 1) + }, capiframework.WaitShort, capiframework.RetryShort).Should(Succeed(), "Should be able to scale down MAPI MachineSet") + verifyMachinesetReplicas(mapiMSScale, 1) + verifyMachinesetReplicas(capiMSMirrorScale, 1) }) It("should succeed switching back MachineSet's AuthoritativeAPI to ClusterAPI, after the initial switch to AuthoritativeAPI: MachineAPI", func() { - switchMachineSetAuthoritativeAPI(mapiMachineSet, mapiv1beta1.MachineAuthorityClusterAPI, mapiv1beta1.MachineAuthorityClusterAPI) - verifyMachineSetPausedCondition(mapiMachineSet, mapiv1beta1.MachineAuthorityClusterAPI) - verifyMachineSetPausedCondition(capiMachineSet, mapiv1beta1.MachineAuthorityClusterAPI) - verifyMAPIMachineSetSynchronizedCondition(mapiMachineSet, mapiv1beta1.MachineAuthorityClusterAPI) + switchMachineSetAuthoritativeAPI(mapiMSScale, mapiv1beta1.MachineAuthorityClusterAPI, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachineSetPausedCondition(mapiMSScale, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachineSetPausedCondition(capiMSMirrorScale, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMAPIMachineSetSynchronizedCondition(mapiMSScale, mapiv1beta1.MachineAuthorityClusterAPI) }) It("should delete both MAPI and CAPI MachineSets/Machines and InfraMachineTemplate when deleting CAPI MachineSet", func() { - capiframework.DeleteMachineSets(ctx, cl, capiMachineSet) - mapiframework.WaitForMachineSetsDeleted(ctx, cl, mapiMachineSet) - capiframework.WaitForMachineSetsDeleted(cl, capiMachineSet) - verifyResourceRemoved(awsMachineTemplate) + capiframework.DeleteMachineSets(ctx, cl, capiMSMirrorScale) + mapiframework.WaitForMachineSetsDeleted(ctx, cl, mapiMSScale) + capiframework.WaitForMachineSetsDeleted(cl, capiMSMirrorScale) + verifyResourceRemoved(awsMachineTemplateScale) }) }) }) var _ = Describe("Delete MachineSets", Ordered, func() { - var mapiMSAuthMAPIName = "ms-authoritativeapi-mapi" - var mapiMachineSet *mapiv1beta1.MachineSet - var capiMachineSet *clusterv1.MachineSet - var awsMachineTemplate *awsv1.AWSMachineTemplate + AfterAll(func() { + By("Cleaning up Delete test resources") + cleanupMachineSetTestResources( + ctx, + cl, + []*clusterv1.MachineSet{capiMSMirrorDelete}, + []*awsv1.AWSMachineTemplate{awsMachineTemplateDelete}, + []*mapiv1beta1.MachineSet{mapiMSDelete}, + ) + }) Context("when removing non-authoritative MAPI MachineSet", Ordered, func() { - BeforeAll(func() { - mapiMachineSet = createMAPIMachineSetWithAuthoritativeAPI(ctx, cl, 1, mapiMSAuthMAPIName, mapiv1beta1.MachineAuthorityMachineAPI, mapiv1beta1.MachineAuthorityMachineAPI) - capiMachineSet, awsMachineTemplate = waitForMAPIMachineSetMirrors(cl, mapiMSAuthMAPIName) - - mapiMachines, err := mapiframework.GetMachinesFromMachineSet(ctx, cl, mapiMachineSet) - Expect(mapiMachines).ToNot(BeEmpty(), "no MAPI Machines found") - Expect(err).ToNot(HaveOccurred(), "failed to get MAPI Machines from MachineSet") - - capiMachines := capiframework.GetMachinesFromMachineSet(cl, capiMachineSet) - Expect(capiMachines).ToNot(BeEmpty(), "no CAPI Machines found") - Expect(capiMachines[0].Name).To(Equal(mapiMachines[0].Name)) - - DeferCleanup(func() { - By("Cleaning up Context 'when removing non-authoritative MAPI MachineSet' resources") - cleanupMachineSetTestResources( - ctx, - cl, - []*clusterv1.MachineSet{capiMachineSet}, - []*awsv1.AWSMachineTemplate{awsMachineTemplate}, - []*mapiv1beta1.MachineSet{mapiMachineSet}, - ) - }) - }) - It("shouldn't delete its authoritative CAPI MachineSet", func() { By("Switching AuthoritativeAPI to ClusterAPI") - switchMachineSetAuthoritativeAPI(mapiMachineSet, mapiv1beta1.MachineAuthorityClusterAPI, mapiv1beta1.MachineAuthorityClusterAPI) + switchMachineSetAuthoritativeAPI(mapiMSDelete, mapiv1beta1.MachineAuthorityClusterAPI, mapiv1beta1.MachineAuthorityClusterAPI) // TODO(OCPBUGS-74571): this extra verification step is a workaround as a stop-gap until // remove this once https://issues.redhat.com/browse/OCPBUGS-74571 is fixed. By("Verifying MAPI MachineSet is paused and CAPI MachineSet is unpaused after switch") - verifyMachineSetPausedCondition(mapiMachineSet, mapiv1beta1.MachineAuthorityClusterAPI) - verifyMachineSetPausedCondition(capiMachineSet, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachineSetPausedCondition(mapiMSDelete, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachineSetPausedCondition(capiMSMirrorDelete, mapiv1beta1.MachineAuthorityClusterAPI) By("Scaling up CAPI MachineSet to 2 replicas") - capiframework.ScaleCAPIMachineSet(mapiMachineSet.GetName(), 2, capiframework.CAPINamespace) + capiframework.ScaleCAPIMachineSet(mapiMSDelete.GetName(), 2, capiframework.CAPINamespace) By("Verifying MachineSet status.replicas is set to 2") - verifyMachinesetReplicas(capiMachineSet, 2) - verifyMachinesetReplicas(mapiMachineSet, 2) + verifyMachinesetReplicas(capiMSMirrorDelete, 2) + verifyMachinesetReplicas(mapiMSDelete, 2) By("Verifying new CAPI Machine is running") - capiMachine := capiframework.GetNewestMachineFromMachineSet(cl, capiMachineSet) + capiMachine := capiframework.GetNewestMachineFromMachineSet(cl, capiMSMirrorDelete) verifyMachineRunning(cl, capiMachine) verifyMachinePausedCondition(capiMachine, mapiv1beta1.MachineAuthorityClusterAPI) By("Verifying there is a non-authoritative, paused MAPI Machine mirror for the new CAPI Machine") - mapiMachine, err := mapiframework.GetLatestMachineFromMachineSet(ctx, cl, mapiMachineSet) - Expect(err).ToNot(HaveOccurred(), "failed to get MAPI Machines from MachineSet") + var mapiMachine *mapiv1beta1.Machine + var err error + Eventually(func(g Gomega) { + mapiMachine, err = mapiframework.GetLatestMachineFromMachineSet(ctx, cl, mapiMSDelete) + g.Expect(err).ToNot(HaveOccurred(), "Should have successfully got MAPI Machines from MachineSet") + }, capiframework.WaitMedium, capiframework.RetryMedium).Should(Succeed(), "Should have found latest MAPI Machine from MachineSet") verifyMachineAuthoritative(mapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) verifyMachinePausedCondition(mapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) By("Deleting non-authoritative MAPI MachineSet") - mapiMachineSet, err = mapiframework.GetMachineSet(ctx, cl, mapiMSAuthMAPIName) - Expect(err).ToNot(HaveOccurred(), "failed to get mapiMachineSet") - mapiframework.DeleteMachineSets(cl, mapiMachineSet) + Eventually(func(g Gomega) { + mapiMSDelete, err = mapiframework.GetMachineSet(ctx, cl, mapiMSDelete.Name) + g.Expect(err).ToNot(HaveOccurred(), "Should have successfully got mapiMachineSet") + }, capiframework.WaitShort, capiframework.RetryShort).Should(Succeed(), "Should have refreshed mapiMachineSet") + mapiframework.DeleteMachineSets(cl, mapiMSDelete) By("Verifying CAPI MachineSet not removed, both MAPI Machines and Mirrors remain") // TODO: Add full verification once OCPBUGS-56897 is fixed - capiMachineSet = capiframework.GetMachineSet(cl, mapiMSAuthMAPIName, capiframework.CAPINamespace) - Expect(capiMachineSet).ToNot(BeNil(), "CAPI MachineSet should still exist after deleting non-authoritative MAPI MachineSet") - Expect(capiMachineSet.DeletionTimestamp.IsZero()).To(BeTrue(), "CAPI MachineSet should not be marked for deletion") + Eventually(func(g Gomega) { + capiMSMirrorDelete = capiframework.GetMachineSet(cl, mapiMSDelete.Name, capiframework.CAPINamespace) + g.Expect(capiMSMirrorDelete).ToNot(BeNil(), "Should have found CAPI MachineSet after deleting non-authoritative MAPI MachineSet") + g.Expect(capiMSMirrorDelete.DeletionTimestamp.IsZero()).To(BeTrue(), "Should have CAPI MachineSet not marked for deletion") + }, capiframework.WaitShort, capiframework.RetryShort).Should(Succeed(), "Should have verified CAPI MachineSet still exists") }) }) }) diff --git a/e2e/machineset_migration_helpers.go b/e2e/machineset_migration_helpers.go index 3a0b6cf24..0bcf81eaa 100644 --- a/e2e/machineset_migration_helpers.go +++ b/e2e/machineset_migration_helpers.go @@ -23,6 +23,14 @@ import ( // createCAPIMachineSet creates a CAPI MachineSet with an AWSMachineTemplate and waits for it to be ready. func createCAPIMachineSet(ctx context.Context, cl client.Client, replicas int32, machineSetName string, instanceType string) *clusterv1.MachineSet { + return createCAPIMachineSetSkipWait(ctx, cl, replicas, machineSetName, instanceType, false) +} + +// createCAPIMachineSetSkipWait creates a CAPI MachineSet with an AWSMachineTemplate. +// If skipWait is true, it skips waiting for the MachineSet to be ready. +// This allows for parallel creation of multiple MachineSets to reduce total test time. +func createCAPIMachineSetSkipWait(ctx context.Context, cl client.Client, replicas int32, machineSetName string, instanceType string, skipWait bool) *clusterv1.MachineSet { + GinkgoHelper() By(fmt.Sprintf("Creating CAPI MachineSet %s with %d replicas", machineSetName, replicas)) _, mapiDefaultProviderSpec := getDefaultAWSMAPIProviderSpec() createAWSClient(mapiDefaultProviderSpec.Placement.Region) @@ -47,12 +55,22 @@ func createCAPIMachineSet(ctx context.Context, cl client.Client, replicas int32, "worker-user-data", )) - capiframework.WaitForMachineSet(cl, machineSet.Name, machineSet.Namespace) + if !skipWait { + capiframework.WaitForMachineSet(cl, machineSet.Name, machineSet.Namespace) + } return machineSet } // createMAPIMachineSetWithAuthoritativeAPI creates a MAPI MachineSet with specified authoritativeAPI and waits for the CAPI mirror to be created. func createMAPIMachineSetWithAuthoritativeAPI(ctx context.Context, cl client.Client, replicas int, machineSetName string, machineSetAuthority mapiv1beta1.MachineAuthority, machineAuthority mapiv1beta1.MachineAuthority) *mapiv1beta1.MachineSet { + return createMAPIMachineSetWithAuthoritativeAPISkipWait(ctx, cl, replicas, machineSetName, machineSetAuthority, machineAuthority, false) +} + +// createMAPIMachineSetWithAuthoritativeAPISkipWait creates a MAPI MachineSet with specified authoritativeAPI. +// If skipWait is true, it skips waiting for the CAPI mirror creation and Machine running state. +// This allows for parallel creation of multiple MachineSets to reduce total test time. +func createMAPIMachineSetWithAuthoritativeAPISkipWait(ctx context.Context, cl client.Client, replicas int, machineSetName string, machineSetAuthority mapiv1beta1.MachineAuthority, machineAuthority mapiv1beta1.MachineAuthority, skipWait bool) *mapiv1beta1.MachineSet { + GinkgoHelper() By(fmt.Sprintf("Creating MAPI MachineSet with spec.authoritativeAPI: %s, spec.template.spec.authoritativeAPI: %s, replicas=%d", machineSetAuthority, machineAuthority, replicas)) machineSetParams := mapiframework.BuildMachineSetParams(ctx, cl, replicas) machineSetParams.Name = machineSetName @@ -64,6 +82,10 @@ func createMAPIMachineSetWithAuthoritativeAPI(ctx context.Context, cl client.Cli mapiMachineSet, err := mapiframework.CreateMachineSet(cl, machineSetParams) Expect(err).ToNot(HaveOccurred(), "MAPI MachineSet %s creation should succeed", machineSetName) + if skipWait { + return mapiMachineSet + } + capiMachineSet := &clusterv1.MachineSet{ ObjectMeta: metav1.ObjectMeta{ Name: machineSetName, @@ -82,8 +104,31 @@ func createMAPIMachineSetWithAuthoritativeAPI(ctx context.Context, cl client.Cli return mapiMachineSet } +// waitForMAPIMachineSetReady waits for a MAPI MachineSet's CAPI mirror and Machines to be ready. +func waitForMAPIMachineSetReady(ctx context.Context, cl client.Client, machineSetName string, machineAuthority mapiv1beta1.MachineAuthority) { + GinkgoHelper() + By(fmt.Sprintf("Waiting for MachineSet %s to be ready", machineSetName)) + + capiMachineSet := &clusterv1.MachineSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: machineSetName, + Namespace: capiframework.CAPINamespace, + }, + } + Eventually(komega.Get(capiMachineSet), capiframework.WaitShort, capiframework.RetryShort).Should( + Succeed(), "Should have mirror CAPI MachineSet created within 1 minute") + + switch machineAuthority { + case mapiv1beta1.MachineAuthorityMachineAPI: + mapiframework.WaitForMachineSet(ctx, cl, machineSetName) + case mapiv1beta1.MachineAuthorityClusterAPI: + capiframework.WaitForMachineSet(cl, machineSetName, capiframework.CAPINamespace) + } +} + // switchMachineSetAuthoritativeAPI updates the authoritativeAPI fields of a MAPI MachineSet and its template. func switchMachineSetAuthoritativeAPI(mapiMachineSet *mapiv1beta1.MachineSet, machineSetAuthority mapiv1beta1.MachineAuthority, machineAuthority mapiv1beta1.MachineAuthority) { + GinkgoHelper() By(fmt.Sprintf("Switching MachineSet %s AuthoritativeAPI to spec.authoritativeAPI: %s, spec.template.spec.authoritativeAPI: %s", mapiMachineSet.Name, machineSetAuthority, machineAuthority)) Eventually(komega.Update(mapiMachineSet, func() { mapiMachineSet.Spec.AuthoritativeAPI = machineSetAuthority @@ -93,6 +138,7 @@ func switchMachineSetAuthoritativeAPI(mapiMachineSet *mapiv1beta1.MachineSet, ma // verifyMachineSetAuthoritative verifies that a MAPI MachineSet's status.authoritativeAPI matches the expected authority. func verifyMachineSetAuthoritative(mapiMachineSet *mapiv1beta1.MachineSet, authority mapiv1beta1.MachineAuthority) { + GinkgoHelper() By(fmt.Sprintf("Verifying the MachineSet authoritative is %s", authority)) Eventually(komega.Object(mapiMachineSet), capiframework.WaitMedium, capiframework.RetryMedium).Should( HaveField("Status.AuthoritativeAPI", Equal(authority)), @@ -102,6 +148,7 @@ func verifyMachineSetAuthoritative(mapiMachineSet *mapiv1beta1.MachineSet, autho // verifyMachineSetPausedCondition verifies the Paused condition of a MachineSet (MAPI or CAPI) based on its authoritative API. func verifyMachineSetPausedCondition(machineSet client.Object, authority mapiv1beta1.MachineAuthority) { + GinkgoHelper() Expect(machineSet).NotTo(BeNil(), "MachineSet parameter cannot be nil") Expect(machineSet.GetName()).NotTo(BeEmpty(), "MachineSet name cannot be empty") var conditionMatcher types.GomegaMatcher @@ -168,6 +215,7 @@ func verifyMachineSetPausedCondition(machineSet client.Object, authority mapiv1b // verifyMachinesetReplicas verifies that a MachineSet (MAPI or CAPI) has the expected number of replicas in its status. func verifyMachinesetReplicas(machineSet client.Object, replicas int) { + GinkgoHelper() Expect(machineSet).NotTo(BeNil(), "Machine parameter cannot be nil") Expect(machineSet.GetName()).NotTo(BeEmpty(), "Machine name cannot be empty") switch ms := machineSet.(type) { @@ -188,6 +236,7 @@ func verifyMachinesetReplicas(machineSet client.Object, replicas int) { // verifyMAPIMachineSetSynchronizedCondition verifies that a MAPI MachineSet has the Synchronized condition set to True with the correct message. func verifyMAPIMachineSetSynchronizedCondition(mapiMachineSet *mapiv1beta1.MachineSet, authority mapiv1beta1.MachineAuthority) { + GinkgoHelper() By("Verifying the MAPI MachineSet Synchronized condition is True") var expectedMessage string @@ -220,6 +269,7 @@ func verifyMAPIMachineSetSynchronizedCondition(mapiMachineSet *mapiv1beta1.Machi // verifyMAPIMachineSetProviderSpec verifies that a MAPI MachineSet's providerSpec matches the given Gomega matcher. func verifyMAPIMachineSetProviderSpec(mapiMachineSet *mapiv1beta1.MachineSet, matcher types.GomegaMatcher) { + GinkgoHelper() By(fmt.Sprintf("Verifying MAPI MachineSet %s ProviderSpec", mapiMachineSet.Name)) Eventually(komega.Object(mapiMachineSet), capiframework.WaitMedium, capiframework.RetryShort).Should( WithTransform(getAWSProviderSpecFromMachineSet, matcher), @@ -228,6 +278,7 @@ func verifyMAPIMachineSetProviderSpec(mapiMachineSet *mapiv1beta1.MachineSet, ma // getAWSProviderSpecFromMachineSet extracts and unmarshals the AWSMachineProviderConfig from a MAPI MachineSet. func getAWSProviderSpecFromMachineSet(mapiMachineSet *mapiv1beta1.MachineSet) *mapiv1beta1.AWSMachineProviderConfig { + GinkgoHelper() Expect(mapiMachineSet.Spec.Template.Spec.ProviderSpec.Value).ToNot(BeNil()) providerSpec := &mapiv1beta1.AWSMachineProviderConfig{} @@ -238,6 +289,7 @@ func getAWSProviderSpecFromMachineSet(mapiMachineSet *mapiv1beta1.MachineSet) *m // updateAWSMachineSetProviderSpec updates a MAPI MachineSet's AWS providerSpec using the provided update function. func updateAWSMachineSetProviderSpec(ctx context.Context, cl client.Client, mapiMachineSet *mapiv1beta1.MachineSet, updateFunc func(*mapiv1beta1.AWSMachineProviderConfig)) { + GinkgoHelper() By(fmt.Sprintf("Updating MachineSet %s providerSpec", mapiMachineSet.Name)) providerSpec := getAWSProviderSpecFromMachineSet(mapiMachineSet) @@ -255,6 +307,7 @@ func updateAWSMachineSetProviderSpec(ctx context.Context, cl client.Client, mapi // waitForMAPIMachineSetMirrors waits for the corresponding CAPI MachineSet and AWSMachineTemplate mirrors to be created for a MAPI MachineSet. func waitForMAPIMachineSetMirrors(cl client.Client, machineSetNameMAPI string) (*clusterv1.MachineSet, *awsv1.AWSMachineTemplate) { + GinkgoHelper() By(fmt.Sprintf("Verifying there is a CAPI MachineSet mirror and AWSMachineTemplate for MAPI MachineSet %s", machineSetNameMAPI)) var err error var capiMachineSet *clusterv1.MachineSet @@ -278,6 +331,7 @@ func waitForMAPIMachineSetMirrors(cl client.Client, machineSetNameMAPI string) ( // waitForCAPIMachineSetMirror waits for a CAPI MachineSet mirror to be created for a MAPI MachineSet. func waitForCAPIMachineSetMirror(cl client.Client, machineName string) *clusterv1.MachineSet { + GinkgoHelper() By(fmt.Sprintf("Verifying there is a CAPI MachineSet mirror for MAPI MachineSet %s", machineName)) var capiMachineSet *clusterv1.MachineSet Eventually(func() error { @@ -292,6 +346,7 @@ func waitForCAPIMachineSetMirror(cl client.Client, machineName string) *clusterv // waitForAWSMachineTemplate waits for an AWSMachineTemplate with the specified name prefix to be created. func waitForAWSMachineTemplate(cl client.Client, prefix string) *awsv1.AWSMachineTemplate { + GinkgoHelper() By(fmt.Sprintf("Verifying there is an AWSMachineTemplate with prefix %s", prefix)) var awsMachineTemplate *awsv1.AWSMachineTemplate Eventually(func() error { @@ -308,6 +363,7 @@ func waitForAWSMachineTemplate(cl client.Client, prefix string) *awsv1.AWSMachin // createAWSMachineTemplate creates a new AWSMachineTemplate with an optional update function to modify the spec. func createAWSMachineTemplate(ctx context.Context, cl client.Client, originalName string, updateFunc func(*awsv1.AWSMachineSpec)) *awsv1.AWSMachineTemplate { + GinkgoHelper() By("Creating a new awsMachineTemplate") _, mapiDefaultProviderSpec := getDefaultAWSMAPIProviderSpec() createAWSClient(mapiDefaultProviderSpec.Placement.Region) @@ -327,6 +383,7 @@ func createAWSMachineTemplate(ctx context.Context, cl client.Client, originalNam // updateCAPIMachineSetInfraTemplate updates a CAPI MachineSet's infrastructureRef to point to a new template. func updateCAPIMachineSetInfraTemplate(capiMachineSet *clusterv1.MachineSet, newInfraTemplateName string) { + GinkgoHelper() By(fmt.Sprintf("Updating CAPI MachineSet %s to point to new InfraTemplate %s", capiMachineSet.Name, newInfraTemplateName)) Eventually(komega.Update(capiMachineSet, func() { capiMachineSet.Spec.Template.Spec.InfrastructureRef.Name = newInfraTemplateName diff --git a/e2e/machineset_migration_mapi_authoritative_test.go b/e2e/machineset_migration_mapi_authoritative_test.go index 800a5f4a6..bcaeb5068 100644 --- a/e2e/machineset_migration_mapi_authoritative_test.go +++ b/e2e/machineset_migration_mapi_authoritative_test.go @@ -18,6 +18,28 @@ import ( var _ = Describe("[sig-cluster-lifecycle][OCPFeatureGate:MachineAPIMigration] MachineSet Migration MAPI Authoritative Tests", Ordered, func() { var k komega.Komega + var mapiMSAuthMAPI *mapiv1beta1.MachineSet + var capiMSMirrorAuthMAPI *clusterv1.MachineSet + var awsMachineTemplateAuthMAPI *awsv1.AWSMachineTemplate + + var capiMSAuthMAPISameName *clusterv1.MachineSet + var awsMachineTemplateAuthMAPISameName *awsv1.AWSMachineTemplate + + var mapiMSScale *mapiv1beta1.MachineSet + var capiMSMirrorScale *clusterv1.MachineSet + var awsMachineTemplateScale *awsv1.AWSMachineTemplate + var firstMAPIMachine *mapiv1beta1.Machine + var secondMAPIMachine *mapiv1beta1.Machine + + var mapiMSScaleCAPI *mapiv1beta1.MachineSet + var capiMSMirrorScaleCAPI *clusterv1.MachineSet + var awsMachineTemplateScaleCAPI *awsv1.AWSMachineTemplate + + var mapiMSUpdate *mapiv1beta1.MachineSet + var capiMSMirrorUpdate *clusterv1.MachineSet + var awsMachineTemplateUpdate *awsv1.AWSMachineTemplate + var newAWSMachineTemplateUpdate *awsv1.AWSMachineTemplate + BeforeAll(func() { if platform != configv1.AWSPlatformType { Skip(fmt.Sprintf("Skipping tests on %s, this is only supported on AWS", platform)) @@ -28,162 +50,180 @@ var _ = Describe("[sig-cluster-lifecycle][OCPFeatureGate:MachineAPIMigration] Ma } k = komega.New(cl) + + // Creating all MachineSets without waiting (parallel creation)" + By("Creating MachineSets for Create tests") + mapiMSAuthMAPI = createMAPIMachineSetWithAuthoritativeAPISkipWait( + ctx, cl, 0, + UniqueName("ms-authoritativeapi-mapi"), + mapiv1beta1.MachineAuthorityMachineAPI, + mapiv1beta1.MachineAuthorityMachineAPI, + true, // skipWait=true + ) + + By("Creating CAPI MachineSet first for existing CAPI MachineSet scenario") + capiMSAuthMAPISameName = createCAPIMachineSetSkipWait(ctx, cl, 0, UniqueName("capi-machineset-authoritativeapi-mapi"), "", true) + + By("Creating MachineSet for Scale tests with spec.authoritativeAPI: MachineAPI") + mapiMSScale = createMAPIMachineSetWithAuthoritativeAPISkipWait( + ctx, cl, 1, + UniqueName("ms-authoritativeapi-mapi-scale"), + mapiv1beta1.MachineAuthorityMachineAPI, + mapiv1beta1.MachineAuthorityMachineAPI, + true, // skipWait=true + ) + mapiMSScaleCAPI = createMAPIMachineSetWithAuthoritativeAPISkipWait( + ctx, cl, 0, + UniqueName("ms-mapi-machine-capi-scale"), + mapiv1beta1.MachineAuthorityMachineAPI, + mapiv1beta1.MachineAuthorityClusterAPI, + true, // skipWait=true + ) + + By("Creating MachineSet for Update tests with spec.authoritativeAPI: MachineAPI") + mapiMSUpdate = createMAPIMachineSetWithAuthoritativeAPISkipWait( + ctx, cl, 0, + UniqueName("ms-authoritativeapi-mapi-update"), + mapiv1beta1.MachineAuthorityMachineAPI, + mapiv1beta1.MachineAuthorityMachineAPI, + true, // skipWait=true + ) + + By("Waiting for all MachineSets to become ready (parallel waiting)") + waitForMAPIMachineSetReady(ctx, cl, mapiMSAuthMAPI.Name, mapiv1beta1.MachineAuthorityMachineAPI) + capiframework.WaitForMachineSet(cl, capiMSAuthMAPISameName.Name, capiframework.CAPINamespace) + waitForMAPIMachineSetReady(ctx, cl, mapiMSScale.Name, mapiv1beta1.MachineAuthorityMachineAPI) + waitForMAPIMachineSetReady(ctx, cl, mapiMSScaleCAPI.Name, mapiv1beta1.MachineAuthorityMachineAPI) + waitForMAPIMachineSetReady(ctx, cl, mapiMSUpdate.Name, mapiv1beta1.MachineAuthorityMachineAPI) + + By("Getting all MachineSet mirrors and templates") + capiMSMirrorAuthMAPI, awsMachineTemplateAuthMAPI = waitForMAPIMachineSetMirrors(cl, mapiMSAuthMAPI.Name) + awsMachineTemplateAuthMAPISameName = waitForAWSMachineTemplate(cl, capiMSAuthMAPISameName.Name) + capiMSMirrorScale, awsMachineTemplateScale = waitForMAPIMachineSetMirrors(cl, mapiMSScale.Name) + capiMSMirrorScaleCAPI, awsMachineTemplateScaleCAPI = waitForMAPIMachineSetMirrors(cl, mapiMSScaleCAPI.Name) + capiMSMirrorUpdate, awsMachineTemplateUpdate = waitForMAPIMachineSetMirrors(cl, mapiMSUpdate.Name) + + By("Getting Machines from Scale MachineSet") + mapiMachines, err := mapiframework.GetMachinesFromMachineSet(ctx, cl, mapiMSScale) + Expect(err).ToNot(HaveOccurred(), "Should have successfully got MAPI Machines from MachineSet") + Expect(mapiMachines).ToNot(BeEmpty(), "Should have found MAPI Machines") + + capiMachines := capiframework.GetMachinesFromMachineSet(cl, capiMSMirrorScale) + Expect(capiMachines).ToNot(BeEmpty(), "Should have found CAPI Machines") + Expect(capiMachines[0].Name).To(Equal(mapiMachines[0].Name), "Should have CAPI Machine name match MAPI Machine name") + firstMAPIMachine = mapiMachines[0] }) var _ = Describe("Create MAPI MachineSets", Ordered, func() { - var mapiMSAuthMAPIName = "ms-authoritativeapi-mapi" - var existingCAPIMSAuthorityMAPIName = "capi-machineset-authoritativeapi-mapi" - - var awsMachineTemplate *awsv1.AWSMachineTemplate - var capiMachineSet *clusterv1.MachineSet - var mapiMachineSet *mapiv1beta1.MachineSet + AfterAll(func() { + By("Cleaning up Create test resources") + cleanupMachineSetTestResources( + ctx, + cl, + []*clusterv1.MachineSet{capiMSMirrorAuthMAPI, capiMSAuthMAPISameName}, + []*awsv1.AWSMachineTemplate{awsMachineTemplateAuthMAPI, awsMachineTemplateAuthMAPISameName}, + []*mapiv1beta1.MachineSet{mapiMSAuthMAPI}, + ) + }) Context("with spec.authoritativeAPI: MachineAPI and existing CAPI MachineSet with same name", func() { - BeforeAll(func() { - capiMachineSet = createCAPIMachineSet(ctx, cl, 0, existingCAPIMSAuthorityMAPIName, "") - awsMachineTemplate = waitForAWSMachineTemplate(cl, existingCAPIMSAuthorityMAPIName) - - DeferCleanup(func() { - By("Cleaning up Context 'with spec.authoritativeAPI: MachineAPI and existing CAPI MachineSet with same name' resources") - cleanupMachineSetTestResources( - ctx, - cl, - []*clusterv1.MachineSet{capiMachineSet}, - []*awsv1.AWSMachineTemplate{awsMachineTemplate}, - []*mapiv1beta1.MachineSet{}, - ) - }) - }) - // https://issues.redhat.com/browse/OCPCLOUD-3188 PIt("should reject creation of MAPI MachineSet with same name as existing CAPI MachineSet", func() { By("Creating a same name MAPI MachineSet") - createMAPIMachineSetWithAuthoritativeAPI(ctx, cl, 0, existingCAPIMSAuthorityMAPIName, mapiv1beta1.MachineAuthorityMachineAPI, mapiv1beta1.MachineAuthorityMachineAPI) + createMAPIMachineSetWithAuthoritativeAPI(ctx, cl, 0, capiMSAuthMAPISameName.Name, mapiv1beta1.MachineAuthorityMachineAPI, mapiv1beta1.MachineAuthorityMachineAPI) }) }) Context("with spec.authoritativeAPI: MachineAPI and when no existing CAPI MachineSet with same name", func() { - BeforeAll(func() { - mapiMachineSet = createMAPIMachineSetWithAuthoritativeAPI(ctx, cl, 0, mapiMSAuthMAPIName, mapiv1beta1.MachineAuthorityMachineAPI, mapiv1beta1.MachineAuthorityMachineAPI) - capiMachineSet = waitForCAPIMachineSetMirror(cl, mapiMSAuthMAPIName) - awsMachineTemplate = waitForAWSMachineTemplate(cl, mapiMSAuthMAPIName) - - DeferCleanup(func() { - By("Cleaning up Context 'with spec.authoritativeAPI: MachineAPI and when no existing CAPI MachineSet with same name' resources") - cleanupMachineSetTestResources( - ctx, - cl, - []*clusterv1.MachineSet{}, - []*awsv1.AWSMachineTemplate{awsMachineTemplate}, - []*mapiv1beta1.MachineSet{mapiMachineSet}, - ) - }) - }) - It("should find MAPI MachineSet .status.authoritativeAPI to equal MAPI", func() { - verifyMachineSetAuthoritative(mapiMachineSet, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMachineSetAuthoritative(mapiMSAuthMAPI, mapiv1beta1.MachineAuthorityMachineAPI) }) It("should verify that MAPI MachineSet Paused condition is False", func() { - verifyMachineSetPausedCondition(mapiMachineSet, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMachineSetPausedCondition(mapiMSAuthMAPI, mapiv1beta1.MachineAuthorityMachineAPI) }) It("should verify that MAPI MachineSet Synchronized condition is True", func() { - verifyMAPIMachineSetSynchronizedCondition(mapiMachineSet, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMAPIMachineSetSynchronizedCondition(mapiMSAuthMAPI, mapiv1beta1.MachineAuthorityMachineAPI) }) It("should find that MAPI MachineSet has a CAPI MachineSet mirror", func() { - waitForCAPIMachineSetMirror(cl, mapiMSAuthMAPIName) + waitForCAPIMachineSetMirror(cl, mapiMSAuthMAPI.Name) }) It("should verify that the mirror CAPI MachineSet has Paused condition True", func() { - verifyMachineSetPausedCondition(capiMachineSet, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMachineSetPausedCondition(capiMSMirrorAuthMAPI, mapiv1beta1.MachineAuthorityMachineAPI) }) }) }) var _ = Describe("Scale MAPI MachineSets", Ordered, func() { - var mapiMSAuthMAPIName = "ms-authoritativeapi-mapi" - var mapiMSAuthMAPICAPI = "ms-mapi-machine-capi" - - var awsMachineTemplate *awsv1.AWSMachineTemplate - var capiMachineSet *clusterv1.MachineSet - var mapiMachineSet *mapiv1beta1.MachineSet - var firstMAPIMachine *mapiv1beta1.Machine - var secondMAPIMachine *mapiv1beta1.Machine + AfterAll(func() { + By("Cleaning up Scale test resources") + cleanupMachineSetTestResources( + ctx, + cl, + []*clusterv1.MachineSet{capiMSMirrorScale, capiMSMirrorScaleCAPI}, + []*awsv1.AWSMachineTemplate{awsMachineTemplateScale, awsMachineTemplateScaleCAPI}, + []*mapiv1beta1.MachineSet{mapiMSScale, mapiMSScaleCAPI}, + ) + }) Context("with spec.authoritativeAPI: MachineAPI", Ordered, func() { - BeforeAll(func() { - mapiMachineSet = createMAPIMachineSetWithAuthoritativeAPI(ctx, cl, 1, mapiMSAuthMAPIName, mapiv1beta1.MachineAuthorityMachineAPI, mapiv1beta1.MachineAuthorityMachineAPI) - capiMachineSet, awsMachineTemplate = waitForMAPIMachineSetMirrors(cl, mapiMSAuthMAPIName) - - mapiMachines, err := mapiframework.GetMachinesFromMachineSet(ctx, cl, mapiMachineSet) - Expect(err).ToNot(HaveOccurred(), "failed to get MAPI Machines from MachineSet") - Expect(mapiMachines).ToNot(BeEmpty(), "no MAPI Machines found") - - capiMachines := capiframework.GetMachinesFromMachineSet(cl, capiMachineSet) - Expect(capiMachines).ToNot(BeEmpty(), "no CAPI Machines found") - Expect(capiMachines[0].Name).To(Equal(mapiMachines[0].Name)) - firstMAPIMachine = mapiMachines[0] - - DeferCleanup(func() { - By("Cleaning up Context 'with spec.authoritativeAPI: MachineAPI' resources") - cleanupMachineSetTestResources( - ctx, - cl, - []*clusterv1.MachineSet{capiMachineSet}, - []*awsv1.AWSMachineTemplate{awsMachineTemplate}, - []*mapiv1beta1.MachineSet{mapiMachineSet}, - ) - }) - }) - It("should be able scale MAPI MachineSet to 2 replicas successfully", func() { By("Scaling up MAPI MachineSet to 2 replicas") - Expect(mapiframework.ScaleMachineSet(mapiMachineSet.GetName(), 2)).To(Succeed(), "should be able to scale up MAPI MachineSet") - mapiframework.WaitForMachineSet(ctx, cl, mapiMSAuthMAPIName) - verifyMachinesetReplicas(mapiMachineSet, 2) - verifyMachinesetReplicas(capiMachineSet, 2) + Eventually(func() error { + return mapiframework.ScaleMachineSet(mapiMSScale.GetName(), 2) + }, capiframework.WaitShort, capiframework.RetryShort).Should(Succeed(), "Should be able to scale up MAPI MachineSet") + mapiframework.WaitForMachineSet(ctx, cl, mapiMSScale.Name) + verifyMachinesetReplicas(mapiMSScale, 2) + verifyMachinesetReplicas(capiMSMirrorScale, 2) By("Verifying a new MAPI Machine is created and Paused condition is False") var err error - secondMAPIMachine, err = mapiframework.GetLatestMachineFromMachineSet(ctx, cl, mapiMachineSet) - Expect(err).ToNot(HaveOccurred(), "failed to get MAPI Machines from MachineSet") + Eventually(func(g Gomega) { + secondMAPIMachine, err = mapiframework.GetLatestMachineFromMachineSet(ctx, cl, mapiMSScale) + g.Expect(err).ToNot(HaveOccurred(), "Should have successfully got MAPI Machines from MachineSet") + }, capiframework.WaitMedium, capiframework.RetryMedium).Should(Succeed(), "Should have found latest MAPI Machine from MachineSet") verifyMachineRunning(cl, secondMAPIMachine) verifyMachineAuthoritative(secondMAPIMachine, mapiv1beta1.MachineAuthorityMachineAPI) verifyMachinePausedCondition(secondMAPIMachine, mapiv1beta1.MachineAuthorityMachineAPI) By("Verifying there is a non-authoritative CAPI Machine mirror for the MAPI Machine and its Paused condition is True") - capiMachine := capiframework.GetNewestMachineFromMachineSet(cl, capiMachineSet) + capiMachine := capiframework.GetNewestMachineFromMachineSet(cl, capiMSMirrorScale) verifyMachinePausedCondition(capiMachine, mapiv1beta1.MachineAuthorityMachineAPI) By("Verifying CAPI MachineSet status.replicas is set to 2") - verifyMachinesetReplicas(capiMachineSet, 2) + verifyMachinesetReplicas(capiMSMirrorScale, 2) }) It("should succeed switching MAPI MachineSet AuthoritativeAPI to ClusterAPI", func() { - switchMachineSetAuthoritativeAPI(mapiMachineSet, mapiv1beta1.MachineAuthorityClusterAPI, mapiv1beta1.MachineAuthorityClusterAPI) - verifyMachineSetPausedCondition(mapiMachineSet, mapiv1beta1.MachineAuthorityClusterAPI) - verifyMachineSetPausedCondition(capiMachineSet, mapiv1beta1.MachineAuthorityClusterAPI) - verifyMAPIMachineSetSynchronizedCondition(mapiMachineSet, mapiv1beta1.MachineAuthorityClusterAPI) + switchMachineSetAuthoritativeAPI(mapiMSScale, mapiv1beta1.MachineAuthorityClusterAPI, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachineSetPausedCondition(mapiMSScale, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMachineSetPausedCondition(capiMSMirrorScale, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMAPIMachineSetSynchronizedCondition(mapiMSScale, mapiv1beta1.MachineAuthorityClusterAPI) }) It("should succeed scaling up CAPI MachineSet to 3, after the switch of AuthoritativeAPI to ClusterAPI", func() { By("Scaling up CAPI MachineSet to 3") - capiframework.ScaleCAPIMachineSet(mapiMSAuthMAPIName, 3, capiframework.CAPINamespace) + capiframework.ScaleCAPIMachineSet(mapiMSScale.Name, 3, capiframework.CAPINamespace) By("Verifying MachineSet status.replicas is set to 3") - verifyMachinesetReplicas(capiMachineSet, 3) - verifyMachinesetReplicas(mapiMachineSet, 3) + verifyMachinesetReplicas(capiMSMirrorScale, 3) + verifyMachinesetReplicas(mapiMSScale, 3) By("Verifying a new CAPI Machine is running and Paused condition is False") - capiMachine := capiframework.GetNewestMachineFromMachineSet(cl, capiMachineSet) + capiMachine := capiframework.GetNewestMachineFromMachineSet(cl, capiMSMirrorScale) verifyMachineRunning(cl, capiMachine) verifyMachinePausedCondition(capiMachine, mapiv1beta1.MachineAuthorityClusterAPI) By("Verifying there is a non-authoritative, paused MAPI Machine mirror for the new CAPI Machine") - mapiMachine, err := mapiframework.GetLatestMachineFromMachineSet(ctx, cl, mapiMachineSet) - Expect(err).ToNot(HaveOccurred(), "failed to get MAPI Machines from MachineSet") + var err error + var mapiMachine *mapiv1beta1.Machine + Eventually(func(g Gomega) { + mapiMachine, err = mapiframework.GetLatestMachineFromMachineSet(ctx, cl, mapiMSScale) + g.Expect(err).ToNot(HaveOccurred(), "Should have successfully got MAPI Machines from MachineSet") + }, capiframework.WaitMedium, capiframework.RetryMedium).Should(Succeed(), "Should have found latest MAPI Machine from MachineSet") verifyMachineAuthoritative(mapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) verifyMachinePausedCondition(mapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) @@ -194,184 +234,188 @@ var _ = Describe("[sig-cluster-lifecycle][OCPFeatureGate:MachineAPIMigration] Ma It("should succeed scaling down CAPI MachineSet to 1, after the switch of AuthoritativeAPI to ClusterAPI", func() { By("Scaling down CAPI MachineSet to 1") - capiframework.ScaleCAPIMachineSet(mapiMSAuthMAPIName, 1, capiframework.CAPINamespace) + capiframework.ScaleCAPIMachineSet(mapiMSScale.Name, 1, capiframework.CAPINamespace) By("Verifying both CAPI MachineSet and its MAPI MachineSet mirror are scaled down to 1") - verifyMachinesetReplicas(capiMachineSet, 1) - verifyMachinesetReplicas(mapiMachineSet, 1) + verifyMachinesetReplicas(capiMSMirrorScale, 1) + verifyMachinesetReplicas(mapiMSScale, 1) }) It("should succeed in switching back the AuthoritativeAPI to MachineAPI after the initial switch to ClusterAPI", func() { - switchMachineSetAuthoritativeAPI(mapiMachineSet, mapiv1beta1.MachineAuthorityMachineAPI, mapiv1beta1.MachineAuthorityMachineAPI) - verifyMachineSetPausedCondition(mapiMachineSet, mapiv1beta1.MachineAuthorityMachineAPI) - verifyMachineSetPausedCondition(capiMachineSet, mapiv1beta1.MachineAuthorityMachineAPI) - verifyMAPIMachineSetSynchronizedCondition(mapiMachineSet, mapiv1beta1.MachineAuthorityMachineAPI) + switchMachineSetAuthoritativeAPI(mapiMSScale, mapiv1beta1.MachineAuthorityMachineAPI, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMachineSetPausedCondition(mapiMSScale, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMachineSetPausedCondition(capiMSMirrorScale, mapiv1beta1.MachineAuthorityMachineAPI) + verifyMAPIMachineSetSynchronizedCondition(mapiMSScale, mapiv1beta1.MachineAuthorityMachineAPI) }) It("should delete both MAPI and CAPI MachineSets/Machines and InfraMachineTemplate when deleting MAPI MachineSet", func() { - Expect(mapiframework.DeleteMachineSets(cl, mapiMachineSet)).To(Succeed(), "Should be able to delete test MachineSet") - capiframework.WaitForMachineSetsDeleted(cl, capiMachineSet) - mapiframework.WaitForMachineSetsDeleted(ctx, cl, mapiMachineSet) - verifyResourceRemoved(awsMachineTemplate) + Eventually(func() error { + return mapiframework.DeleteMachineSets(cl, mapiMSScale) + }, capiframework.WaitShort, capiframework.RetryShort).Should(Succeed(), "Should be able to delete test MachineSet") + capiframework.WaitForMachineSetsDeleted(cl, capiMSMirrorScale) + mapiframework.WaitForMachineSetsDeleted(ctx, cl, mapiMSScale) + verifyResourceRemoved(awsMachineTemplateScale) }) }) Context("with spec.authoritativeAPI: MachineAPI, spec.template.spec.authoritativeAPI: ClusterAPI", Ordered, func() { - BeforeAll(func() { - mapiMachineSet = createMAPIMachineSetWithAuthoritativeAPI(ctx, cl, 0, mapiMSAuthMAPICAPI, mapiv1beta1.MachineAuthorityMachineAPI, mapiv1beta1.MachineAuthorityClusterAPI) - capiMachineSet, awsMachineTemplate = waitForMAPIMachineSetMirrors(cl, mapiMSAuthMAPICAPI) - - DeferCleanup(func() { - By("Cleaning up Context 'with spec.authoritativeAPI: MachineAPI, spec.template.spec.authoritativeAPI: ClusterAPI' resources") - cleanupMachineSetTestResources( - ctx, - cl, - []*clusterv1.MachineSet{capiMachineSet}, - []*awsv1.AWSMachineTemplate{awsMachineTemplate}, - []*mapiv1beta1.MachineSet{mapiMachineSet}, - ) - }) - }) - It("should create an authoritative CAPI Machine when scaling MAPI MachineSet to 1 replicas", func() { By("Scaling up MAPI MachineSet to 1 replicas") - Expect(mapiframework.ScaleMachineSet(mapiMachineSet.GetName(), 1)).To(Succeed(), "should be able to scale up MAPI MachineSet") - capiframework.WaitForMachineSet(cl, mapiMSAuthMAPICAPI, capiframework.CAPINamespace) - verifyMachinesetReplicas(mapiMachineSet, 1) - verifyMachinesetReplicas(capiMachineSet, 1) + Eventually(func() error { + return mapiframework.ScaleMachineSet(mapiMSScaleCAPI.GetName(), 1) + }, capiframework.WaitShort, capiframework.RetryShort).Should(Succeed(), "Should be able to scale up MAPI MachineSet") + capiframework.WaitForMachineSet(cl, mapiMSScaleCAPI.Name, capiframework.CAPINamespace) + verifyMachinesetReplicas(mapiMSScaleCAPI, 1) + verifyMachinesetReplicas(capiMSMirrorScaleCAPI, 1) By("Verifying MAPI Machine is created and .status.authoritativeAPI to equal CAPI") - mapiMachine, err := mapiframework.GetLatestMachineFromMachineSet(ctx, cl, mapiMachineSet) - Expect(err).ToNot(HaveOccurred(), "failed to get MAPI Machines from MachineSet") + var mapiMachine *mapiv1beta1.Machine + var err error + Eventually(func(g Gomega) { + mapiMachine, err = mapiframework.GetLatestMachineFromMachineSet(ctx, cl, mapiMSScaleCAPI) + g.Expect(err).ToNot(HaveOccurred(), "Should have successfully got MAPI Machines from MachineSet") + }, capiframework.WaitMedium, capiframework.RetryMedium).Should(Succeed(), "Should have found latest MAPI Machine from MachineSet") verifyMachineAuthoritative(mapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) verifyMachinePausedCondition(mapiMachine, mapiv1beta1.MachineAuthorityClusterAPI) By("Verifying CAPI Machine is created and Paused condition is False and provisions a running Machine") - capiMachine := capiframework.GetNewestMachineFromMachineSet(cl, capiMachineSet) + capiMachine := capiframework.GetNewestMachineFromMachineSet(cl, capiMSMirrorScaleCAPI) verifyMachineRunning(cl, capiMachine) verifyMachinePausedCondition(capiMachine, mapiv1beta1.MachineAuthorityClusterAPI) }) It("should delete both MAPI and CAPI MachineSets/Machines and InfraMachineTemplate when deleting MAPI MachineSet", func() { - Expect(mapiframework.DeleteMachineSets(cl, mapiMachineSet)).To(Succeed(), "Should be able to delete test MachineSet") - capiframework.WaitForMachineSetsDeleted(cl, capiMachineSet) - mapiframework.WaitForMachineSetsDeleted(ctx, cl, mapiMachineSet) - verifyResourceRemoved(awsMachineTemplate) + Eventually(func() error { + return mapiframework.DeleteMachineSets(cl, mapiMSScaleCAPI) + }, capiframework.WaitShort, capiframework.RetryShort).Should(Succeed(), "Should be able to delete test MachineSet") + capiframework.WaitForMachineSetsDeleted(cl, capiMSMirrorScaleCAPI) + mapiframework.WaitForMachineSetsDeleted(ctx, cl, mapiMSScaleCAPI) + verifyResourceRemoved(awsMachineTemplateScaleCAPI) }) }) }) var _ = Describe("Update MachineSets", Ordered, func() { - var mapiMSAuthMAPIName = "ms-authoritativeapi-mapi" - var mapiMachineSet *mapiv1beta1.MachineSet - var capiMachineSet *clusterv1.MachineSet - var awsMachineTemplate *awsv1.AWSMachineTemplate - var newAWSMachineTemplate *awsv1.AWSMachineTemplate - - BeforeAll(func() { - mapiMachineSet = createMAPIMachineSetWithAuthoritativeAPI(ctx, cl, 0, mapiMSAuthMAPIName, mapiv1beta1.MachineAuthorityMachineAPI, mapiv1beta1.MachineAuthorityMachineAPI) - capiMachineSet, awsMachineTemplate = waitForMAPIMachineSetMirrors(cl, mapiMSAuthMAPIName) - - DeferCleanup(func() { - By("Cleaning up 'Update MachineSet' resources") - cleanupMachineSetTestResources( - ctx, - cl, - []*clusterv1.MachineSet{capiMachineSet}, - []*awsv1.AWSMachineTemplate{awsMachineTemplate, newAWSMachineTemplate}, - []*mapiv1beta1.MachineSet{mapiMachineSet}, - ) - }) + AfterAll(func() { + By("Cleaning up Update test resources") + cleanupMachineSetTestResources( + ctx, + cl, + []*clusterv1.MachineSet{capiMSMirrorUpdate}, + []*awsv1.AWSMachineTemplate{awsMachineTemplateUpdate, newAWSMachineTemplateUpdate}, + []*mapiv1beta1.MachineSet{mapiMSUpdate}, + ) }) Context("when MAPI MachineSet with spec.authoritativeAPI: MachineAPI and replicas 0", Ordered, func() { It("should reject update when attempting scaling of the CAPI MachineSet mirror", func() { By("Scaling up CAPI MachineSet to 1 should be rejected") - capiframework.ScaleCAPIMachineSet(mapiMSAuthMAPIName, 1, capiframework.CAPINamespace) - capiMachineSet = capiframework.GetMachineSet(cl, mapiMSAuthMAPIName, capiframework.CAPINamespace) - verifyMachinesetReplicas(capiMachineSet, 0) + capiframework.ScaleCAPIMachineSet(mapiMSUpdate.Name, 1, capiframework.CAPINamespace) + Eventually(func(g Gomega) { + capiMSMirrorUpdate = capiframework.GetMachineSet(cl, mapiMSUpdate.Name, capiframework.CAPINamespace) + g.Expect(capiMSMirrorUpdate).NotTo(BeNil(), "Should have found CAPI MachineSet") + }, capiframework.WaitShort, capiframework.RetryShort).Should(Succeed(), "Should have found CAPI MachineSet") + verifyMachinesetReplicas(capiMSMirrorUpdate, 0) }) It("should reject update when attempting to change the spec of the CAPI MachineSet mirror", func() { By("Updating CAPI mirror spec (such as Deletion.Order)") - Eventually(k.Update(capiMachineSet, func() { - capiMachineSet.Spec.Deletion = clusterv1.MachineSetDeletionSpec{ + Eventually(k.Update(capiMSMirrorUpdate, func() { + capiMSMirrorUpdate.Spec.Deletion = clusterv1.MachineSetDeletionSpec{ Order: clusterv1.OldestMachineSetDeletionOrder, } - }), capiframework.WaitMedium, capiframework.RetryShort).Should(Succeed(), "Failed to update CAPI MachineSet Deletion.Order") + }), capiframework.WaitMedium, capiframework.RetryShort).Should(Succeed(), "Should have successfully updated CAPI MachineSet Deletion.Order") By("Verifying both MAPI and CAPI MachineSet spec value are restored to original value") - Eventually(k.Object(mapiMachineSet), capiframework.WaitShort, capiframework.RetryShort).Should(HaveField("Spec.DeletePolicy", SatisfyAny(BeEmpty(), Equal("Random"))), "Should have DeletePolicy be either empty or 'Random'") - Eventually(k.Object(capiMachineSet), capiframework.WaitShort, capiframework.RetryShort).Should(HaveField("Spec.Deletion.Order", Equal(clusterv1.RandomMachineSetDeletionOrder)), "Should have Deletion.Order be 'Random'") + Eventually(k.Object(mapiMSUpdate), capiframework.WaitShort, capiframework.RetryShort).Should( + HaveField("Spec.DeletePolicy", SatisfyAny(BeEmpty(), Equal("Random"))), + "Should have DeletePolicy be either empty or 'Random'", + ) + Eventually(k.Object(capiMSMirrorUpdate), capiframework.WaitShort, capiframework.RetryShort).Should( + HaveField("Spec.Deletion.Order", Equal(clusterv1.RandomMachineSetDeletionOrder)), + "Should have Deletion.Order be 'Random'", + ) }) It("should create a new InfraTemplate when update MAPI MachineSet providerSpec", func() { By("Updating MAPI MachineSet providerSpec InstanceType to m5.large") newInstanceType := "m5.large" - updateAWSMachineSetProviderSpec(ctx, cl, mapiMachineSet, func(providerSpec *mapiv1beta1.AWSMachineProviderConfig) { + updateAWSMachineSetProviderSpec(ctx, cl, mapiMSUpdate, func(providerSpec *mapiv1beta1.AWSMachineProviderConfig) { providerSpec.InstanceType = newInstanceType }) By("Waiting for new InfraTemplate to be created") - originalAWSMachineTemplateName := capiMachineSet.Spec.Template.Spec.InfrastructureRef.Name - capiMachineSet = capiframework.GetMachineSet(cl, mapiMSAuthMAPIName, capiframework.CAPINamespace) - Eventually(k.Object(capiMachineSet), capiframework.WaitMedium, capiframework.RetryMedium).Should(HaveField("Spec.Template.Spec.InfrastructureRef.Name", Not(Equal(originalAWSMachineTemplateName))), "Should have InfraTemplate name changed") + originalAWSMachineTemplateName := capiMSMirrorUpdate.Spec.Template.Spec.InfrastructureRef.Name + Eventually(func(g Gomega) { + capiMSMirrorUpdate = capiframework.GetMachineSet(cl, mapiMSUpdate.Name, capiframework.CAPINamespace) + g.Expect(capiMSMirrorUpdate).NotTo(BeNil(), "Should have found CAPI MachineSet") + }, capiframework.WaitShort, capiframework.RetryShort).Should(Succeed(), "Should have refreshed CAPI MachineSet") + Eventually(k.Object(capiMSMirrorUpdate), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Spec.Template.Spec.InfrastructureRef.Name", Not(Equal(originalAWSMachineTemplateName))), + "Should have InfraTemplate name changed", + ) By("Verifying new InfraTemplate has the updated InstanceType") var err error - newAWSMachineTemplate, err = capiframework.GetAWSMachineTemplateByPrefix(cl, mapiMSAuthMAPIName, capiframework.CAPINamespace) - Expect(err).ToNot(HaveOccurred(), "Failed to get new awsMachineTemplate %s", newAWSMachineTemplate) - Expect(newAWSMachineTemplate.Spec.Template.Spec.InstanceType).To(Equal(newInstanceType)) + Eventually(func(g Gomega) { + newAWSMachineTemplateUpdate, err = capiframework.GetAWSMachineTemplateByPrefix(cl, mapiMSUpdate.Name, capiframework.CAPINamespace) + g.Expect(err).ToNot(HaveOccurred(), "Should have successfully got new awsMachineTemplate") + g.Expect(newAWSMachineTemplateUpdate.Spec.Template.Spec.InstanceType).To(Equal(newInstanceType), "Should have new awsMachineTemplate with updated InstanceType") + }, capiframework.WaitMedium, capiframework.RetryMedium).Should(Succeed(), "Should have found new awsMachineTemplate %s", newAWSMachineTemplateUpdate) By("Verifying the old InfraTemplate is deleted") - verifyResourceRemoved(awsMachineTemplate) + verifyResourceRemoved(awsMachineTemplateUpdate) }) }) Context("when switching MAPI MachineSet spec.authoritativeAPI to ClusterAPI", Ordered, func() { BeforeAll(func() { - switchMachineSetAuthoritativeAPI(mapiMachineSet, mapiv1beta1.MachineAuthorityClusterAPI, mapiv1beta1.MachineAuthorityClusterAPI) - verifyMAPIMachineSetSynchronizedCondition(mapiMachineSet, mapiv1beta1.MachineAuthorityClusterAPI) + switchMachineSetAuthoritativeAPI(mapiMSUpdate, mapiv1beta1.MachineAuthorityClusterAPI, mapiv1beta1.MachineAuthorityClusterAPI) + verifyMAPIMachineSetSynchronizedCondition(mapiMSUpdate, mapiv1beta1.MachineAuthorityClusterAPI) }) It("should be rejected when scaling MAPI MachineSet", func() { By("Scaling up MAPI MachineSet to 1") - Expect(mapiframework.ScaleMachineSet(mapiMSAuthMAPIName, 1)).To(Succeed(), "should allow scaling MAPI MachineSet") + Eventually(func() error { + return mapiframework.ScaleMachineSet(mapiMSUpdate.Name, 1) + }, capiframework.WaitShort, capiframework.RetryShort).Should(Succeed(), "Should allow scaling MAPI MachineSet") By("Verifying MAPI MachineSet replicas is restored to original value 0") - verifyMachinesetReplicas(mapiMachineSet, 0) - verifyMachinesetReplicas(capiMachineSet, 0) + verifyMachinesetReplicas(mapiMSUpdate, 0) + verifyMachinesetReplicas(capiMSMirrorUpdate, 0) }) It("should be rejected when when updating providerSpec of MAPI MachineSet", func() { By("Getting the current MAPI MachineSet providerSpec InstanceType") - originalSpec := getAWSProviderSpecFromMachineSet(mapiMachineSet) + originalSpec := getAWSProviderSpecFromMachineSet(mapiMSUpdate) By("Updating the MAPI MachineSet providerSpec InstanceType") - updateAWSMachineSetProviderSpec(ctx, cl, mapiMachineSet, func(providerSpec *mapiv1beta1.AWSMachineProviderConfig) { + updateAWSMachineSetProviderSpec(ctx, cl, mapiMSUpdate, func(providerSpec *mapiv1beta1.AWSMachineProviderConfig) { providerSpec.InstanceType = "m5.xlarge" }) By("Verifying MAPI MachineSet instanceType is restored to original value") - verifyMAPIMachineSetProviderSpec(mapiMachineSet, HaveField("InstanceType", Equal(originalSpec.InstanceType))) + verifyMAPIMachineSetProviderSpec(mapiMSUpdate, HaveField("InstanceType", Equal(originalSpec.InstanceType))) }) It("should update MAPI MachineSet and remove old InfraTemplate when CAPI MachineSet points to new InfraTemplate", func() { By("Creating a new awsMachineTemplate with different spec") newInstanceType := "m6.xlarge" - originalAWSMachineTemplateName := capiMachineSet.Spec.Template.Spec.InfrastructureRef.Name - newAWSMachineTemplate = createAWSMachineTemplate(ctx, cl, originalAWSMachineTemplateName, func(spec *awsv1.AWSMachineSpec) { + originalAWSMachineTemplateName := capiMSMirrorUpdate.Spec.Template.Spec.InfrastructureRef.Name + newAWSMachineTemplateUpdate = createAWSMachineTemplate(ctx, cl, originalAWSMachineTemplateName, func(spec *awsv1.AWSMachineSpec) { spec.InstanceType = newInstanceType }) By("Updating CAPI MachineSet to point to the new InfraTemplate") - updateCAPIMachineSetInfraTemplate(capiMachineSet, newAWSMachineTemplate.Name) + updateCAPIMachineSetInfraTemplate(capiMSMirrorUpdate, newAWSMachineTemplateUpdate.Name) By("Verifying the MAPI MachineSet is updated to reflect the new template") var err error - mapiMachineSet, err = mapiframework.GetMachineSet(ctx, cl, mapiMSAuthMAPIName) - Expect(err).ToNot(HaveOccurred(), "failed to refresh MAPI MachineSet") - Eventually(k.Object(mapiMachineSet), capiframework.WaitMedium, capiframework.RetryMedium).Should( + Eventually(func(g Gomega) { + mapiMSUpdate, err = mapiframework.GetMachineSet(ctx, cl, mapiMSUpdate.Name) + g.Expect(err).ToNot(HaveOccurred(), "Should have successfully refreshed MAPI MachineSet") + }, capiframework.WaitShort, capiframework.RetryShort).Should(Succeed(), "Should have refreshed MAPI MachineSet") + Eventually(k.Object(mapiMSUpdate), capiframework.WaitMedium, capiframework.RetryMedium).Should( HaveField("Spec.Template.Spec.ProviderSpec.Value.Raw", ContainSubstring(newInstanceType)), "Should have MAPI MachineSet providerSpec updated to reflect the new InfraTemplate with InstanceType %s", newInstanceType, ) diff --git a/e2e/migration_common.go b/e2e/migration_common.go index 09edf07dd..3408e1177 100644 --- a/e2e/migration_common.go +++ b/e2e/migration_common.go @@ -1,6 +1,9 @@ package e2e import ( + "fmt" + "time" + mapiv1beta1 "github.com/openshift/api/machine/v1beta1" clusterv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" ) @@ -13,3 +16,9 @@ const ( // CAPIPausedCondition represents the paused state for CAPI machines. CAPIPausedCondition = clusterv1.PausedCondition ) + +// UniqueName generates a unique name with the given prefix using nanosecond timestamp. +// This is useful for creating resources in parallel tests without naming conflicts. +func UniqueName(prefix string) string { + return fmt.Sprintf("%s-%d", prefix, time.Now().UnixNano()) +} diff --git a/e2e/status_conversion_test.go b/e2e/status_conversion_test.go new file mode 100644 index 000000000..b2e07aced --- /dev/null +++ b/e2e/status_conversion_test.go @@ -0,0 +1,895 @@ +package e2e + +import ( + "fmt" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + configv1 "github.com/openshift/api/config/v1" + mapiv1beta1 "github.com/openshift/api/machine/v1beta1" + mapiframework "github.com/openshift/cluster-api-actuator-pkg/pkg/framework" + capiframework "github.com/openshift/cluster-capi-operator/e2e/framework" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/utils/ptr" + awsv1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2" + clusterv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" + "sigs.k8s.io/controller-runtime/pkg/envtest/komega" + "sigs.k8s.io/yaml" +) + +var _ = Describe("[sig-cluster-lifecycle][OCPFeatureGate:MachineAPIMigration] Status Conversion Tests", Ordered, func() { + BeforeAll(func() { + if platform != configv1.AWSPlatformType { + Skip(fmt.Sprintf("Skipping tests on %s, these tests only support AWS", platform)) + } + + if !capiframework.IsMachineAPIMigrationEnabled(ctx, cl) { + Skip("Skipping, this feature is only supported on MachineAPIMigration enabled clusters") + } + }) + + var _ = Describe("MachineSet Status Conversion", Ordered, func() { + var mapiMSAuthMAPI *mapiv1beta1.MachineSet + var mapiMSAuthCAPI *mapiv1beta1.MachineSet + var capiMSMirrorMAPI *clusterv1.MachineSet + var capiMSMirrorCAPI *clusterv1.MachineSet + var awsMachineTemplateMAPI *awsv1.AWSMachineTemplate + var awsMachineTemplateCAPI *awsv1.AWSMachineTemplate + + var mapiMSSameName *mapiv1beta1.MachineSet + var capiMSSameName *clusterv1.MachineSet + var awsMachineTemplateSameName *awsv1.AWSMachineTemplate + + BeforeAll(func() { + By("Creating both MAPI-auth and CAPI-auth MachineSets without waiting (parallel creation)") + mapiMSAuthMAPI = createMAPIMachineSetWithAuthoritativeAPISkipWait( + ctx, cl, 1, + UniqueName("status-mapi-auth-ms"), + mapiv1beta1.MachineAuthorityMachineAPI, + mapiv1beta1.MachineAuthorityMachineAPI, + true, // skipWait=true + ) + mapiMSAuthCAPI = createMAPIMachineSetWithAuthoritativeAPISkipWait( + ctx, cl, 1, + UniqueName("status-capi-auth-ms"), + mapiv1beta1.MachineAuthorityClusterAPI, + mapiv1beta1.MachineAuthorityClusterAPI, + true, // skipWait=true + ) + + By("Creating a same-name MAPI MachineSet with CAPI authority") + sameNameMSName := UniqueName("status-same-name-ms") + capiMSSameName = createCAPIMachineSetSkipWait(ctx, cl, 1, sameNameMSName, "", true) // skipWait=true + mapiMSSameName = createMAPIMachineSetWithAuthoritativeAPISkipWait( + ctx, cl, 1, sameNameMSName, + mapiv1beta1.MachineAuthorityClusterAPI, + mapiv1beta1.MachineAuthorityClusterAPI, + true, // skipWait=true + ) + + By("Waiting for all MachineSets to become ready (parallel waiting)") + waitForMAPIMachineSetReady(ctx, cl, mapiMSAuthMAPI.Name, mapiv1beta1.MachineAuthorityMachineAPI) + waitForMAPIMachineSetReady(ctx, cl, mapiMSAuthCAPI.Name, mapiv1beta1.MachineAuthorityClusterAPI) + capiframework.WaitForMachineSet(cl, capiMSSameName.Name, capiframework.CAPINamespace) + + By("Getting CAPI MachineSet mirrors and AWSMachineTemplates") + capiMSMirrorMAPI, awsMachineTemplateMAPI = waitForMAPIMachineSetMirrors(cl, mapiMSAuthMAPI.Name) + capiMSMirrorCAPI, awsMachineTemplateCAPI = waitForMAPIMachineSetMirrors(cl, mapiMSAuthCAPI.Name) + capiMSSameName, awsMachineTemplateSameName = waitForMAPIMachineSetMirrors(cl, sameNameMSName) + capiframework.WaitForMachineSet(cl, mapiMSAuthCAPI.Name, capiframework.CAPINamespace) + + DeferCleanup(func() { + By("Cleaning up MachineSet Status Conversion test resources") + cleanupMachineSetTestResources( + ctx, cl, + []*clusterv1.MachineSet{capiMSMirrorMAPI, capiMSMirrorCAPI, capiMSSameName}, + []*awsv1.AWSMachineTemplate{awsMachineTemplateMAPI, awsMachineTemplateCAPI, awsMachineTemplateSameName}, + []*mapiv1beta1.MachineSet{mapiMSAuthMAPI, mapiMSAuthCAPI, mapiMSSameName}, + ) + }) + }) + + Context("MAPI to CAPI conversion", func() { + It("should have MAPI MachineSet SynchronizedGeneration set and equal to its Generation", func() { + Eventually(komega.Object(mapiMSAuthMAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.SynchronizedGeneration", Equal(mapiMSAuthMAPI.Generation)), + "MAPI MachineSet SynchronizedGeneration should equal its Generation", + ) + }) + + It("should convert status.replicas from MAPI to CAPI", func() { + Eventually(komega.Object(capiMSMirrorMAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.Replicas", HaveValue(Equal(int32(1)))), + "Should have CAPI MachineSet status.replicas equal to 1", + ) + }) + + It("should convert status.readyReplicas from MAPI to CAPI v1beta2 and v1beta1 deprecated status", func() { + By("Waiting for MAPI MachineSet to have readyReplicas") + Eventually(komega.Object(mapiMSAuthMAPI), capiframework.WaitLong, capiframework.RetryLong).Should( + HaveField("Status.ReadyReplicas", HaveValue(BeNumerically(">", 0))), + "Should have MAPI MachineSet with readyReplicas > 0", + ) + + By("Verifying CAPI MachineSet status.readyReplicas is synchronized") + Eventually(komega.Object(capiMSMirrorMAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.ReadyReplicas", HaveValue(Equal(mapiMSAuthMAPI.Status.ReadyReplicas))), + "Should have CAPI MachineSet status.readyReplicas match MAPI", + ) + + By("Verifying CAPI MachineSet status.Deprecated.V1Beta1.readyReplicas is synchronized") + Eventually(komega.Object(capiMSMirrorMAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.Deprecated.V1Beta1.ReadyReplicas", HaveValue(Equal(mapiMSAuthMAPI.Status.ReadyReplicas))), + "Should have CAPI MachineSet status.Deprecated.V1Beta1.readyReplicas match MAPI", + ) + }) + + It("should convert status.availableReplicas from MAPI to CAPI status and status.Deprecated.V1Beta1", func() { + By("Waiting for MAPI availableReplicas > 0") + Eventually(komega.Object(mapiMSAuthMAPI), capiframework.WaitLong, capiframework.RetryMedium).Should( + HaveField("Status.AvailableReplicas", HaveValue(BeNumerically(">", 0))), + "Should have MAPI MachineSet status.availableReplicas > 0", + ) + By("Verifying CAPI MachineSet status.availableReplicas is synchronized") + Eventually(komega.Object(capiMSMirrorMAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.AvailableReplicas", HaveValue(Equal(mapiMSAuthMAPI.Status.AvailableReplicas))), + "Should have CAPI MachineSet status.availableReplicas match MAPI", + ) + By("Verifying CAPI MachineSet status.Deprecated.V1Beta1.availableReplicas is synchronized") + Eventually(komega.Object(capiMSMirrorMAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.Deprecated.V1Beta1.AvailableReplicas", HaveValue(Equal(mapiMSAuthMAPI.Status.AvailableReplicas))), + "Should have CAPI MachineSet status.Deprecated.V1Beta1.availableReplicas match MAPI", + ) + }) + + It("should convert status.fullyLabeledReplicas from MAPI to CAPI", func() { + By("Waiting for MAPI fullyLabeledReplicas > 0") + Eventually(komega.Object(mapiMSAuthMAPI), capiframework.WaitLong, capiframework.RetryMedium).Should( + HaveField("Status.FullyLabeledReplicas", BeNumerically(">", 0)), + "Should have MAPI MachineSet status.FullyLabeledReplicas > 0", + ) + By("Verifying CAPI MachineSet status.fullyLabeledReplicas is synchronized") + Eventually(komega.Object(capiMSMirrorMAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.Deprecated.V1Beta1.FullyLabeledReplicas", Equal(mapiMSAuthMAPI.Status.FullyLabeledReplicas)), + "Should have CAPI MachineSet Status.Deprecated.V1Beta1.FullyLabeledReplicas match MAPI", + ) + }) + + It("should convert status.ObservedGeneration from MAPI to CAPI", func() { + Eventually(komega.Object(capiMSMirrorMAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.ObservedGeneration", Equal(mapiMSAuthMAPI.Status.ObservedGeneration)), + "Should have CAPI MachineSet status.ObservedGeneration match MAPI", + ) + }) + + It("should have v1beta1 deprecated conditions", func() { + Eventually(komega.Object(capiMSMirrorMAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.Deprecated.V1Beta1.Conditions", SatisfyAll( + ContainElement(SatisfyAll( + HaveField("Type", Equal(clusterv1.ReadyV1Beta1Condition)), + HaveField("Status", Equal(corev1.ConditionTrue)), + )), + ContainElement(SatisfyAll( + HaveField("Type", Equal(clusterv1.MachinesReadyV1Beta1Condition)), + HaveField("Status", Equal(corev1.ConditionTrue)), + )), + ContainElement(SatisfyAll( + HaveField("Type", Equal(clusterv1.MachinesCreatedV1Beta1Condition)), + HaveField("Status", Equal(corev1.ConditionTrue)), + )), + ContainElement(SatisfyAll( + HaveField("Type", Equal(clusterv1.ResizedV1Beta1Condition)), + HaveField("Status", Equal(corev1.ConditionTrue)), + )), + )), + "Should have correct CAPI MachineSet v1beta1 deprecated conditions", + ) + }) + + // Note: When MachineSet has authoritativeAPI=MachineAPI, it gets paused (cluster.x-k8s.io/paused annotation). + // CAPI clears all v1beta2 conditions for paused MachineSets, keeping only the Paused condition. + // Therefore, we only verify the Paused condition. + It("should have CAPI MachineSet v1beta2 Paused condition when authoritativeAPI is MachineAPI", func() { + Eventually(komega.Object(capiMSMirrorMAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.Conditions", ContainElement(SatisfyAll( + HaveField("Type", Equal(clusterv1.PausedCondition)), + HaveField("Status", Equal(metav1.ConditionTrue)), + HaveField("Reason", Equal(clusterv1.PausedReason)), + ))), + "Should have CAPI MachineSet Paused condition", + ) + }) + + It("should NOT have Synchronized condition in CAPI MachineSet", func() { + By("Verifying MAPI MachineSet has Synchronized condition") + Eventually(komega.Object(mapiMSAuthMAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.Conditions", ContainElement(HaveField("Type", Equal(SynchronizedCondition)))), + "Should have MAPI MachineSet with Synchronized condition", + ) + By("Verifying CAPI MachineSet does NOT have Synchronized condition in v1beta2 conditions") + Consistently(komega.Object(capiMSMirrorMAPI), capiframework.WaitShort, capiframework.RetryShort).Should( + HaveField("Status.Conditions", Not(ContainElement(HaveField("Type", Equal("Synchronized"))))), + "Should NOT have Synchronized condition in CAPI MachineSet v1beta2 conditions", + ) + }) + + It("should convert spec.selector to CAPI MachineSet status.selector", func() { + By("Converting MAPI selector.matchLabels to label selector string") + expectedSelector := labels.SelectorFromSet(mapiMSAuthMAPI.Spec.Selector.MatchLabels).String() + + By("Verifying CAPI MachineSet status.selector matches MAPI selector") + Eventually(komega.Object(capiMSMirrorMAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.Selector", Equal(expectedSelector)), + "Should have CAPI MachineSet status.selector match MAPI selector", + ) + }) + }) + + Context("CAPI to MAPI conversion", func() { + It("should have MAPI MachineSet SynchronizedGeneration set and equal to CAPI MachineSet Generation", func() { + Eventually(komega.Object(mapiMSAuthCAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.SynchronizedGeneration", Equal(capiMSMirrorCAPI.Generation)), + "MAPI MachineSet SynchronizedGeneration should equal CAPI MachineSet Generation (CAPI authoritative)", + ) + }) + + It("should convert status.replicas from CAPI to MAPI", func() { + Eventually(komega.Object(mapiMSAuthCAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.Replicas", Equal(ptr.Deref(capiMSMirrorCAPI.Status.Replicas, 0))), + "Should have MAPI MachineSet status.replicas match CAPI", + ) + }) + + It("should convert status.readyReplicas from CAPI to MAPI", func() { + By("Waiting for CAPI readyReplicas > 0") + Eventually(komega.Object(capiMSMirrorCAPI), capiframework.WaitLong, capiframework.RetryLong).Should( + HaveField("Status.ReadyReplicas", HaveValue(BeNumerically(">", 0))), + "Should have CAPI MachineSet with readyReplicas > 0", + ) + + By("Verifying MAPI MachineSet status.readyReplicas is synchronized") + Eventually(komega.Object(mapiMSAuthCAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.ReadyReplicas", Equal(ptr.Deref(capiMSMirrorCAPI.Status.ReadyReplicas, 0))), + "Should have MAPI MachineSet status.readyReplicas match CAPI", + ) + }) + + It("should convert status.availableReplicas from CAPI to MAPI", func() { + By("Waiting for CAPI availableReplicas > 0") + Eventually(komega.Object(capiMSMirrorCAPI), capiframework.WaitLong, capiframework.RetryMedium).Should( + HaveField("Status.AvailableReplicas", HaveValue(BeNumerically(">", 0))), + "Should have CAPI MachineSet with availableReplicas > 0", + ) + + By("Verifying MAPI MachineSet status.availableReplicas is synchronized") + Eventually(komega.Object(mapiMSAuthCAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.AvailableReplicas", Equal(ptr.Deref(capiMSMirrorCAPI.Status.AvailableReplicas, 0))), + "Should have MAPI MachineSet status.availableReplicas match CAPI", + ) + }) + + It("should convert status.fullyLabeledReplicas from CAPI to MAPI", func() { + By("Waiting for CAPI fullyLabeledReplicas > 0") + Eventually(komega.Object(capiMSMirrorCAPI), capiframework.WaitLong, capiframework.RetryMedium).Should( + HaveField("Status.Deprecated.V1Beta1.FullyLabeledReplicas", BeNumerically(">", 0)), + "Should have CAPI MachineSet with fullyLabeledReplicas > 0", + ) + + By("Verifying MAPI MachineSet status.fullyLabeledReplicas is synchronized") + Eventually(komega.Object(mapiMSAuthCAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.FullyLabeledReplicas", Equal(capiMSMirrorCAPI.Status.Deprecated.V1Beta1.FullyLabeledReplicas)), + "Should have MAPI MachineSet status.fullyLabeledReplicas match CAPI", + ) + }) + + It("should convert status.ObservedGeneration from CAPI to MAPI", func() { + Eventually(komega.Object(mapiMSAuthCAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.ObservedGeneration", Equal(capiMSMirrorCAPI.Status.ObservedGeneration)), + "Should have MAPI MachineSet status.ObservedGeneration match CAPI", + ) + }) + + It("should have MAPI MachineSet Synchronized condition", func() { + Eventually(komega.Object(mapiMSAuthCAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.Conditions", ContainElement(SatisfyAll( + HaveField("Type", Equal(SynchronizedCondition)), + HaveField("Status", Equal(corev1.ConditionTrue)), + ))), + "Should have MAPI MachineSet with Synchronized condition", + ) + }) + + It("should NOT have CAPI-specific conditions", func() { + Consistently(komega.Object(mapiMSAuthCAPI), capiframework.WaitShort, capiframework.RetryShort).Should( + SatisfyAll( + HaveField("Status.Conditions", Not(ContainElement(HaveField("Type", Equal(clusterv1.ReadyCondition))))), + HaveField("Status.Conditions", Not(ContainElement(HaveField("Type", Equal(clusterv1.MachinesReadyV1Beta1Condition))))), + HaveField("Status.Conditions", Not(ContainElement(HaveField("Type", Equal(clusterv1.ResizedV1Beta1Condition))))), + HaveField("Status.Conditions", Not(ContainElement(HaveField("Type", Equal(clusterv1.MachinesCreatedV1Beta1Condition))))), + ), + "Should NOT have CAPI-specific conditions in MAPI MachineSet", + ) + }) + }) + + Context("when CAPI MachineSet exists and MAPI MachineSet with CAPI authority is created with same name", func() { + It("should have MAPI MachineSet SynchronizedGeneration set and equal to CAPI MachineSet Generation", func() { + Eventually(komega.Object(mapiMSSameName), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.SynchronizedGeneration", Equal(capiMSSameName.Generation)), + "MAPI MachineSet SynchronizedGeneration should equal CAPI MachineSet Generation", + ) + }) + + It("should convert status.replicas from CAPI to MAPI", func() { + By("Waiting for CAPI MachineSet to have replicas > 0") + Eventually(komega.Object(capiMSSameName), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.Replicas", HaveValue(BeNumerically(">", 0))), + "Should have CAPI MachineSet status.replicas > 0", + ) + + By("Verifying MAPI MachineSet status.replicas is synchronized") + Eventually(komega.Object(mapiMSSameName), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.Replicas", Equal(ptr.Deref(capiMSSameName.Status.Replicas, 0))), + "Should have MAPI MachineSet status.replicas match CAPI", + ) + }) + + It("should convert status.readyReplicas from CAPI to MAPI", func() { + By("Waiting for CAPI readyReplicas > 0") + Eventually(komega.Object(capiMSSameName), capiframework.WaitLong, capiframework.RetryLong).Should( + HaveField("Status.ReadyReplicas", HaveValue(BeNumerically(">", 0))), + "Should have CAPI MachineSet with readyReplicas > 0", + ) + + By("Verifying MAPI MachineSet status.readyReplicas is synchronized") + Eventually(komega.Object(mapiMSSameName), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.ReadyReplicas", Equal(ptr.Deref(capiMSSameName.Status.ReadyReplicas, 0))), + "Should have MAPI MachineSet status.readyReplicas match CAPI", + ) + }) + + It("should convert status.availableReplicas from CAPI to MAPI", func() { + By("Waiting for CAPI availableReplicas > 0") + Eventually(komega.Object(capiMSSameName), capiframework.WaitLong, capiframework.RetryMedium).Should( + HaveField("Status.AvailableReplicas", HaveValue(BeNumerically(">", 0))), + "Should have CAPI MachineSet with availableReplicas > 0", + ) + + By("Verifying MAPI MachineSet status.AvailableReplicas is synchronized") + Eventually(komega.Object(mapiMSSameName), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.AvailableReplicas", Equal(ptr.Deref(capiMSSameName.Status.AvailableReplicas, 0))), + "Should have MAPI MachineSet status.availableReplicas match CAPI", + ) + }) + + It("should convert status.fullyLabeledReplicas from CAPI to MAPI", func() { + By("Waiting for CAPI fullyLabeledReplicas > 0") + Eventually(komega.Object(capiMSSameName), capiframework.WaitLong, capiframework.RetryMedium).Should( + HaveField("Status.Deprecated.V1Beta1.FullyLabeledReplicas", BeNumerically(">", 0)), + "Should have CAPI MachineSet with fullyLabeledReplicas > 0", + ) + + By("Verifying MAPI MachineSet status.FullyLabeledReplicas is synchronized") + Eventually(komega.Object(mapiMSSameName), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.FullyLabeledReplicas", Equal(capiMSSameName.Status.Deprecated.V1Beta1.FullyLabeledReplicas)), + "Should have MAPI MachineSet status.fullyLabeledReplicas match CAPI", + ) + }) + + It("should convert status.ObservedGeneration from CAPI to MAPI", func() { + Eventually(komega.Object(mapiMSSameName), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.ObservedGeneration", Equal(capiMSSameName.Status.ObservedGeneration)), + "Should have MAPI MachineSet status.ObservedGeneration match CAPI", + ) + }) + + It("should have MAPI MachineSet Synchronized condition", func() { + Eventually(komega.Object(mapiMSSameName), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.Conditions", ContainElement(SatisfyAll( + HaveField("Type", Equal(SynchronizedCondition)), + HaveField("Status", Equal(corev1.ConditionTrue)), + ))), + "Should have MAPI MachineSet with Synchronized condition", + ) + }) + + It("should NOT have CAPI-specific conditions in MAPI MachineSet", func() { + Consistently(komega.Object(mapiMSSameName), capiframework.WaitShort, capiframework.RetryShort).Should( + SatisfyAll( + HaveField("Status.Conditions", Not(ContainElement(HaveField("Type", Equal(clusterv1.ReadyCondition))))), + HaveField("Status.Conditions", Not(ContainElement(HaveField("Type", Equal(clusterv1.MachinesReadyV1Beta1Condition))))), + HaveField("Status.Conditions", Not(ContainElement(HaveField("Type", Equal(clusterv1.ResizedV1Beta1Condition))))), + HaveField("Status.Conditions", Not(ContainElement(HaveField("Type", Equal(clusterv1.MachinesCreatedV1Beta1Condition))))), + ), + "Should NOT have CAPI-specific conditions in MAPI MachineSet", + ) + }) + }) + }) + + var _ = Describe("Machine Status Conversion", Ordered, func() { + var mapiMachineAuthMAPI *mapiv1beta1.Machine + var mapiMachineAuthCAPI *mapiv1beta1.Machine + var capiMachineMirrorMAPI *clusterv1.Machine + var capiMachineMirrorCAPI *clusterv1.Machine + + var errorMachineSet *mapiv1beta1.MachineSet + var errorCAPIMachineSet *clusterv1.MachineSet + var errorAWSMachineTemplate *awsv1.AWSMachineTemplate + var errorMachine *mapiv1beta1.Machine + var errorCAPIMachine *clusterv1.Machine + + var capiMachineSameName *clusterv1.Machine + var mapiMachineSameName *mapiv1beta1.Machine + var err error + + BeforeAll(func() { + By("Creating all Machines without waiting for them to be ready") + mapiMachineAuthMAPI = createMAPIMachineWithAuthority( + ctx, cl, + UniqueName("status-mapi-machine"), + mapiv1beta1.MachineAuthorityMachineAPI, + ) + mapiMachineAuthCAPI = createMAPIMachineWithAuthority( + ctx, cl, + UniqueName("status-capi-machine"), + mapiv1beta1.MachineAuthorityClusterAPI, + ) + + By("Creating error MachineSet with invalid instanceType (skipWait)") + errorMachineSet = createMAPIMachineSetWithAuthoritativeAPISkipWait( + ctx, cl, 0, + UniqueName("status-error"), + mapiv1beta1.MachineAuthorityMachineAPI, + mapiv1beta1.MachineAuthorityMachineAPI, + true, // skipWait=true + ) + + By("Setting invalid instanceType to trigger error") + updateAWSMachineSetProviderSpec(ctx, cl, errorMachineSet, func(providerSpec *mapiv1beta1.AWSMachineProviderConfig) { + providerSpec.InstanceType = "invalid" + }) + + By("Waiting for error MachineSet to be ready before scaling") + waitForMAPIMachineSetReady(ctx, cl, errorMachineSet.Name, mapiv1beta1.MachineAuthorityMachineAPI) + + By("Scaling error MachineSet to 1 and waiting for Machine creation") + mapiframework.ScaleMachineSet(errorMachineSet.Name, 1) + + Eventually(func() ([]*mapiv1beta1.Machine, error) { + return mapiframework.GetMachinesFromMachineSet(ctx, cl, errorMachineSet) + }, capiframework.WaitShort, capiframework.RetryShort).Should( + And(Not(BeEmpty()), HaveLen(1)), + "Should have exactly one error Machine created", + ) + + errorMachine, err = mapiframework.GetLatestMachineFromMachineSet(ctx, cl, errorMachineSet) + Expect(err).ToNot(HaveOccurred(), "Should get error Machine from MachineSet") + Expect(errorMachine).ToNot(BeNil(), "Error Machine should not be nil") + errorCAPIMachine = capiframework.GetMachine(cl, errorMachine.Name, capiframework.CAPINamespace) + + By("Creating same-name scenario: CAPI Machine first, then MAPI Machine") + sameNameMachineName := UniqueName("status-same-name-machine") + capiMachineSameName = createCAPIMachine(ctx, cl, sameNameMachineName) + mapiMachineSameName = createMAPIMachineWithAuthority(ctx, cl, sameNameMachineName, mapiv1beta1.MachineAuthorityClusterAPI) + + By("Waiting for all normal Machines to be running (parallel waiting)") + verifyMachineRunning(cl, mapiMachineAuthMAPI) + verifyMachineRunning(cl, mapiMachineAuthCAPI) + + By("Getting CAPI Machine mirrors") + capiMachineMirrorMAPI = capiframework.GetMachine(cl, mapiMachineAuthMAPI.Name, capiframework.CAPINamespace) + capiMachineMirrorCAPI = capiframework.GetMachine(cl, mapiMachineAuthCAPI.Name, capiframework.CAPINamespace) + errorCAPIMachineSet, errorAWSMachineTemplate = waitForMAPIMachineSetMirrors(cl, errorMachineSet.Name) + + DeferCleanup(func() { + By("Cleaning up Machine Status Conversion test resources") + cleanupMachineSetTestResources(ctx, cl, + []*clusterv1.MachineSet{errorCAPIMachineSet}, + []*awsv1.AWSMachineTemplate{errorAWSMachineTemplate}, + []*mapiv1beta1.MachineSet{errorMachineSet}, + ) + cleanupMachineResources(ctx, cl, + []*clusterv1.Machine{capiMachineMirrorCAPI, capiMachineSameName}, + []*mapiv1beta1.Machine{mapiMachineAuthMAPI, mapiMachineAuthCAPI, mapiMachineSameName}, + ) + }) + }) + + Context("MAPI to CAPI conversion", func() { + It("should have MAPI Machine SynchronizedGeneration set and equal to its Generation", func() { + mapiMachineAuthMAPI, err = mapiframework.GetMachine(cl, mapiMachineAuthMAPI.Name) + Expect(err).ToNot(HaveOccurred()) + Eventually(komega.Object(mapiMachineAuthMAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.SynchronizedGeneration", Equal(mapiMachineAuthMAPI.Generation)), + "Should have SynchronizedGeneration equal to Generation", + ) + }) + + It("should convert MAPI Machine phase to CAPI Machine phase", func() { + Eventually(komega.Object(capiMachineMirrorMAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.Phase", Equal(ptr.Deref(mapiMachineAuthMAPI.Status.Phase, ""))), + "Should have CAPI Machine phase match MAPI Machine phase", + ) + }) + + It("should convert MAPI Machine nodeRef to CAPI Machine nodeRef", func() { + By("Waiting for MAPI Machine to have nodeRef") + Eventually(komega.Object(mapiMachineAuthMAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.NodeRef", Not(BeNil())), + "Should have MAPI nodeRef not nil", + ) + + By("Verifying CAPI Machine nodeRef matches MAPI Machine nodeRef") + // Note: CAPI v1beta2 MachineNodeReference only has Name field, not Kind + Eventually(komega.Object(capiMachineMirrorMAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.NodeRef.Name", Equal(mapiMachineAuthMAPI.Status.NodeRef.Name)), + "Should have CAPI Machine nodeRef Name match MAPI Machine nodeRef", + ) + }) + + It("should convert MAPI Machine lastUpdated to CAPI Machine lastUpdated", func() { + By("Waiting for MAPI Machine to have lastUpdated") + Eventually(komega.Object(mapiMachineAuthMAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.LastUpdated", Not(BeNil())), + "Should have MAPI Machine with lastUpdated", + ) + + By("Verifying CAPI Machine lastUpdated matches MAPI Machine lastUpdated") + Eventually(komega.Object(capiMachineMirrorMAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.LastUpdated", Equal(*mapiMachineAuthMAPI.Status.LastUpdated)), + "Should have CAPI Machine lastUpdated match MAPI Machine lastUpdated", + ) + }) + + It("should convert MAPI Machine addresses to CAPI Machine addresses", func() { + Eventually(komega.Object(mapiMachineAuthMAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.Addresses", Not(BeEmpty())), + "Should have MAPI addresses not empty", + ) + + expectedMatchers := make([]interface{}, len(mapiMachineAuthMAPI.Status.Addresses)) + for i, addr := range mapiMachineAuthMAPI.Status.Addresses { + expectedMatchers[i] = SatisfyAll( + HaveField("Type", Equal(clusterv1.MachineAddressType(addr.Type))), + HaveField("Address", Equal(addr.Address)), + ) + } + Eventually(komega.Object(capiMachineMirrorMAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.Addresses", ConsistOf(expectedMatchers...)), + "Should have CAPI Machine addresses match MAPI Machine addresses", + ) + }) + + It("should convert MAPI Machine conditions to CAPI Machine v1beta1 deprecated conditions", func() { + By("Waiting for MAPI Machine to have conditions") + Eventually(komega.Object(mapiMachineAuthMAPI), capiframework.WaitShort, capiframework.RetryShort).Should( + HaveField("Status.Conditions", Not(BeEmpty())), + "Should have MAPI conditions not empty", + ) + + By("Verifying CAPI Machine has v1beta1 deprecated conditions set") + Eventually(komega.Object(capiMachineMirrorMAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + SatisfyAll( + HaveField("Status.Deprecated.V1Beta1.Conditions", ContainElement(SatisfyAll( + HaveField("Type", Equal(clusterv1.ReadyV1Beta1Condition)), + HaveField("Status", Equal(corev1.ConditionTrue)), + ))), + HaveField("Status.Deprecated.V1Beta1.Conditions", ContainElement(SatisfyAll( + HaveField("Type", Equal(clusterv1.BootstrapReadyV1Beta1Condition)), + HaveField("Status", Equal(corev1.ConditionTrue)), + ))), + HaveField("Status.Deprecated.V1Beta1.Conditions", ContainElement(SatisfyAll( + HaveField("Type", Equal(clusterv1.InfrastructureReadyV1Beta1Condition)), + HaveField("Status", Equal(corev1.ConditionTrue)), + ))), + ), + "Should have CAPI Machine v1beta1 deprecated conditions set", + ) + }) + + It("should convert MAPI Machine conditions to CAPI Machine v1beta2 conditions", func() { + Eventually(komega.Object(capiMachineMirrorMAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + SatisfyAll( + HaveField("Status.Conditions", ContainElement(SatisfyAll( + HaveField("Type", Equal(clusterv1.MachineAvailableCondition)), + HaveField("Status", Equal(metav1.ConditionTrue)), + ))), + HaveField("Status.Conditions", ContainElement(SatisfyAll( + HaveField("Type", Equal(clusterv1.MachineReadyCondition)), + HaveField("Status", Equal(metav1.ConditionTrue)), + ))), + HaveField("Status.Conditions", ContainElement(SatisfyAll( + HaveField("Type", Equal(clusterv1.MachineBootstrapConfigReadyCondition)), + HaveField("Status", Equal(metav1.ConditionTrue)), + ))), + HaveField("Status.Conditions", ContainElement(SatisfyAll( + HaveField("Type", Equal(clusterv1.MachineInfrastructureReadyCondition)), + HaveField("Status", Equal(metav1.ConditionTrue)), + ))), + HaveField("Status.Conditions", ContainElement(SatisfyAll( + HaveField("Type", Equal(clusterv1.MachineNodeReadyCondition)), + HaveField("Status", Equal(metav1.ConditionTrue)), + ))), + HaveField("Status.Conditions", ContainElement(SatisfyAll( + HaveField("Type", Equal(clusterv1.MachineDeletingCondition)), + HaveField("Status", Equal(metav1.ConditionFalse)), + ))), + ), + "Should have CAPI Machine v1beta2 conditions set", + ) + }) + + It("should NOT have MAPI Synchronized condition in CAPI Machine", func() { + By("Verifying MAPI Machine has Synchronized condition") + Eventually(komega.Object(mapiMachineAuthMAPI), capiframework.WaitShort, capiframework.RetryShort).Should( + HaveField("Status.Conditions", ContainElement(HaveField("Type", Equal(SynchronizedCondition)))), + "Should have MAPI Machine with Synchronized condition", + ) + By("Verifying CAPI Machine does NOT have Synchronized condition in v1beta2 conditions") + Consistently(komega.Object(capiMachineMirrorMAPI), capiframework.WaitShort, capiframework.RetryShort).Should( + HaveField("Status.Conditions", Not(ContainElement(HaveField("Type", Equal("Synchronized"))))), + "Should NOT have Synchronized condition in CAPI Machine v1beta2 conditions", + ) + }) + + It("should convert MAPI Machine providerStatus to CAPI AWSMachine status", func() { + By("Getting AWSMachine for the CAPI Machine") + awsMachine := capiframework.GetAWSMachine(cl, capiMachineMirrorMAPI.Name, capiframework.CAPINamespace) + Expect(awsMachine).NotTo(BeNil(), "AWSMachine should exist") + + By("Verifying AWSMachine status.ready is set based on MAPI Machine providerStatus.instanceState") + Eventually(komega.Object(awsMachine), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.Ready", BeTrue()), + "Should have AWSMachine status.ready be true when instance is running", + ) + + By("Verifying AWSMachine status.instanceState matches MAPI Machine providerStatus.instanceState") + var mapiProviderStatus mapiv1beta1.AWSMachineProviderStatus + err := yaml.Unmarshal(mapiMachineAuthMAPI.Status.ProviderStatus.Raw, &mapiProviderStatus) + Expect(err).ToNot(HaveOccurred()) + + Eventually(komega.Object(awsMachine), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.InstanceState", HaveValue(Equal(awsv1.InstanceState(ptr.Deref(mapiProviderStatus.InstanceState, ""))))), + "Should have AWSMachine status.instanceState match MAPI providerStatus.instanceState", + ) + }) + }) + + Context("CAPI to MAPI conversion", func() { + It("should have MAPI Machine SynchronizedGeneration set and equal to CAPI Machine Generation", func() { + mapiMachineAuthCAPI, err = mapiframework.GetMachine(cl, mapiMachineAuthCAPI.Name) + Expect(err).ToNot(HaveOccurred()) + capiMachineMirrorCAPI = capiframework.GetMachine(cl, mapiMachineAuthCAPI.Name, capiframework.CAPINamespace) + + Eventually(komega.Object(mapiMachineAuthCAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.SynchronizedGeneration", Equal(capiMachineMirrorCAPI.Generation)), + "Should have MAPI Machine SynchronizedGeneration equal to CAPI Generation", + ) + }) + + It("should convert CAPI Machine phase to MAPI Machine phase", func() { + Eventually(komega.Object(mapiMachineAuthCAPI), capiframework.WaitShort, capiframework.RetryShort).Should( + HaveField("Status.Phase", HaveValue(Equal(capiMachineMirrorCAPI.Status.Phase))), + "Should have MAPI Machine phase match CAPI Machine phase", + ) + }) + + It("should convert CAPI Machine nodeRef to MAPI Machine nodeRef", func() { + By("Waiting for CAPI Machine to have nodeRef") + Eventually(komega.Object(capiMachineMirrorCAPI), capiframework.WaitLong, capiframework.RetryShort).Should( + HaveField("Status.NodeRef", Not(BeNil())), + "Should have CAPI nodeRef not nil", + ) + + By("Verifying MAPI Machine nodeRef matches CAPI Machine nodeRef") + Eventually(komega.Object(mapiMachineAuthCAPI), capiframework.WaitShort, capiframework.RetryShort).Should( + HaveField("Status.NodeRef.Name", Equal(capiMachineMirrorCAPI.Status.NodeRef.Name)), + "Should have MAPI Machine nodeRef match CAPI Machine nodeRef", + ) + }) + + It("should convert CAPI Machine lastUpdated to MAPI Machine lastUpdated", func() { + By("Waiting for CAPI Machine to have lastUpdated") + Eventually(komega.Object(capiMachineMirrorCAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.LastUpdated", Not(BeZero())), + "Should have CAPI Machine with lastUpdated set", + ) + + By("Verifying MAPI Machine lastUpdated matches CAPI Machine lastUpdated") + Eventually(komega.Object(mapiMachineAuthCAPI), capiframework.WaitShort, capiframework.RetryShort).Should( + HaveField("Status.LastUpdated", HaveValue(Equal(capiMachineMirrorCAPI.Status.LastUpdated))), + "Should have MAPI Machine lastUpdated match CAPI Machine lastUpdated", + ) + }) + + It("should convert CAPI Machine addresses to MAPI Machine addresses", func() { + By("Waiting for CAPI Machine to have addresses") + capiMachineMirrorCAPI = capiframework.GetMachine(cl, capiMachineMirrorCAPI.Name, capiframework.CAPINamespace) + Eventually(komega.Object(capiMachineMirrorCAPI), capiframework.WaitShort, capiframework.RetryShort).Should( + HaveField("Status.Addresses", Not(BeEmpty())), + "Should have CAPI addresses not empty", + ) + + By("Verifying MAPI Machine has matching addresses from CAPI") + expectedMatchers := make([]interface{}, len(capiMachineMirrorCAPI.Status.Addresses)) + for i, addr := range capiMachineMirrorCAPI.Status.Addresses { + expectedMatchers[i] = SatisfyAll( + HaveField("Type", Equal(corev1.NodeAddressType(addr.Type))), + HaveField("Address", Equal(addr.Address)), + ) + } + Eventually(komega.Object(mapiMachineAuthCAPI), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.Addresses", ConsistOf(expectedMatchers...)), + "Should have MAPI Machine addresses match CAPI Machine addresses", + ) + }) + + It("should NOT have CAPI-specific conditions in MAPI Machine", func() { + Consistently(komega.Object(mapiMachineAuthCAPI), capiframework.WaitShort, capiframework.RetryShort).Should( + SatisfyAll( + HaveField("Status.Conditions", Not(ContainElement(HaveField("Type", Equal(clusterv1.ReadyCondition))))), + HaveField("Status.Conditions", Not(ContainElement(HaveField("Type", Equal(clusterv1.MachinesReadyV1Beta1Condition))))), + HaveField("Status.Conditions", Not(ContainElement(HaveField("Type", Equal(clusterv1.ResizedV1Beta1Condition))))), + HaveField("Status.Conditions", Not(ContainElement(HaveField("Type", Equal(clusterv1.MachinesCreatedV1Beta1Condition))))), + ), + "Should NOT have CAPI-specific conditions in MAPI Machine", + ) + }) + + // bug https://issues.redhat.com/browse/OCPBUGS-70136 + PIt("should convert CAPI AWSMachine status to MAPI providerStatus", func() { + By("Getting AWSMachine for the CAPI Machine") + awsMachine := capiframework.GetAWSMachine(cl, capiMachineMirrorCAPI.Name, capiframework.CAPINamespace) + Expect(awsMachine).NotTo(BeNil(), "AWSMachine should exist") + + By("Waiting for AWSMachine to have instanceState set") + Eventually(komega.Object(awsMachine), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.InstanceState", Not(BeNil())), + "Should have AWSMachine InstanceState not nil", + ) + + verifyMAPIMachineProviderStatus(mapiMachineAuthCAPI, + HaveField("InstanceState", HaveValue(Equal(ptr.Deref(awsMachine.Status.InstanceState, "")))), + ) + + verifyMAPIMachineProviderStatus(mapiMachineAuthCAPI, + WithTransform(func(status *mapiv1beta1.AWSMachineProviderStatus) bool { + for _, cond := range status.Conditions { + if cond.Type == string(mapiv1beta1.MachineCreation) { + return cond.Status == metav1.ConditionTrue + } + } + return false + }, BeTrue()), + ) + }) + }) + + Context("Error status conversion", func() { + It("should convert error status to CAPI failureReason and failureMessage", func() { + By("Waiting for MAPI Machine error status") + Eventually(komega.Object(errorMachine), capiframework.WaitLong, capiframework.RetryLong).Should( + SatisfyAny( + HaveField("Status.ErrorReason", Not(BeNil())), + HaveField("Status.ErrorMessage", Not(BeNil())), + ), + "Should have error status in MAPI Machine", + ) + + if errorMachine.Status.ErrorReason != nil { + Eventually(komega.Object(errorCAPIMachine), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.Deprecated.V1Beta1.FailureReason", HaveValue(BeEquivalentTo(*errorMachine.Status.ErrorReason))), + "Should have failureReason converted from MAPI to CAPI", + ) + } + + if errorMachine.Status.ErrorMessage != nil { + Eventually(komega.Object(errorCAPIMachine), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.Deprecated.V1Beta1.FailureMessage", HaveValue(Equal(*errorMachine.Status.ErrorMessage))), + "Should have failureMessage converted from MAPI to CAPI", + ) + } + }) + + It("should convert Failed phase", func() { + Eventually(komega.Object(errorMachine), capiframework.WaitLong, capiframework.RetryLong).Should( + HaveField("Status.Phase", HaveValue(Equal("Failed"))), + "Should have Failed phase in MAPI Machine", + ) + Eventually(komega.Object(errorCAPIMachine), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.Phase", Equal("Failed")), + "Should have Failed phase converted from MAPI to CAPI", + ) + }) + }) + + Context("when CAPI Machine exists and MAPI Machine with CAPI authority is created with same name", func() { + It("should have MAPI Machine SynchronizedGeneration set and equal to CAPI Machine Generation same-name scenario", func() { + mapiMachineSameName, err = mapiframework.GetMachine(cl, mapiMachineSameName.Name) + Expect(err).ToNot(HaveOccurred()) + capiMachineSameName = capiframework.GetMachine(cl, mapiMachineSameName.Name, capiframework.CAPINamespace) + + Eventually(komega.Object(mapiMachineSameName), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.SynchronizedGeneration", Equal(capiMachineSameName.Generation)), + "Should have SynchronizedGeneration equal to CAPI Generation", + ) + }) + + // bug https://issues.redhat.com/browse/OCPBUGS-63183 + PIt("should convert CAPI Machine phase to MAPI Machine phase", func() { + Eventually(komega.Object(mapiMachineSameName), capiframework.WaitShort, capiframework.RetryShort).Should( + HaveField("Status.Phase", HaveValue(Equal(capiMachineSameName.Status.Phase))), + "Should have phase converted from CAPI to MAPI", + ) + }) + + It("should convert CAPI Machine nodeRef to MAPI Machine nodeRef", func() { + By("Waiting for CAPI nodeRef") + Eventually(komega.Object(capiMachineSameName), capiframework.WaitLong, capiframework.RetryShort).Should( + HaveField("Status.NodeRef", Not(BeNil())), + "Should have CAPI nodeRef not nil", + ) + + By("Verifying MAPI Machine has matching nodeRef from CAPI") + Eventually(komega.Object(mapiMachineSameName), capiframework.WaitShort, capiframework.RetryShort).Should( + HaveField("Status.NodeRef.Name", Equal(capiMachineSameName.Status.NodeRef.Name)), + "Should have nodeRef.Name converted from CAPI to MAPI", + ) + }) + + // bug https://issues.redhat.com/browse/OCPBUGS-63183 + PIt("should convert CAPI Machine lastUpdated to MAPI Machine lastUpdated", func() { + By("Waiting for CAPI Machine to have lastUpdated") + Eventually(komega.Object(capiMachineSameName), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.LastUpdated", Not(BeZero())), + "Should have CAPI Machine with lastUpdated set", + ) + + By("Verifying MAPI Machine lastUpdated matches CAPI Machine lastUpdated") + Eventually(komega.Object(mapiMachineSameName), capiframework.WaitShort, capiframework.RetryShort).Should( + HaveField("Status.LastUpdated", HaveValue(Equal(capiMachineSameName.Status.LastUpdated))), + "Should have lastUpdated converted from CAPI to MAPI", + ) + }) + + // bug https://issues.redhat.com/browse/OCPBUGS-63183 + PIt("should convert CAPI Machine addresses to MAPI Machine addresses", func() { + By("Waiting for CAPI Machine to have addresses") + capiMachineSameName = capiframework.GetMachine(cl, capiMachineSameName.Name, capiframework.CAPINamespace) + Eventually(komega.Object(capiMachineSameName), capiframework.WaitShort, capiframework.RetryShort).Should( + HaveField("Status.Addresses", Not(BeEmpty())), + "Should have CAPI addresses not empty", + ) + + By("Verifying MAPI Machine has matching addresses from CAPI") + expectedMatchers := make([]interface{}, len(capiMachineSameName.Status.Addresses)) + for i, addr := range capiMachineSameName.Status.Addresses { + expectedMatchers[i] = SatisfyAll( + HaveField("Type", Equal(corev1.NodeAddressType(addr.Type))), + HaveField("Address", Equal(addr.Address)), + ) + } + Eventually(komega.Object(mapiMachineSameName), capiframework.WaitMedium, capiframework.RetryMedium).Should( + HaveField("Status.Addresses", ConsistOf(expectedMatchers...)), + "Should have MAPI Machine addresses match CAPI Machine addresses", + ) + }) + + It("should NOT have CAPI-specific conditions in MAPI Machine", func() { + Consistently(komega.Object(mapiMachineSameName), capiframework.WaitShort, capiframework.RetryShort).Should( + SatisfyAll( + HaveField("Status.Conditions", Not(ContainElement(HaveField("Type", Equal(clusterv1.ReadyCondition))))), + HaveField("Status.Conditions", Not(ContainElement(HaveField("Type", Equal(clusterv1.MachinesReadyV1Beta1Condition))))), + HaveField("Status.Conditions", Not(ContainElement(HaveField("Type", Equal(clusterv1.ResizedV1Beta1Condition))))), + HaveField("Status.Conditions", Not(ContainElement(HaveField("Type", Equal(clusterv1.MachinesCreatedV1Beta1Condition))))), + ), + "Should NOT have CAPI-specific conditions in MAPI Machine", + ) + }) + }) + }) +})