From b630f544fd9114ab1522dbd63cc4b22a9eb61df6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Mart=C3=ADn?= Date: Thu, 3 Aug 2023 10:50:05 +0200 Subject: [PATCH] openstack: fix cognitive complexity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miguel Martín --- .../plan/adapter/openstack/BUILD.bazel | 1 + .../plan/adapter/openstack/builder.go | 83 ++-- .../plan/adapter/openstack/client.go | 458 ++++++++++-------- 3 files changed, 291 insertions(+), 251 deletions(-) diff --git a/pkg/controller/plan/adapter/openstack/BUILD.bazel b/pkg/controller/plan/adapter/openstack/BUILD.bazel index 9a050d356..ae496d9ee 100644 --- a/pkg/controller/plan/adapter/openstack/BUILD.bazel +++ b/pkg/controller/plan/adapter/openstack/BUILD.bazel @@ -30,6 +30,7 @@ go_library( "//vendor/k8s.io/apimachinery/pkg/api/resource", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:meta", "//vendor/k8s.io/apimachinery/pkg/labels", + "//vendor/k8s.io/apimachinery/pkg/runtime/schema", "//vendor/k8s.io/apimachinery/pkg/types", "//vendor/kubevirt.io/api/core/v1:core", "//vendor/kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1", diff --git a/pkg/controller/plan/adapter/openstack/builder.go b/pkg/controller/plan/adapter/openstack/builder.go index 4dc9d78dc..9b43f1d81 100644 --- a/pkg/controller/plan/adapter/openstack/builder.go +++ b/pkg/controller/plan/adapter/openstack/builder.go @@ -876,13 +876,11 @@ func (r *Builder) PopulatorVolumes(vmRef ref.Ref, annotations map[string]string, err = liberr.Wrap(err) return } - images, err := r.getImagesFromVolumes(workload) if err != nil { err = liberr.Wrap(err) return } - if workload.ImageID != "" { var image model.Image image, err = r.getVMSnapshotImage(workload) @@ -892,34 +890,52 @@ func (r *Builder) PopulatorVolumes(vmRef ref.Ref, annotations map[string]string, } images = append(images, image) } - for _, image := range images { - if image.Status != string(ImageStatusActive) { r.Log.Info("the image is not ready yet", "image", image.Name) continue } - - originalVolumeDiskId := image.Name - if imageProperty, ok := image.Properties[forkliftPropertyOriginalVolumeID]; ok { - originalVolumeDiskId = imageProperty.(string) + var populatorName string + populatorName, err = r.ensureVolumePopulator(workload, &image, secretName) + if err != nil { + return } - - _, err = r.getVolumePopulator(image.Name) + var pvc *core.PersistentVolumeClaim + pvc, err = r.ensureVolumePopulatorPVC(workload, &image, annotations, populatorName) if err != nil { - if !k8serr.IsNotFound(err) { - err = liberr.Wrap(err) - return - } + return } + if pvc != nil { + pvcNames = append(pvcNames, pvc.Name) + } + } + return +} - var populatorName string - populatorName, err = r.createVolumePopulatorCR(image, secretName, vmRef.ID) - if err != nil { +func (r *Builder) ensureVolumePopulator(workload *model.Workload, image *model.Image, secretName string) (populatorName string, err error) { + volumePopulatorCR, err := r.getVolumePopulatorCR(image.Name) + if err != nil { + if !k8serr.IsNotFound(err) { err = liberr.Wrap(err) return } + return r.createVolumePopulatorCR(*image, secretName, workload.ID) + } + populatorName = volumePopulatorCR.Name + return +} +func (r *Builder) ensureVolumePopulatorPVC(workload *model.Workload, image *model.Image, annotations map[string]string, populatorName string) (pvc *core.PersistentVolumeClaim, err error) { + _, err = r.getVolumePopulatorPVC(image.ID) + if err != nil { + if !k8serr.IsNotFound(err) { + err = liberr.Wrap(err) + return + } + originalVolumeDiskId := image.Name + if imageProperty, ok := image.Properties[forkliftPropertyOriginalVolumeID]; ok { + originalVolumeDiskId = imageProperty.(string) + } storageClassName := r.Context.Map.Storage.Spec.Map[0].Destination.StorageClass volumeType := r.getVolumeType(workload, originalVolumeDiskId) if volumeType != "" { @@ -929,19 +945,7 @@ func (r *Builder) PopulatorVolumes(vmRef ref.Ref, annotations map[string]string, return } } - - var pvc *core.PersistentVolumeClaim - pvc, err = r.persistentVolumeClaimWithSourceRef(image, storageClassName, populatorName, annotations) - if err != nil { - if !k8serr.IsAlreadyExists(err) { - err = liberr.Wrap(err, "couldn't build the PVC", - "image", image.Name, "storageClassName", storageClassName, "populatorName", populatorName) - return - } - err = nil - continue - } - pvcNames = append(pvcNames, pvc.Name) + pvc, err = r.persistentVolumeClaimWithSourceRef(*image, storageClassName, populatorName, annotations) } return } @@ -1004,12 +1008,7 @@ func (r *Builder) createVolumePopulatorCR(image model.Image, secretName, vmId st } err = r.Context.Client.Create(context.TODO(), populatorCR, &client.CreateOptions{}) if err != nil { - if !k8serr.IsAlreadyExists(err) { - err = liberr.Wrap(err) - return - } else { - err = nil - } + return } name = populatorCR.Name return @@ -1074,12 +1073,18 @@ func (r *Builder) getVolumeAndAccessMode(storageClassName string) ([]core.Persis } // Get the OpenstackVolumePopulator CustomResource based on the image name. -func (r *Builder) getVolumePopulator(name string) (populatorCr api.OpenstackVolumePopulator, err error) { +func (r *Builder) getVolumePopulatorCR(name string) (populatorCr api.OpenstackVolumePopulator, err error) { populatorCr = api.OpenstackVolumePopulator{} err = r.Destination.Client.Get(context.TODO(), client.ObjectKey{Namespace: r.Plan.Spec.TargetNamespace, Name: name}, &populatorCr) return } +func (r *Builder) getVolumePopulatorPVC(name string) (populatorPvc core.PersistentVolumeClaim, err error) { + populatorPvc = core.PersistentVolumeClaim{} + err = r.Destination.Client.Get(context.TODO(), client.ObjectKey{Namespace: r.Plan.Spec.TargetNamespace, Name: name}, &populatorPvc) + return +} + func (r *Builder) persistentVolumeClaimWithSourceRef(image model.Image, storageClassName string, populatorName string, annotations map[string]string) (pvc *core.PersistentVolumeClaim, err error) { @@ -1142,7 +1147,7 @@ func (r *Builder) PopulatorTransferredBytes(persistentVolumeClaim *core.Persiste if err != nil { return } - populatorCr, err := r.getVolumePopulator(image.Name) + populatorCr, err := r.getVolumePopulatorCR(image.Name) if err != nil { return } @@ -1194,7 +1199,7 @@ func (r *Builder) SetPopulatorDataSourceLabels(vmRef ref.Ref, pvcs []core.Persis } migrationID := string(r.Plan.Status.Migration.ActiveSnapshot().Migration.UID) for _, image := range images { - populatorCr, err := r.getVolumePopulator(image.Name) + populatorCr, err := r.getVolumePopulatorCR(image.Name) if err != nil { continue } diff --git a/pkg/controller/plan/adapter/openstack/client.go b/pkg/controller/plan/adapter/openstack/client.go index e21a1a55e..bccde213f 100644 --- a/pkg/controller/plan/adapter/openstack/client.go +++ b/pkg/controller/plan/adapter/openstack/client.go @@ -179,225 +179,19 @@ func (r *Client) PreTransferActions(vmRef ref.Ref) (ready bool, err error) { vmRef.String()) return } - // VM Snapshot - vmSnapshotImage, err := r.getVmSnapshotImage(vm) - if err != nil { - if !errors.Is(err, ResourceNotFoundError) { - err = liberr.Wrap(err) - r.Log.Error(err, "trying to retrieve the VM snapshot image info", - "vm", vm.Name) - return - } - r.Log.Info("creating the VM snapshot image", "vm", vm.Name) - vmSnapshotImage, err = r.createVmSnapshotImage(vm) - if err != nil { - err = liberr.Wrap(err) - r.Log.Error(err, "trying to create the VM snapshot image", - "vm", vm.Name) - return - } - } - switch vmSnapshotImage.Status { - case ImageStatusActive: - r.Log.Info("the VM snapshot image is ready!", - "vm", vm.Name, "image", vmSnapshotImage.Name, "imageID", vmSnapshotImage.ID) - case ImageStatusImporting, ImageStatusQueued, ImageStatusUploading, ImageStatusSaving: - r.Log.Info("the VM snapshot image is not ready yet, skipping...", - "vm", vm.Name, "image", vmSnapshotImage.Name, "imageID", vmSnapshotImage.ID) - return - default: - err = liberr.New("unexpected VM snapshot image status") - r.Log.Error(err, "checking the VM snapshot image", - "vm", vm.Name, "image", vmSnapshotImage.Name, "imageID", vmSnapshotImage.ID, "status", vmSnapshotImage.Status) + ready, err = r.ensureVmSnapshot(vm) + if err != nil || !ready { return } - // Images from VM Volumes - var imagesFromVolumes []libclient.Image - imagesFromVolumes, err = r.getImagesFromVolumes(vm) - if err != nil { - err = liberr.Wrap(err) - r.Log.Error(err, "error while trying to get the images from the VM volumes", - "vm", vm.Name) + ready, err = r.ensureImagesFromVolumesReady(vm) + if err != nil || ready { return } - imagesFromVolumesMap := map[string]string{} - for _, image := range imagesFromVolumes { - imagesFromVolumesMap[image.ID] = image.Name - } - r.Log.Info("the images from volumes are", - "vm", vm.Name, "images", imagesFromVolumesMap) - - ready = true - for _, image := range imagesFromVolumes { - switch image.Status { - case ImageStatusQueued, ImageStatusUploading, ImageStatusSaving: - r.Log.Info("the image is still being processed", - "vm", vm.Name, "image", image.Name, "status", image.Status) - ready = false - case ImageStatusActive: - err = r.updateImageProperty(vm, &image) - if err != nil { - return - } - r.Log.Info("the image properties have been updated", - "vm", vm.Name, "image", image.Name, "properties", image.Properties) - inventoryImage := &model.Image{} - err = r.Context.Source.Inventory.Find(inventoryImage, ref.Ref{ID: image.ID}) - if err != nil { - if !errors.As(err, &model.NotFoundError{}) { - return - } - ready = false - err = nil - r.Log.Info("the image does not exist in the inventory, waiting...", - "vm", vm.Name, "image", image.Name, "properties", image.Properties) - continue - } - if _, ok := inventoryImage.Properties[forkliftPropertyOriginalVolumeID]; !ok { - r.Log.Info("image properties have not been synchronized, waiting...", - "vm", vm.Name, "image", inventoryImage.Name, "properties", inventoryImage.Properties) - ready = false - continue - } - r.Log.Info("the image properties are in sync, cleaning the image", - "vm", vm.Name, "image", inventoryImage.Name, "properties", inventoryImage.Properties) - originalVolumeID := inventoryImage.Properties[forkliftPropertyOriginalVolumeID].(string) - err = r.cleanup(vm, originalVolumeID) - if err != nil { - r.Log.Error(err, "cleaning the image", - "vm", vm.Name, "image", image.Name) - return - } - default: - err = liberr.New("unexpected image status") - r.Log.Error(err, "checking the image from volume", - "vm", vm.Name, "image", image.Name, "status", image.Status) - } - } - if len(vm.AttachedVolumes) != len(imagesFromVolumes) { - r.Log.Info("not all the images have been created", - "vm", vm.Name, "images", imagesFromVolumesMap, "attachedVolumes", vm.AttachedVolumes) - ready = false - } - if ready { - r.Log.Info("all steps finished!", "vm", vm.Name) - return - } - // Snapshots from VM Volumes - var snapshotsFromVolumes []libclient.Snapshot - snapshotsFromVolumes, err = r.getSnapshotsFromVolumes(vm) + err = r.ensureSnapshotsFromVolumes(vm) if err != nil { - err = liberr.Wrap(err) return } - snapshotsFromVolumesMap := map[string]string{} - for _, snapshot := range snapshotsFromVolumes { - snapshotsFromVolumesMap[snapshot.ID] = snapshot.VolumeID - } - r.Log.Info("the snapshots from volumes are", - "vm", vm.Name, "snapshots", snapshotsFromVolumesMap) - - for _, snapshot := range snapshotsFromVolumes { - switch snapshot.Status { - case SnapshotStatusCreating: - r.Log.Info("the snapshot is still being created, skipping...", - "vm", vm.Name, "snapshot", snapshot.Name) - case SnapshotStatusAvailable: - _, err = r.getVolumeFromSnapshot(vm, snapshot.ID) - if err != nil { - if !errors.Is(err, ResourceNotFoundError) { - err = liberr.Wrap(err) - r.Log.Error(err, "trying to get the snapshot info from the volume VM snapshot", - "vm", vm.Name, "snapshot", snapshot.Name) - return - } - imageName := getImageFromVolumeName(r.Context, vm.ID, snapshot.VolumeID) - var image *libclient.Image - image, err = r.getImage(ref.Ref{Name: imageName}) - if err == nil { - r.Log.Info("skipping the snapshot creation, the image already exists", - "vm", vm.Name, "snapshot", snapshot.Name) - continue - } else { - if !errors.Is(err, ResourceNotFoundError) { - err = liberr.Wrap(err) - r.Log.Error(err, "trying to get the image info from the snapshot", - "vm", vm.Name, "image", image.Name) - return - } - r.Log.Info("creating the volume from snapshot", - "vm", vm.Name, "snapshot", snapshot.Name) - _, err = r.createVolumeFromSnapshot(vm, snapshot.ID) - if err != nil { - err = liberr.Wrap(err) - r.Log.Error(err, "trying to create a volume from the VM snapshot", - "vm", vm.Name, "snapshot", snapshot.Name) - return - - } - } - } - case SnapshotStatusDeleted, SnapshotStatusDeleting: - r.Log.Info("the snapshot is being deleted, skipping...", - "vm", vm.Name, "snapshot", snapshot.Name) - default: - err = liberr.New("unexpected snapshot status") - r.Log.Error(err, "checking the snapshot", - "vm", vm.Name, "snapshot", snapshot.Name, "status", snapshot.Status) - return - } - } - // Volumes from VM Snapshots - var volumesFromSnapshots []libclient.Volume - volumesFromSnapshots, err = r.getVolumesFromSnapshots(vm) - if err != nil { - err = liberr.Wrap(err) - return - } - volumesFromSnapshotsMap := map[string]string{} - for _, volume := range volumesFromSnapshots { - volumesFromSnapshotsMap[volume.ID] = volume.SnapshotID - } - r.Log.Info("the volumes from snapshots are", - "vm", vm.Name, "snapshots", volumesFromSnapshotsMap) - - for _, volume := range volumesFromSnapshots { - switch volume.Status { - case VolumeStatusCreating: - r.Log.Info("the volume is still being created", - "vm", vm.Name, "volume", volume.Name, "snapshot", volume.SnapshotID) - case VolumeStatusUploading: - r.Log.Info("the volume is still uploading to the image, skipping...", - "vm", vm.Name, "volume", volume.Name, "snapshot", volume.SnapshotID) - case VolumeStatusAvailable: - _, err = r.getImageFromVolume(vm, volume.ID) - if err != nil { - if !errors.Is(err, ResourceNotFoundError) { - err = liberr.Wrap(err) - r.Log.Error(err, "while trying to get the image from the volume", - "vm", vm.Name, "volume", volume.Name, "snaphsot", volume.SnapshotID) - return - } - r.Log.Info("creating the image from the volume", - "vm", vm.Name, "volume", volume.Name, "snapshot", volume.SnapshotID) - _, err = r.createImageFromVolume(vm, volume.ID) - if err != nil { - err = liberr.Wrap(err) - r.Log.Error(err, "while trying to create the image from the volume", - "vm", vm.Name, "volume", volume.Name, "snapshot", volume.SnapshotID) - return - } - } - case VolumeStatusDeleting: - r.Log.Info("the volume is being deleted", - "vm", vm.Name, "volume", volume.Name, "snapshot", volume.SnapshotID) - default: - err = UnexpectedVolumeStatusError - r.Log.Error(err, "checking the volume", - "vm", vm.Name, "volume", volume.Name, "status", volume.Status) - return - } - } + err = r.ensureVolumesFromSnapshots(vm) return } @@ -922,3 +716,243 @@ func (r *Client) getImagesFromVolumes(vm *libclient.VM) (images []libclient.Imag } return } + +func (r *Client) ensureVmSnapshot(vm *libclient.VM) (ready bool, err error) { + vmSnapshotImage, err := r.getVmSnapshotImage(vm) + if err != nil { + if !errors.Is(err, ResourceNotFoundError) { + err = liberr.Wrap(err) + r.Log.Error(err, "trying to retrieve the VM snapshot image info", + "vm", vm.Name) + return + } + r.Log.Info("creating the VM snapshot image", "vm", vm.Name) + vmSnapshotImage, err = r.createVmSnapshotImage(vm) + if err != nil { + err = liberr.Wrap(err) + r.Log.Error(err, "trying to create the VM snapshot image", + "vm", vm.Name) + return + } + } + switch vmSnapshotImage.Status { + case ImageStatusActive: + r.Log.Info("the VM snapshot image is ready!", + "vm", vm.Name, "image", vmSnapshotImage.Name, "imageID", vmSnapshotImage.ID) + ready = true + case ImageStatusImporting, ImageStatusQueued, ImageStatusUploading, ImageStatusSaving: + r.Log.Info("the VM snapshot image is not ready yet, skipping...", + "vm", vm.Name, "image", vmSnapshotImage.Name, "imageID", vmSnapshotImage.ID) + return + default: + err = liberr.New("unexpected VM snapshot image status") + r.Log.Error(err, "checking the VM snapshot image", + "vm", vm.Name, "image", vmSnapshotImage.Name, "imageID", vmSnapshotImage.ID, "status", vmSnapshotImage.Status) + return + } + return +} + +func (r *Client) ensureImagesFromVolumesReady(vm *libclient.VM) (ready bool, err error) { + var imagesFromVolumes []libclient.Image + imagesFromVolumes, err = r.getImagesFromVolumes(vm) + if err != nil { + err = liberr.Wrap(err) + r.Log.Error(err, "error while trying to get the images from the VM volumes", + "vm", vm.Name) + return + } + ready = true + for _, image := range imagesFromVolumes { + ready, err = r.ensureImageFromVolumeReady(vm, &image) + if err != nil { + err = liberr.Wrap(err) + return + } + if !ready { + continue + } + originalVolumeID := image.Properties[forkliftPropertyOriginalVolumeID].(string) + err = r.cleanup(vm, originalVolumeID) + if err != nil { + r.Log.Error(err, "cleaning the image", + "vm", vm.Name, "image", image.Name) + return + } + } + if len(vm.AttachedVolumes) != len(imagesFromVolumes) { + r.Log.Info("not all the images have been created", + "vm", vm.Name, "attachedVolumes", vm.AttachedVolumes, "imagesFromVolumes", imagesFromVolumes) + ready = false + } + if ready { + r.Log.Info("all steps finished!", "vm", vm.Name) + } + return +} + +func (r *Client) ensureImageFromVolumeReady(vm *libclient.VM, image *libclient.Image) (ready bool, err error) { + switch image.Status { + case ImageStatusQueued, ImageStatusUploading, ImageStatusSaving: + r.Log.Info("the image is still being processed", + "vm", vm.Name, "image", image.Name, "status", image.Status) + case ImageStatusActive: + err = r.updateImageProperty(vm, image) + if err != nil { + return + } + r.Log.Info("the image properties have been updated", + "vm", vm.Name, "image", image.Name, "properties", image.Properties) + var imageUpToDate bool + imageUpToDate, err = r.ensureImageUpToDate(vm, image) + if err != nil || !imageUpToDate { + return + } + r.Log.Info("the image properties are in sync, cleaning the image", + "vm", vm.Name, "image", image.Name, "properties", image.Properties) + ready = true + default: + err = liberr.New("unexpected image status") + r.Log.Error(err, "checking the image from volume", + "vm", vm.Name, "image", image.Name, "status", image.Status) + } + return +} + +func (r *Client) ensureImageUpToDate(vm *libclient.VM, image *libclient.Image) (upToDate bool, err error) { + inventoryImage := &model.Image{} + err = r.Context.Source.Inventory.Find(inventoryImage, ref.Ref{ID: image.ID}) + if err != nil { + if !errors.As(err, &model.NotFoundError{}) { + return + } + r.Log.Info("the image does not exist in the inventory, waiting...", + "vm", vm.Name, "image", image.Name, "properties", image.Properties) + upToDate = false + err = nil + } + upToDate = true + if _, ok := inventoryImage.Properties[forkliftPropertyOriginalVolumeID]; !ok { + r.Log.Info("image properties have not been synchronized, waiting...", + "vm", vm.Name, "image", inventoryImage.Name, "properties", inventoryImage.Properties) + upToDate = false + } + return + +} + +func (r *Client) ensureSnapshotsFromVolumes(vm *libclient.VM) (err error) { + var snapshotsFromVolumes []libclient.Snapshot + snapshotsFromVolumes, err = r.getSnapshotsFromVolumes(vm) + if err != nil { + err = liberr.Wrap(err) + return + } + for _, snapshot := range snapshotsFromVolumes { + switch snapshot.Status { + case SnapshotStatusCreating: + r.Log.Info("the snapshot is still being created, skipping...", + "vm", vm.Name, "snapshot", snapshot.Name) + case SnapshotStatusAvailable: + err = r.ensureVolumeFromSnapshot(vm, &snapshot) + case SnapshotStatusDeleted, SnapshotStatusDeleting: + r.Log.Info("the snapshot is being deleted, skipping...", + "vm", vm.Name, "snapshot", snapshot.Name) + default: + err = liberr.New("unexpected snapshot status") + r.Log.Error(err, "checking the snapshot", + "vm", vm.Name, "snapshot", snapshot.Name, "status", snapshot.Status) + return + } + } + return +} + +func (r *Client) ensureVolumeFromSnapshot(vm *libclient.VM, snapshot *libclient.Snapshot) (err error) { + _, err = r.getVolumeFromSnapshot(vm, snapshot.ID) + if err != nil { + if !errors.Is(err, ResourceNotFoundError) { + err = liberr.Wrap(err) + r.Log.Error(err, "trying to get the snapshot info from the volume VM snapshot", + "vm", vm.Name, "snapshot", snapshot.Name) + return + } + imageName := getImageFromVolumeName(r.Context, vm.ID, snapshot.VolumeID) + var image *libclient.Image + image, err = r.getImage(ref.Ref{Name: imageName}) + if err == nil { + r.Log.Info("skipping the snapshot creation, the image already exists", + "vm", vm.Name, "snapshot", snapshot.Name) + } else { + if !errors.Is(err, ResourceNotFoundError) { + err = liberr.Wrap(err) + r.Log.Error(err, "trying to get the image info from the snapshot", + "vm", vm.Name, "image", image.Name) + return + } + r.Log.Info("creating the volume from snapshot", + "vm", vm.Name, "snapshot", snapshot.Name) + _, err = r.createVolumeFromSnapshot(vm, snapshot.ID) + if err != nil { + err = liberr.Wrap(err) + r.Log.Error(err, "trying to create a volume from the VM snapshot", + "vm", vm.Name, "snapshot", snapshot.Name) + return + + } + } + } + return +} + +func (r *Client) ensureVolumesFromSnapshots(vm *libclient.VM) (err error) { + var volumesFromSnapshots []libclient.Volume + volumesFromSnapshots, err = r.getVolumesFromSnapshots(vm) + if err != nil { + err = liberr.Wrap(err) + return + } + for _, volume := range volumesFromSnapshots { + switch volume.Status { + case VolumeStatusCreating: + r.Log.Info("the volume is still being created", + "vm", vm.Name, "volume", volume.Name, "snapshot", volume.SnapshotID) + case VolumeStatusUploading: + r.Log.Info("the volume is still uploading to the image, skipping...", + "vm", vm.Name, "volume", volume.Name, "snapshot", volume.SnapshotID) + case VolumeStatusAvailable: + err = r.ensureImageFromVolume(vm, &volume) + case VolumeStatusDeleting: + r.Log.Info("the volume is being deleted", + "vm", vm.Name, "volume", volume.Name, "snapshot", volume.SnapshotID) + default: + err = UnexpectedVolumeStatusError + r.Log.Error(err, "checking the volume", + "vm", vm.Name, "volume", volume.Name, "status", volume.Status) + return + } + } + return +} + +func (r *Client) ensureImageFromVolume(vm *libclient.VM, volume *libclient.Volume) (err error) { + _, err = r.getImageFromVolume(vm, volume.ID) + if err != nil { + if !errors.Is(err, ResourceNotFoundError) { + err = liberr.Wrap(err) + r.Log.Error(err, "while trying to get the image from the volume", + "vm", vm.Name, "volume", volume.Name, "snaphsot", volume.SnapshotID) + return + } + r.Log.Info("creating the image from the volume", + "vm", vm.Name, "volume", volume.Name, "snapshot", volume.SnapshotID) + _, err = r.createImageFromVolume(vm, volume.ID) + if err != nil { + err = liberr.Wrap(err) + r.Log.Error(err, "while trying to create the image from the volume", + "vm", vm.Name, "volume", volume.Name, "snapshot", volume.SnapshotID) + return + } + } + return +}