From b7501bcfde6e0700122213306a1903df2b977254 Mon Sep 17 00:00:00 2001 From: Martin Necas Date: Thu, 12 Sep 2024 12:37:45 +0200 Subject: [PATCH] MTV-446 | Warm: Add cbt check before migration Issue: Right now we have a check to fail the migration when we start to create the VM which does not have the CBT enabled. We should throw error much earlier before the customer even start the migration. Fix: Add a CBT check to the plan validation. This fix right now affects only VMware migrations. Signed-off-by: Martin Necas --- pkg/controller/plan/adapter/base/doc.go | 2 + pkg/controller/plan/adapter/ocp/validator.go | 5 + .../plan/adapter/openstack/validator.go | 5 + pkg/controller/plan/adapter/ova/validator.go | 6 + .../plan/adapter/ovirt/validator.go | 6 + .../plan/adapter/vsphere/validator.go | 13 ++ pkg/controller/plan/validation.go | 112 +++++++++++------- 7 files changed, 105 insertions(+), 44 deletions(-) diff --git a/pkg/controller/plan/adapter/base/doc.go b/pkg/controller/plan/adapter/base/doc.go index 9a8716ba8..f7e93fe4b 100644 --- a/pkg/controller/plan/adapter/base/doc.go +++ b/pkg/controller/plan/adapter/base/doc.go @@ -138,6 +138,8 @@ type Validator interface { PodNetwork(vmRef ref.Ref) (bool, error) // Validate that we have information about static IPs for every virtual NIC StaticIPs(vmRef ref.Ref) (bool, error) + // Validate that the vm has the change tracking enabled + ChangeTrackingEnabled(vmRef ref.Ref) (bool, error) } // DestinationClient API. diff --git a/pkg/controller/plan/adapter/ocp/validator.go b/pkg/controller/plan/adapter/ocp/validator.go index ed31ae4f2..58adaa206 100644 --- a/pkg/controller/plan/adapter/ocp/validator.go +++ b/pkg/controller/plan/adapter/ocp/validator.go @@ -192,3 +192,8 @@ func (r *Validator) DirectStorage(vmRef ref.Ref) (bool, error) { func (r *Validator) StaticIPs(vmRef ref.Ref) (bool, error) { return true, nil } + +// NO-OP +func (r *Validator) ChangeTrackingEnabled(vmRef ref.Ref) (bool, error) { + return true, nil +} diff --git a/pkg/controller/plan/adapter/openstack/validator.go b/pkg/controller/plan/adapter/openstack/validator.go index 8c374eb16..567f68328 100644 --- a/pkg/controller/plan/adapter/openstack/validator.go +++ b/pkg/controller/plan/adapter/openstack/validator.go @@ -115,3 +115,8 @@ func (r *Validator) StaticIPs(vmRef ref.Ref) (bool, error) { // the guest operating system is not modified during the migration so static IPs should be preserved return true, nil } + +// NO-OP +func (r *Validator) ChangeTrackingEnabled(vmRef ref.Ref) (bool, error) { + return true, nil +} diff --git a/pkg/controller/plan/adapter/ova/validator.go b/pkg/controller/plan/adapter/ova/validator.go index 9b0dd2204..565f7eacb 100644 --- a/pkg/controller/plan/adapter/ova/validator.go +++ b/pkg/controller/plan/adapter/ova/validator.go @@ -105,3 +105,9 @@ func (r *Validator) DirectStorage(vmRef ref.Ref) (bool, error) { func (r *Validator) StaticIPs(vmRef ref.Ref) (bool, error) { return true, nil } + +// NO-OP +func (r *Validator) ChangeTrackingEnabled(vmRef ref.Ref) (bool, error) { + // Validate that the vm has the change tracking enabled + return true, nil +} diff --git a/pkg/controller/plan/adapter/ovirt/validator.go b/pkg/controller/plan/adapter/ovirt/validator.go index 7a0a2517a..30406bc03 100644 --- a/pkg/controller/plan/adapter/ovirt/validator.go +++ b/pkg/controller/plan/adapter/ovirt/validator.go @@ -171,3 +171,9 @@ func (r *Validator) StaticIPs(vmRef ref.Ref) (bool, error) { // the guest operating system is not modified during the migration so static IPs should be preserved return true, nil } + +// NO-OP +func (r *Validator) ChangeTrackingEnabled(vmRef ref.Ref) (bool, error) { + // Validate that the vm has the change tracking enabled + return true, nil +} diff --git a/pkg/controller/plan/adapter/vsphere/validator.go b/pkg/controller/plan/adapter/vsphere/validator.go index 4c842d9a9..a43f167e0 100644 --- a/pkg/controller/plan/adapter/vsphere/validator.go +++ b/pkg/controller/plan/adapter/vsphere/validator.go @@ -155,3 +155,16 @@ func (r *Validator) StaticIPs(vmRef ref.Ref) (ok bool, err error) { ok = true return } + +// Validate that the vm has the change tracking enabled +func (r *Validator) ChangeTrackingEnabled(vmRef ref.Ref) (bool, error) { + if !r.plan.Spec.Warm { + return true, nil + } + vm := &model.Workload{} + err := r.inventory.Find(vm, vmRef) + if err != nil { + return false, liberr.Wrap(err, "vm", vmRef) + } + return vm.ChangeTrackingEnabled, nil +} diff --git a/pkg/controller/plan/validation.go b/pkg/controller/plan/validation.go index 9e84b1bda..d9892edb6 100644 --- a/pkg/controller/plan/validation.go +++ b/pkg/controller/plan/validation.go @@ -35,40 +35,41 @@ import ( // Types const ( - WarmMigrationNotReady = "WarmMigrationNotReady" - NamespaceNotValid = "NamespaceNotValid" - TransferNetNotValid = "TransferNetworkNotValid" - NetRefNotValid = "NetworkMapRefNotValid" - NetMapNotReady = "NetworkMapNotReady" - DsMapNotReady = "StorageMapNotReady" - DsRefNotValid = "StorageRefNotValid" - VMRefNotValid = "VMRefNotValid" - VMNotFound = "VMNotFound" - VMAlreadyExists = "VMAlreadyExists" - VMNetworksNotMapped = "VMNetworksNotMapped" - VMStorageNotMapped = "VMStorageNotMapped" - VMStorageNotSupported = "VMStorageNotSupported" - VMMultiplePodNetworkMappings = "VMMultiplePodNetworkMappings" - VMMissingGuestIPs = "VMMissingGuestIPs" - HostNotReady = "HostNotReady" - DuplicateVM = "DuplicateVM" - NameNotValid = "TargetNameNotValid" - HookNotValid = "HookNotValid" - HookNotReady = "HookNotReady" - HookStepNotValid = "HookStepNotValid" - Executing = "Executing" - Succeeded = "Succeeded" - Failed = "Failed" - Canceled = "Canceled" - Deleted = "Deleted" - Paused = "Paused" - Pending = "Pending" - Running = "Running" - Blocked = "Blocked" - Archived = "Archived" - unsupportedVersion = "UnsupportedVersion" - VDDKInvalid = "VDDKInvalid" - ValidatingVDDK = "ValidatingVDDK" + WarmMigrationNotReady = "WarmMigrationNotReady" + NamespaceNotValid = "NamespaceNotValid" + TransferNetNotValid = "TransferNetworkNotValid" + NetRefNotValid = "NetworkMapRefNotValid" + NetMapNotReady = "NetworkMapNotReady" + DsMapNotReady = "StorageMapNotReady" + DsRefNotValid = "StorageRefNotValid" + VMRefNotValid = "VMRefNotValid" + VMNotFound = "VMNotFound" + VMAlreadyExists = "VMAlreadyExists" + VMNetworksNotMapped = "VMNetworksNotMapped" + VMStorageNotMapped = "VMStorageNotMapped" + VMStorageNotSupported = "VMStorageNotSupported" + VMMultiplePodNetworkMappings = "VMMultiplePodNetworkMappings" + VMMissingGuestIPs = "VMMissingGuestIPs" + VMMissingChangedBlockTracking = "VMMissingChangedBlockTracking" + HostNotReady = "HostNotReady" + DuplicateVM = "DuplicateVM" + NameNotValid = "TargetNameNotValid" + HookNotValid = "HookNotValid" + HookNotReady = "HookNotReady" + HookStepNotValid = "HookStepNotValid" + Executing = "Executing" + Succeeded = "Succeeded" + Failed = "Failed" + Canceled = "Canceled" + Deleted = "Deleted" + Paused = "Paused" + Pending = "Pending" + Running = "Running" + Blocked = "Blocked" + Archived = "Archived" + unsupportedVersion = "UnsupportedVersion" + VDDKInvalid = "VDDKInvalid" + ValidatingVDDK = "ValidatingVDDK" ) // Categories @@ -82,16 +83,17 @@ const ( // Reasons const ( - NotSet = "NotSet" - NotFound = "NotFound" - NotUnique = "NotUnique" - NotSupported = "NotSupported" - Ambiguous = "Ambiguous" - NotValid = "NotValid" - Modified = "Modified" - UserRequested = "UserRequested" - InMaintenanceMode = "InMaintenanceMode" - MissingGuestInfo = "MissingGuestInformation" + NotSet = "NotSet" + NotFound = "NotFound" + NotUnique = "NotUnique" + NotSupported = "NotSupported" + Ambiguous = "Ambiguous" + NotValid = "NotValid" + Modified = "Modified" + UserRequested = "UserRequested" + InMaintenanceMode = "InMaintenanceMode" + MissingGuestInfo = "MissingGuestInformation" + MissingChangedBlockTracking = "MissingChangedBlockTracking" ) // Statuses @@ -236,6 +238,28 @@ func (r *Reconciler) validateWarmMigration(plan *api.Plan) (err error) { Message: "Warm migration from the source provider is not supported.", }) } + + missingCbtForWarm := libcnd.Condition{ + Type: VMMissingChangedBlockTracking, + Status: True, + Reason: MissingChangedBlockTracking, + Category: Critical, + Message: "Changed Block Tracking (CBT) has not been enabled on some VM. This feature is a prerequisite for VM warm migration.", + Items: []string{}, + } + for i := range plan.Spec.VMs { + ref := &plan.Spec.VMs[i].Ref + enabled, err := validator.ChangeTrackingEnabled(*ref) + if err != nil { + return err + } + if !enabled { + missingCbtForWarm.Items = append(missingCbtForWarm.Items, ref.String()) + } + } + if len(missingCbtForWarm.Items) > 0 { + plan.Status.SetCondition(missingCbtForWarm) + } return }