diff --git a/pkg/controller/plan/BUILD.bazel b/pkg/controller/plan/BUILD.bazel index 363f98ac6..8172e0ac9 100644 --- a/pkg/controller/plan/BUILD.bazel +++ b/pkg/controller/plan/BUILD.bazel @@ -28,6 +28,7 @@ go_library( "//pkg/controller/plan/handler", "//pkg/controller/plan/scheduler", "//pkg/controller/provider/web", + "//pkg/controller/provider/web/vsphere", "//pkg/controller/validation", "//pkg/lib/client/openshift", "//pkg/lib/condition", diff --git a/pkg/controller/plan/adapter/base/BUILD.bazel b/pkg/controller/plan/adapter/base/BUILD.bazel index e4d0cea04..1b82caa96 100644 --- a/pkg/controller/plan/adapter/base/BUILD.bazel +++ b/pkg/controller/plan/adapter/base/BUILD.bazel @@ -10,6 +10,7 @@ go_library( "//pkg/apis/forklift/v1beta1/plan", "//pkg/apis/forklift/v1beta1/ref", "//pkg/controller/plan/context", + "//pkg/controller/plan/util", "//pkg/lib/error", "//vendor/k8s.io/api/core/v1:core", "//vendor/kubevirt.io/api/core/v1:core", diff --git a/pkg/controller/plan/adapter/base/doc.go b/pkg/controller/plan/adapter/base/doc.go index 395466171..af9c8c9cf 100644 --- a/pkg/controller/plan/adapter/base/doc.go +++ b/pkg/controller/plan/adapter/base/doc.go @@ -5,6 +5,7 @@ import ( planapi "github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1/plan" "github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1/ref" plancontext "github.com/konveyor/forklift-controller/pkg/controller/plan/context" + "github.com/konveyor/forklift-controller/pkg/controller/plan/util" liberr "github.com/konveyor/forklift-controller/pkg/lib/error" core "k8s.io/api/core/v1" cnv "kubevirt.io/api/core/v1" @@ -103,13 +104,13 @@ type Client interface { // Return whether the source VM is powered off. PoweredOff(vmRef ref.Ref) (bool, error) // Create a snapshot of the source VM. - CreateSnapshot(vmRef ref.Ref) (string, error) + CreateSnapshot(vmRef ref.Ref, hostsFunc util.HostsFunc) (string, error) // Remove all warm migration snapshots. - RemoveSnapshots(vmRef ref.Ref, precopies []planapi.Precopy) error + RemoveSnapshots(vmRef ref.Ref, precopies []planapi.Precopy, hostsFunc util.HostsFunc) error // Check if a snapshot is ready to transfer. CheckSnapshotReady(vmRef ref.Ref, snapshot string) (ready bool, err error) // Set DataVolume checkpoints. - SetCheckpoints(vmRef ref.Ref, precopies []planapi.Precopy, datavolumes []cdi.DataVolume, final bool) (err error) + SetCheckpoints(vmRef ref.Ref, precopies []planapi.Precopy, datavolumes []cdi.DataVolume, final bool, hostsFunc util.HostsFunc) (err error) // Close connections to the provider API. Close() // Finalize migrations diff --git a/pkg/controller/plan/adapter/ocp/BUILD.bazel b/pkg/controller/plan/adapter/ocp/BUILD.bazel index 866ccb325..d097e5931 100644 --- a/pkg/controller/plan/adapter/ocp/BUILD.bazel +++ b/pkg/controller/plan/adapter/ocp/BUILD.bazel @@ -18,6 +18,7 @@ go_library( "//pkg/apis/forklift/v1beta1/ref", "//pkg/controller/plan/adapter/base", "//pkg/controller/plan/context", + "//pkg/controller/plan/util", "//pkg/controller/provider/web", "//pkg/lib/client/openshift", "//pkg/lib/error", diff --git a/pkg/controller/plan/adapter/ocp/client.go b/pkg/controller/plan/adapter/ocp/client.go index 44576f9d2..0c2564994 100644 --- a/pkg/controller/plan/adapter/ocp/client.go +++ b/pkg/controller/plan/adapter/ocp/client.go @@ -7,6 +7,7 @@ import ( planapi "github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1/plan" "github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1/ref" plancontext "github.com/konveyor/forklift-controller/pkg/controller/plan/context" + "github.com/konveyor/forklift-controller/pkg/controller/plan/util" liberr "github.com/konveyor/forklift-controller/pkg/lib/error" "github.com/konveyor/forklift-controller/pkg/settings" core "k8s.io/api/core/v1" @@ -34,7 +35,7 @@ func (r *Client) Close() { } // CreateSnapshot implements base.Client -func (r *Client) CreateSnapshot(vmRef ref.Ref) (string, error) { +func (r *Client) CreateSnapshot(vmRef ref.Ref, hostsFunc util.HostsFunc) (string, error) { return "", nil } @@ -123,12 +124,12 @@ func (r *Client) PoweredOff(vmRef ref.Ref) (bool, error) { } // RemoveSnapshots implements base.Client -func (r *Client) RemoveSnapshots(vmRef ref.Ref, precopies []planapi.Precopy) error { +func (r *Client) RemoveSnapshots(vmRef ref.Ref, precopies []planapi.Precopy, hostsFunc util.HostsFunc) error { return nil } // SetCheckpoints implements base.Client -func (r *Client) SetCheckpoints(vmRef ref.Ref, precopies []planapi.Precopy, datavolumes []cdi.DataVolume, final bool) (err error) { +func (r *Client) SetCheckpoints(vmRef ref.Ref, precopies []planapi.Precopy, datavolumes []cdi.DataVolume, final bool, hostsFunc util.HostsFunc) (err error) { return nil } diff --git a/pkg/controller/plan/adapter/openstack/client.go b/pkg/controller/plan/adapter/openstack/client.go index 5603133bc..61a751ebd 100644 --- a/pkg/controller/plan/adapter/openstack/client.go +++ b/pkg/controller/plan/adapter/openstack/client.go @@ -8,6 +8,7 @@ import ( planapi "github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1/plan" "github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1/ref" plancontext "github.com/konveyor/forklift-controller/pkg/controller/plan/context" + "github.com/konveyor/forklift-controller/pkg/controller/plan/util" model "github.com/konveyor/forklift-controller/pkg/controller/provider/web/openstack" libclient "github.com/konveyor/forklift-controller/pkg/lib/client/openstack" liberr "github.com/konveyor/forklift-controller/pkg/lib/error" @@ -109,12 +110,12 @@ func (r *Client) PoweredOff(vmRef ref.Ref) (off bool, err error) { } // Create a snapshot of the source VM. -func (r *Client) CreateSnapshot(vmRef ref.Ref) (imageID string, err error) { +func (r *Client) CreateSnapshot(vmRef ref.Ref, hostsFunc util.HostsFunc) (imageID string, err error) { return } // Remove all warm migration snapshots. -func (r *Client) RemoveSnapshots(vmRef ref.Ref, precopies []planapi.Precopy) (err error) { +func (r *Client) RemoveSnapshots(vmRef ref.Ref, precopies []planapi.Precopy, hostsFunc util.HostsFunc) (err error) { return } @@ -124,7 +125,7 @@ func (r *Client) CheckSnapshotReady(vmRef ref.Ref, imageID string) (ready bool, } // Set DataVolume checkpoints. -func (r *Client) SetCheckpoints(vmRef ref.Ref, precopies []planapi.Precopy, datavolumes []cdi.DataVolume, final bool) error { +func (r *Client) SetCheckpoints(vmRef ref.Ref, precopies []planapi.Precopy, datavolumes []cdi.DataVolume, final bool, hostsFunc util.HostsFunc) error { return nil } diff --git a/pkg/controller/plan/adapter/ova/BUILD.bazel b/pkg/controller/plan/adapter/ova/BUILD.bazel index 0795708f6..7e226422e 100644 --- a/pkg/controller/plan/adapter/ova/BUILD.bazel +++ b/pkg/controller/plan/adapter/ova/BUILD.bazel @@ -18,6 +18,7 @@ go_library( "//pkg/apis/forklift/v1beta1/ref", "//pkg/controller/plan/adapter/base", "//pkg/controller/plan/context", + "//pkg/controller/plan/util", "//pkg/controller/provider/model/ova", "//pkg/controller/provider/web", "//pkg/controller/provider/web/base", diff --git a/pkg/controller/plan/adapter/ova/client.go b/pkg/controller/plan/adapter/ova/client.go index b94ef9003..c890eab66 100644 --- a/pkg/controller/plan/adapter/ova/client.go +++ b/pkg/controller/plan/adapter/ova/client.go @@ -9,6 +9,7 @@ import ( planapi "github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1/plan" "github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1/ref" plancontext "github.com/konveyor/forklift-controller/pkg/controller/plan/context" + "github.com/konveyor/forklift-controller/pkg/controller/plan/util" libweb "github.com/konveyor/forklift-controller/pkg/lib/inventory/web" core "k8s.io/api/core/v1" cdi "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1" @@ -45,12 +46,12 @@ func (r *Client) connect() (err error) { } // Create a VM snapshot and return its ID. -func (r *Client) CreateSnapshot(vmRef ref.Ref) (snapshot string, err error) { +func (r *Client) CreateSnapshot(vmRef ref.Ref, hostsFunc util.HostsFunc) (snapshot string, err error) { return } // Remove all warm migration snapshots. -func (r *Client) RemoveSnapshots(vmRef ref.Ref, precopies []planapi.Precopy) (err error) { +func (r *Client) RemoveSnapshots(vmRef ref.Ref, precopies []planapi.Precopy, hostsFunc util.HostsFunc) (err error) { return } @@ -60,7 +61,7 @@ func (r *Client) CheckSnapshotReady(vmRef ref.Ref, snapshot string) (ready bool, } // Set DataVolume checkpoints. -func (r *Client) SetCheckpoints(vmRef ref.Ref, precopies []planapi.Precopy, datavolumes []cdi.DataVolume, final bool) (err error) { +func (r *Client) SetCheckpoints(vmRef ref.Ref, precopies []planapi.Precopy, datavolumes []cdi.DataVolume, final bool, hostsFunc util.HostsFunc) (err error) { return } diff --git a/pkg/controller/plan/adapter/ovirt/client.go b/pkg/controller/plan/adapter/ovirt/client.go index 5a2394ff7..c665dc978 100644 --- a/pkg/controller/plan/adapter/ovirt/client.go +++ b/pkg/controller/plan/adapter/ovirt/client.go @@ -11,6 +11,7 @@ import ( planapi "github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1/plan" "github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1/ref" plancontext "github.com/konveyor/forklift-controller/pkg/controller/plan/context" + "github.com/konveyor/forklift-controller/pkg/controller/plan/util" "github.com/konveyor/forklift-controller/pkg/controller/provider/container/ovirt" "github.com/konveyor/forklift-controller/pkg/controller/provider/web" model "github.com/konveyor/forklift-controller/pkg/controller/provider/web/ovirt" @@ -39,7 +40,7 @@ type Client struct { } // Create a VM snapshot and return its ID. -func (r *Client) CreateSnapshot(vmRef ref.Ref) (snapshot string, err error) { +func (r *Client) CreateSnapshot(vmRef ref.Ref, hostsFunc util.HostsFunc) (snapshot string, err error) { _, vmService, err := r.getVM(vmRef) if err != nil { err = liberr.Wrap(err) @@ -74,7 +75,7 @@ func (r *Client) CreateSnapshot(vmRef ref.Ref) (snapshot string, err error) { } // Remove all warm migration snapshots. -func (r *Client) RemoveSnapshots(vmRef ref.Ref, precopies []planapi.Precopy) (err error) { +func (r *Client) RemoveSnapshots(vmRef ref.Ref, precopies []planapi.Precopy, hostsFunc util.HostsFunc) (err error) { // Snapshot removal is done in Finalize to avoid race conditions return } @@ -110,7 +111,7 @@ func (r *Client) CheckSnapshotReady(vmRef ref.Ref, snapshot string) (ready bool, } // Set DataVolume checkpoints. -func (r *Client) SetCheckpoints(vmRef ref.Ref, precopies []planapi.Precopy, datavolumes []cdi.DataVolume, final bool) (err error) { +func (r *Client) SetCheckpoints(vmRef ref.Ref, precopies []planapi.Precopy, datavolumes []cdi.DataVolume, final bool, hostsFunc util.HostsFunc) (err error) { n := len(precopies) previous := "" current := precopies[n-1].Snapshot diff --git a/pkg/controller/plan/adapter/vsphere/BUILD.bazel b/pkg/controller/plan/adapter/vsphere/BUILD.bazel index 1303c6c6a..380efa315 100644 --- a/pkg/controller/plan/adapter/vsphere/BUILD.bazel +++ b/pkg/controller/plan/adapter/vsphere/BUILD.bazel @@ -18,6 +18,7 @@ go_library( "//pkg/apis/forklift/v1beta1/ref", "//pkg/controller/plan/adapter/base", "//pkg/controller/plan/context", + "//pkg/controller/plan/util", "//pkg/controller/provider/container/vsphere", "//pkg/controller/provider/model/vsphere", "//pkg/controller/provider/web", diff --git a/pkg/controller/plan/adapter/vsphere/client.go b/pkg/controller/plan/adapter/vsphere/client.go index 6ad372a98..e78b1e1e6 100644 --- a/pkg/controller/plan/adapter/vsphere/client.go +++ b/pkg/controller/plan/adapter/vsphere/client.go @@ -6,9 +6,11 @@ import ( liburl "net/url" "strconv" + "github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1" planapi "github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1/plan" "github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1/ref" plancontext "github.com/konveyor/forklift-controller/pkg/controller/plan/context" + "github.com/konveyor/forklift-controller/pkg/controller/plan/util" model "github.com/konveyor/forklift-controller/pkg/controller/provider/web/vsphere" liberr "github.com/konveyor/forklift-controller/pkg/lib/error" "github.com/konveyor/forklift-controller/pkg/settings" @@ -19,8 +21,10 @@ import ( "github.com/vmware/govmomi/vim25/mo" "github.com/vmware/govmomi/vim25/soap" "github.com/vmware/govmomi/vim25/types" + core "k8s.io/api/core/v1" "k8s.io/utils/ptr" cdi "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1" + k8sclient "sigs.k8s.io/controller-runtime/pkg/client" ) const ( @@ -31,13 +35,14 @@ const ( // vSphere VM Client type Client struct { *plancontext.Context - client *govmomi.Client + client *govmomi.Client + hostClients map[string]*govmomi.Client } // Create a VM snapshot and return its ID. -func (r *Client) CreateSnapshot(vmRef ref.Ref) (id string, err error) { +func (r *Client) CreateSnapshot(vmRef ref.Ref, hosts util.HostsFunc) (id string, err error) { r.Log.V(1).Info("Creating snapshot", "vmRef", vmRef) - vm, err := r.getVM(vmRef) + vm, err := r.getVM(vmRef, hosts) if err != nil { return } @@ -63,7 +68,7 @@ func (r *Client) CheckSnapshotReady(vmRef ref.Ref, snapshot string) (ready bool, } // Remove all warm migration snapshots. -func (r *Client) RemoveSnapshots(vmRef ref.Ref, precopies []planapi.Precopy) (err error) { +func (r *Client) RemoveSnapshots(vmRef ref.Ref, precopies []planapi.Precopy, hosts util.HostsFunc) (err error) { r.Log.V(1).Info("RemoveSnapshot", "vmRef", vmRef, @@ -76,16 +81,16 @@ func (r *Client) RemoveSnapshots(vmRef ref.Ref, precopies []planapi.Precopy) (er // only necessary to clean up the last snapshot if this feature is enabled, // because all others will have already been cleaned up. lastSnapshot := precopies[len(precopies)-1].Snapshot - err = r.removeSnapshot(vmRef, lastSnapshot, false) + err = r.removeSnapshot(vmRef, lastSnapshot, false, hosts) } else { rootSnapshot := precopies[0].Snapshot - err = r.removeSnapshot(vmRef, rootSnapshot, true) + err = r.removeSnapshot(vmRef, rootSnapshot, true, hosts) } return } // Set DataVolume checkpoints. -func (r *Client) SetCheckpoints(vmRef ref.Ref, precopies []planapi.Precopy, datavolumes []cdi.DataVolume, final bool) (err error) { +func (r *Client) SetCheckpoints(vmRef ref.Ref, precopies []planapi.Precopy, datavolumes []cdi.DataVolume, final bool, hosts util.HostsFunc) (err error) { n := len(precopies) previous := "" current := precopies[n-1].Snapshot @@ -103,7 +108,7 @@ func (r *Client) SetCheckpoints(vmRef ref.Ref, precopies []planapi.Precopy, data if settings.Settings.VsphereIncrementalBackup && previous != "" { var changeIds map[string]string - changeIds, err = r.getChangeIds(vmRef, previous) + changeIds, err = r.getChangeIds(vmRef, previous, hosts) if err != nil { return } @@ -115,7 +120,7 @@ func (r *Client) SetCheckpoints(vmRef ref.Ref, precopies []planapi.Precopy, data }) dv.Spec.FinalCheckpoint = final } - err = r.removeSnapshot(vmRef, previous, false) + err = r.removeSnapshot(vmRef, previous, false, hosts) if err != nil { return } @@ -134,7 +139,7 @@ func (r *Client) SetCheckpoints(vmRef ref.Ref, precopies []planapi.Precopy, data // Get the power state of the VM. func (r *Client) PowerState(vmRef ref.Ref) (state planapi.VMPowerState, err error) { - vm, err := r.getVM(vmRef) + vm, err := r.getVM(vmRef, nullableHosts) if err != nil { return } @@ -156,7 +161,7 @@ func (r *Client) PowerState(vmRef ref.Ref) (state planapi.VMPowerState, err erro // Power on the VM. func (r *Client) PowerOn(vmRef ref.Ref) (err error) { - vm, err := r.getVM(vmRef) + vm, err := r.getVM(vmRef, nullableHosts) if err != nil { return } @@ -177,7 +182,7 @@ func (r *Client) PowerOn(vmRef ref.Ref) (err error) { // Power off the VM. Requires guest tools to be installed. func (r *Client) PowerOff(vmRef ref.Ref) (err error) { - vm, err := r.getVM(vmRef) + vm, err := r.getVM(vmRef, nullableHosts) if err != nil { return } @@ -199,7 +204,7 @@ func (r *Client) PowerOff(vmRef ref.Ref) (err error) { // Determine whether the VM has been powered off. func (r *Client) PoweredOff(vmRef ref.Ref) (poweredOff bool, err error) { - vm, err := r.getVM(vmRef) + vm, err := r.getVM(vmRef, nullableHosts) if err != nil { return } @@ -219,6 +224,11 @@ func (r *Client) Close() { r.client.CloseIdleConnections() r.client = nil } + for _, client := range r.hostClients { + _ = client.Logout(context.TODO()) + client.CloseIdleConnections() + } + r.hostClients = nil } func (c *Client) Finalize(vms []*planapi.VMStatus, planName string) { @@ -230,8 +240,8 @@ func (r *Client) PreTransferActions(vmRef ref.Ref) (ready bool, err error) { } // Get the changeId for a VM snapshot. -func (r *Client) getChangeIds(vmRef ref.Ref, snapshotId string) (changeIdMapping map[string]string, err error) { - vm, err := r.getVM(vmRef) +func (r *Client) getChangeIds(vmRef ref.Ref, snapshotId string, hosts util.HostsFunc) (changeIdMapping map[string]string, err error) { + vm, err := r.getVM(vmRef, hosts) if err != nil { return } @@ -266,8 +276,96 @@ func (r *Client) getChangeIds(vmRef ref.Ref, snapshotId string) (changeIdMapping return } +func (r *Client) getClient(vm *model.VM, hosts util.HostsFunc) (client *vim25.Client, err error) { + if el9, el9Err := r.Plan.VSphereUsesEl9VirtV2v(); el9Err == nil && el9 { + // when virt-v2v/el9 runs the migration, forklift-controller should interact only + // with the component that serves the SDK endpoint of the provider + client = r.client.Client + return + } + + if r.Source.Provider.Spec.Settings[v1beta1.SDK] == v1beta1.ESXI { + // when migrating from ESXi host, we use the client of the SDK endpoint of the provider, + // there's no need in a different client (the ESXi host is the only component involved in the migration) + client = r.client.Client + return + } + + host := &model.Host{} + if err = r.Source.Inventory.Get(host, vm.Host); err != nil { + err = liberr.Wrap(err, "host", vm.Host) + return + } + + if cachedClient, found := r.hostClients[host.ID]; found { + // return the cached client for the ESXi host + client = cachedClient.Client + return + } + + if hostMap, hostsErr := hosts(); hostsErr == nil { + if hostDef, found := hostMap[host.ID]; found { + // create a new client for the ESXi host we are going to transfer the disk(s) from, and cache it + client, err = r.getHostClient(hostDef, host) + } else { + // there is no network defined for the ESXi host, so we will transfer the disk(s) from vCenter and + // thus there is no need in a client for the ESXi host but we use the client for vCenter instead + client = r.client.Client + } + } else { + err = liberr.Wrap(hostsErr) + } + return +} + +func (r *Client) getHostClient(hostDef *v1beta1.Host, host *model.Host) (client *vim25.Client, err error) { + url, err := liburl.Parse("https://" + hostDef.Spec.IpAddress + "/sdk") + if err != nil { + err = liberr.Wrap(err) + return + } + + ref := hostDef.Spec.Secret + secret := &core.Secret{} + err = r.Get( + context.TODO(), + k8sclient.ObjectKey{ + Namespace: ref.Namespace, + Name: ref.Name, + }, + secret) + if err != nil { + err = liberr.Wrap(err) + return + } + + url.User = liburl.UserPassword(string(secret.Data["user"]), string(secret.Data["password"])) + soapClient := soap.NewClient(url, r.getInsecureSkipVerifyFlag()) + soapClient.SetThumbprint(url.Host, host.Thumbprint) + vimClient, err := vim25.NewClient(context.TODO(), soapClient) + if err != nil { + err = liberr.Wrap(err) + return + } + hostClient := &govmomi.Client{ + SessionManager: session.NewManager(vimClient), + Client: vimClient, + } + if err = hostClient.Login(context.TODO(), url.User); err != nil { + err = liberr.Wrap(err) + return + } + + if r.hostClients == nil { + r.hostClients = make(map[string]*govmomi.Client) + } + r.hostClients[host.ID] = hostClient + client = hostClient.Client + return +} + // Get the VM by ref. -func (r *Client) getVM(vmRef ref.Ref) (vsphereVm *object.VirtualMachine, err error) { +func (r *Client) getVM(vmRef ref.Ref, hosts util.HostsFunc) (vsphereVm *object.VirtualMachine, err error) { vm := &model.VM{} err = r.Source.Inventory.Find(vm, vmRef) if err != nil { @@ -275,7 +373,12 @@ func (r *Client) getVM(vmRef ref.Ref) (vsphereVm *object.VirtualMachine, err err return } - searchIndex := object.NewSearchIndex(r.client.Client) + client, err := r.getClient(vm, hosts) + if err != nil { + return + } + + searchIndex := object.NewSearchIndex(client) vsphereRef, err := searchIndex.FindByUuid(context.TODO(), nil, vm.UUID, true, ptr.To(false)) if err != nil { err = liberr.Wrap(err) @@ -288,18 +391,22 @@ func (r *Client) getVM(vmRef ref.Ref) (vsphereVm *object.VirtualMachine, err err vmRef.String())) return } - vsphereVm = object.NewVirtualMachine(r.client.Client, vsphereRef.Reference()) + vsphereVm = object.NewVirtualMachine(client, vsphereRef.Reference()) + return +} + +func nullableHosts() (hosts map[string]*v1beta1.Host, err error) { return } // Remove a VM snapshot and optionally its children. -func (r *Client) removeSnapshot(vmRef ref.Ref, snapshot string, children bool) (err error) { +func (r *Client) removeSnapshot(vmRef ref.Ref, snapshot string, children bool, hosts util.HostsFunc) (err error) { r.Log.Info("Removing snapshot", "vmRef", vmRef, "snapshot", snapshot, "children", children) - vm, err := r.getVM(vmRef) + vm, err := r.getVM(vmRef, hosts) if err != nil { return } diff --git a/pkg/controller/plan/migration.go b/pkg/controller/plan/migration.go index 56efb1748..c633ae80e 100644 --- a/pkg/controller/plan/migration.go +++ b/pkg/controller/plan/migration.go @@ -19,9 +19,11 @@ import ( plancontext "github.com/konveyor/forklift-controller/pkg/controller/plan/context" "github.com/konveyor/forklift-controller/pkg/controller/plan/scheduler" "github.com/konveyor/forklift-controller/pkg/controller/provider/web" + model "github.com/konveyor/forklift-controller/pkg/controller/provider/web/vsphere" libcnd "github.com/konveyor/forklift-controller/pkg/lib/condition" liberr "github.com/konveyor/forklift-controller/pkg/lib/error" libitr "github.com/konveyor/forklift-controller/pkg/lib/itinerary" + libref "github.com/konveyor/forklift-controller/pkg/lib/ref" "github.com/konveyor/forklift-controller/pkg/settings" batchv1 "k8s.io/api/batch/v1" core "k8s.io/api/core/v1" @@ -490,7 +492,7 @@ func (r *Migration) removeWarmSnapshots(vm *plan.VMStatus) { if vm.Warm == nil { return } - if err := r.provider.RemoveSnapshots(vm.Ref, vm.Warm.Precopies); err != nil { + if err := r.provider.RemoveSnapshots(vm.Ref, vm.Warm.Precopies, r.loadHosts); err != nil { r.Log.Error( err, "Failed to clean up warm migration snapshots.", @@ -789,7 +791,7 @@ func (r *Migration) execute(vm *plan.VMStatus) (err error) { } } if vm.Warm != nil { - err = r.provider.SetCheckpoints(vm.Ref, vm.Warm.Precopies, dataVolumes, false) + err = r.provider.SetCheckpoints(vm.Ref, vm.Warm.Precopies, dataVolumes, false, r.loadHosts) if err != nil { step.AddError(err.Error()) err = nil @@ -961,8 +963,7 @@ func (r *Migration) execute(vm *plan.VMStatus) (err error) { break } var snapshot string - snapshot, err = r.provider.CreateSnapshot(vm.Ref) - if err != nil { + if snapshot, err = r.provider.CreateSnapshot(vm.Ref, r.loadHosts); err != nil { if errors.As(err, &web.ProviderNotReadyError{}) || errors.As(err, &web.ConflictError{}) { return } @@ -1078,7 +1079,7 @@ func (r *Migration) execute(vm *plan.VMStatus) (err error) { return } if step.MarkedCompleted() { - err = r.provider.RemoveSnapshots(vm.Ref, vm.Warm.Precopies) + err = r.provider.RemoveSnapshots(vm.Ref, vm.Warm.Precopies, r.loadHosts) if err != nil { r.Log.Info( "Failed to clean up warm migration snapshots.", @@ -1201,6 +1202,53 @@ func (r *Migration) execute(vm *plan.VMStatus) (err error) { return } +// Load host CRs. +func (r *Migration) loadHosts() (hosts map[string]*v1beta1.Host, err error) { + list := &v1beta1.HostList{} + err = r.List( + context.TODO(), + list, + &client.ListOptions{ + Namespace: r.Source.Provider.Namespace, + }, + ) + if err != nil { + err = liberr.Wrap(err) + return + } + hostMap := map[string]*v1beta1.Host{} + for i := range list.Items { + host := &list.Items[i] + ref := host.Spec.Ref + if !libref.Equals(&host.Spec.Provider, &r.Plan.Spec.Provider.Source) { + continue + } + + if !host.Status.HasCondition(libcnd.Ready) { + continue + } + // it's not that great to have a vSphere-specific entity here but as we don't + // intend to do the same for other providers, doing it here for simplicity + m := &model.Host{} + pErr := r.Source.Inventory.Find(m, ref) + if pErr != nil { + if errors.As(pErr, &web.NotFoundError{}) { + continue + } else { + err = pErr + return + } + } + ref.ID = m.ID + ref.Name = m.Name + hostMap[ref.ID] = host + } + + hosts = hostMap + + return +} + func (r *Migration) resetPrecopyTasks(vm *plan.VMStatus, step *plan.Step) { step.Completed = nil for _, task := range step.Tasks { @@ -1716,7 +1764,7 @@ func (r *Migration) setDataVolumeCheckpoints(vm *plan.VMStatus) (err error) { for _, disk := range disks { dvs = append(dvs, *disk.DataVolume) } - err = r.provider.SetCheckpoints(vm.Ref, vm.Warm.Precopies, dvs, vm.Phase == AddFinalCheckpoint) + err = r.provider.SetCheckpoints(vm.Ref, vm.Warm.Precopies, dvs, vm.Phase == AddFinalCheckpoint, r.loadHosts) if err != nil { return } diff --git a/pkg/controller/plan/util/utils.go b/pkg/controller/plan/util/utils.go index dbafdf24c..ae1e8c335 100644 --- a/pkg/controller/plan/util/utils.go +++ b/pkg/controller/plan/util/utils.go @@ -3,6 +3,7 @@ package util import ( "math" + api "github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1" "github.com/konveyor/forklift-controller/pkg/settings" core "k8s.io/api/core/v1" ) @@ -31,3 +32,5 @@ func CalculateSpaceWithOverhead(requestedSpace int64, volumeMode *core.Persisten } return spaceWithOverhead } + +type HostsFunc func() (map[string]*api.Host, error)