From 45ecc962a6dea21852291dfa0e1cb98181d7d3e0 Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Fri, 25 Apr 2025 16:49:05 +0300 Subject: [PATCH 1/8] add Signed-off-by: Valeriy Khorunzhin --- api/core/v1alpha2/virtual_machine_snapshot.go | 11 ++++ api/core/v1alpha2/zz_generated.deepcopy.go | 21 +++++++ .../generated/openapi/zz_generated.openapi.go | 50 ++++++++++++++- crds/virtualmachinesnapshots.yaml | 15 +++++ .../vmsnapshot/internal/life_cycle.go | 61 ++++++++++++++++++- .../vmsnapshot/vmsnapshot_controller.go | 2 +- 6 files changed, 156 insertions(+), 4 deletions(-) diff --git a/api/core/v1alpha2/virtual_machine_snapshot.go b/api/core/v1alpha2/virtual_machine_snapshot.go index 4e4770e695..a329fd15be 100644 --- a/api/core/v1alpha2/virtual_machine_snapshot.go +++ b/api/core/v1alpha2/virtual_machine_snapshot.go @@ -72,6 +72,15 @@ type VirtualMachineSnapshotSpec struct { VolumeSnapshotClasses []VolumeSnapshotClassName `json:"volumeSnapshotClasses,omitempty"` } +type ResourceRef struct { + // Kind of resource + Kind string `json:"kind,omitempty"` + // Api version of resource + ApiVersion string `json:"apiVersion,omitempty"` + // Resource Name + Name string `json:"name,omitempty"` +} + type VirtualMachineSnapshotStatus struct { Phase VirtualMachineSnapshotPhase `json:"phase"` // Whether a virtual machine snapshot is consistent. @@ -80,6 +89,8 @@ type VirtualMachineSnapshotStatus struct { VirtualMachineSnapshotSecretName string `json:"virtualMachineSnapshotSecretName,omitempty"` // List of VirtualDiskSnapshot names for the snapshots taken from the virtual disks of the associated virtual machine. VirtualDiskSnapshotNames []string `json:"virtualDiskSnapshotNames,omitempty"` + // Snapshotted resource list + Resources []ResourceRef `json:"resources,omitempty"` // The latest detailed observations of the VirtualMachineSnapshot resource. Conditions []metav1.Condition `json:"conditions,omitempty"` // Resource generation last processed by the controller. diff --git a/api/core/v1alpha2/zz_generated.deepcopy.go b/api/core/v1alpha2/zz_generated.deepcopy.go index be154678db..1245cd6aff 100644 --- a/api/core/v1alpha2/zz_generated.deepcopy.go +++ b/api/core/v1alpha2/zz_generated.deepcopy.go @@ -660,6 +660,22 @@ func (in *Provisioning) DeepCopy() *Provisioning { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceRef) DeepCopyInto(out *ResourceRef) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceRef. +func (in *ResourceRef) DeepCopy() *ResourceRef { + if in == nil { + return nil + } + out := new(ResourceRef) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ResourcesStatus) DeepCopyInto(out *ResourcesStatus) { *out = *in @@ -2513,6 +2529,11 @@ func (in *VirtualMachineSnapshotStatus) DeepCopyInto(out *VirtualMachineSnapshot *out = make([]string, len(*in)) copy(*out, *in) } + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = make([]ResourceRef, len(*in)) + copy(*out, *in) + } if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions *out = make([]v1.Condition, len(*in)) diff --git a/api/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go b/api/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go index d09e50f796..38efc2e08c 100644 --- a/api/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go +++ b/api/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go @@ -64,6 +64,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/deckhouse/virtualization/api/core/v1alpha2.NameReplacementFrom": schema_virtualization_api_core_v1alpha2_NameReplacementFrom(ref), "github.com/deckhouse/virtualization/api/core/v1alpha2.NodeSelector": schema_virtualization_api_core_v1alpha2_NodeSelector(ref), "github.com/deckhouse/virtualization/api/core/v1alpha2.Provisioning": schema_virtualization_api_core_v1alpha2_Provisioning(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha2.ResourceRef": schema_virtualization_api_core_v1alpha2_ResourceRef(ref), "github.com/deckhouse/virtualization/api/core/v1alpha2.ResourcesStatus": schema_virtualization_api_core_v1alpha2_ResourcesStatus(ref), "github.com/deckhouse/virtualization/api/core/v1alpha2.SizingPolicy": schema_virtualization_api_core_v1alpha2_SizingPolicy(ref), "github.com/deckhouse/virtualization/api/core/v1alpha2.SizingPolicyCores": schema_virtualization_api_core_v1alpha2_SizingPolicyCores(ref), @@ -1768,6 +1769,39 @@ func schema_virtualization_api_core_v1alpha2_Provisioning(ref common.ReferenceCa } } +func schema_virtualization_api_core_v1alpha2_ResourceRef(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind of resource", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "Api version of resource", + Type: []string{"string"}, + Format: "", + }, + }, + "name": { + SchemaProps: spec.SchemaProps{ + Description: "Resource Name", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + func schema_virtualization_api_core_v1alpha2_ResourcesStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -4879,6 +4913,20 @@ func schema_virtualization_api_core_v1alpha2_VirtualMachineSnapshotStatus(ref co }, }, }, + "resources": { + SchemaProps: spec.SchemaProps{ + Description: "Snapshotted resource list", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/deckhouse/virtualization/api/core/v1alpha2.ResourceRef"), + }, + }, + }, + }, + }, "conditions": { SchemaProps: spec.SchemaProps{ Description: "The latest detailed observations of the VirtualMachineSnapshot resource.", @@ -4905,7 +4953,7 @@ func schema_virtualization_api_core_v1alpha2_VirtualMachineSnapshotStatus(ref co }, }, Dependencies: []string{ - "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, + "github.com/deckhouse/virtualization/api/core/v1alpha2.ResourceRef", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, } } diff --git a/crds/virtualmachinesnapshots.yaml b/crds/virtualmachinesnapshots.yaml index 6dccf851d9..dfcfbc3598 100644 --- a/crds/virtualmachinesnapshots.yaml +++ b/crds/virtualmachinesnapshots.yaml @@ -195,6 +195,21 @@ spec: - Failed - Terminating type: string + resources: + description: Snapshotted resource list + items: + properties: + apiVersion: + description: Api version of resource + type: string + kind: + description: Kind of resource + type: string + name: + description: Resource Name + type: string + type: object + type: array virtualDiskSnapshotNames: description: List of VirtualDiskSnapshot names for the snapshots taken diff --git a/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle.go b/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle.go index 203d56f758..0752a4c9fa 100644 --- a/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle.go +++ b/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle.go @@ -24,9 +24,12 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" + "github.com/deckhouse/virtualization-controller/pkg/common/object" "github.com/deckhouse/virtualization-controller/pkg/controller/conditions" "github.com/deckhouse/virtualization-controller/pkg/controller/service" "github.com/deckhouse/virtualization-controller/pkg/eventrecord" @@ -42,13 +45,15 @@ type LifeCycleHandler struct { recorder eventrecord.EventRecorderLogger snapshotter Snapshotter storer Storer + client client.Client } -func NewLifeCycleHandler(recorder eventrecord.EventRecorderLogger, snapshotter Snapshotter, storer Storer) *LifeCycleHandler { +func NewLifeCycleHandler(recorder eventrecord.EventRecorderLogger, snapshotter Snapshotter, storer Storer, client client.Client) *LifeCycleHandler { return &LifeCycleHandler{ recorder: recorder, snapshotter: snapshotter, storer: storer, + client: client, } } @@ -353,7 +358,14 @@ func (h LifeCycleHandler) Handle(ctx context.Context, vmSnapshot *virtv2.Virtual return reconcile.Result{}, err } - // 9. Move to Ready phase. + // 9. Fill status resources. + err = h.fillStatusResources(ctx, vmSnapshot, vm) + if err != nil { + h.setPhaseConditionToFailed(cb, vmSnapshot, err) + return reconcile.Result{}, err + } + + // 10. Move to Ready phase. log.Debug("The virtual disk snapshots are taken: the virtual machine snapshot is Ready now", "unfrozen", unfrozen) vmSnapshot.Status.Phase = virtv2.VirtualMachineSnapshotPhaseReady @@ -649,3 +661,48 @@ func getVDName(vdSnapshotName string, vmSnapshot *virtv2.VirtualMachineSnapshot) func getVDSnapshotName(vdName string, vmSnapshot *virtv2.VirtualMachineSnapshot) string { return fmt.Sprintf("%s-%s", vdName, vmSnapshot.UID) } + +func (h LifeCycleHandler) fillStatusResources(ctx context.Context, vmSnapshot *virtv2.VirtualMachineSnapshot, vm *virtv2.VirtualMachine) error { + vmSnapshot.Status.Resources = []virtv2.ResourceRef{} + + vmSnapshot.Status.Resources = append(vmSnapshot.Status.Resources, virtv2.ResourceRef{ + Kind: virtv2.VirtualMachineKind, + Name: vm.Name, + }) + + for _, bdr := range vm.Status.BlockDeviceRefs { + if bdr.Kind != virtv2.DiskDevice { + continue + } + + vd, err := object.FetchObject(ctx, types.NamespacedName{Name: bdr.Name, Namespace: vm.Namespace}, h.client, &virtv2.VirtualDisk{}) + if err != nil { + return err + } + if vd == nil { + continue + } + vmSnapshot.Status.Resources = append(vmSnapshot.Status.Resources, virtv2.ResourceRef{ + Kind: vd.Kind, + ApiVersion: vd.APIVersion, + Name: vd.Name, + }) + + if bdr.VirtualMachineBlockDeviceAttachmentName != "" { + vmbda, err := object.FetchObject(ctx, types.NamespacedName{Name: bdr.VirtualMachineBlockDeviceAttachmentName, Namespace: vm.Namespace}, h.client, &virtv2.VirtualMachineBlockDeviceAttachment{}) + if err != nil { + return err + } + if vmbda == nil { + continue + } + vmSnapshot.Status.Resources = append(vmSnapshot.Status.Resources, virtv2.ResourceRef{ + Kind: vmbda.Kind, + ApiVersion: vmbda.APIVersion, + Name: vmbda.Name, + }) + } + } + + return nil +} diff --git a/images/virtualization-artifact/pkg/controller/vmsnapshot/vmsnapshot_controller.go b/images/virtualization-artifact/pkg/controller/vmsnapshot/vmsnapshot_controller.go index 9ddaaea503..7dfced1722 100644 --- a/images/virtualization-artifact/pkg/controller/vmsnapshot/vmsnapshot_controller.go +++ b/images/virtualization-artifact/pkg/controller/vmsnapshot/vmsnapshot_controller.go @@ -50,7 +50,7 @@ func NewController( reconciler := NewReconciler( mgr.GetClient(), internal.NewVirtualMachineReadyHandler(snapshotter), - internal.NewLifeCycleHandler(recorder, snapshotter, restorer.NewSecretRestorer(mgr.GetClient())), + internal.NewLifeCycleHandler(recorder, snapshotter, restorer.NewSecretRestorer(mgr.GetClient()), mgr.GetClient()), ) vmSnapshotController, err := controller.New(ControllerName, mgr, controller.Options{ From 8cc283ac1b867d3722c53174e5f0e03764bb6c8d Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Fri, 25 Apr 2025 17:13:32 +0300 Subject: [PATCH 2/8] fix test Signed-off-by: Valeriy Khorunzhin --- .../vmsnapshot/internal/life_cycle_test.go | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle_test.go b/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle_test.go index fa5f13c1eb..6435200752 100644 --- a/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle_test.go +++ b/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle_test.go @@ -27,6 +27,7 @@ import ( "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/deckhouse/virtualization-controller/pkg/common/testutil" "github.com/deckhouse/virtualization-controller/pkg/controller/conditions" "github.com/deckhouse/virtualization-controller/pkg/eventrecord" virtv2 "github.com/deckhouse/virtualization/api/core/v1alpha2" @@ -44,6 +45,7 @@ var _ = Describe("LifeCycle handler", func() { var secret *corev1.Secret var vdSnapshot *virtv2.VirtualDiskSnapshot var vmSnapshot *virtv2.VirtualMachineSnapshot + var fakeClient client.WithWatch BeforeEach(func() { vd = &virtv2.VirtualDisk{ @@ -142,6 +144,10 @@ var _ = Describe("LifeCycle handler", func() { }, } + var err error + fakeClient, err = testutil.NewFakeClientWithObjects(vd, vm, secret, vmSnapshot, vdSnapshot) + Expect(err).ShouldNot(HaveOccurred()) + recorder = &eventrecord.EventRecorderLoggerMock{ EventFunc: func(_ client.Object, _, _, _ string) {}, } @@ -156,7 +162,7 @@ var _ = Describe("LifeCycle handler", func() { conditions.SetCondition(cb, &vm.Status.Conditions) return vm, nil } - h := NewLifeCycleHandler(recorder, snapshotter, storer) + h := NewLifeCycleHandler(recorder, snapshotter, storer, fakeClient) _, err := h.Handle(testContext(), vmSnapshot) Expect(err).To(BeNil()) @@ -172,7 +178,7 @@ var _ = Describe("LifeCycle handler", func() { vd.Status.Phase = virtv2.DiskPending return vd, nil } - h := NewLifeCycleHandler(recorder, snapshotter, storer) + h := NewLifeCycleHandler(recorder, snapshotter, storer, fakeClient) _, err := h.Handle(testContext(), vmSnapshot) Expect(err).To(BeNil()) @@ -191,7 +197,7 @@ var _ = Describe("LifeCycle handler", func() { conditions.SetCondition(cb, &vd.Status.Conditions) return vd, nil } - h := NewLifeCycleHandler(recorder, snapshotter, storer) + h := NewLifeCycleHandler(recorder, snapshotter, storer, fakeClient) _, err := h.Handle(testContext(), vmSnapshot) Expect(err).To(BeNil()) @@ -211,7 +217,7 @@ var _ = Describe("LifeCycle handler", func() { conditions.SetCondition(cb, &vd.Status.Conditions) return vd, nil } - h := NewLifeCycleHandler(recorder, snapshotter, storer) + h := NewLifeCycleHandler(recorder, snapshotter, storer, fakeClient) _, err := h.Handle(testContext(), vmSnapshot) Expect(err).To(BeNil()) @@ -230,7 +236,7 @@ var _ = Describe("LifeCycle handler", func() { return vm, nil } - h := NewLifeCycleHandler(recorder, snapshotter, storer) + h := NewLifeCycleHandler(recorder, snapshotter, storer, fakeClient) _, err := h.Handle(testContext(), vmSnapshot) Expect(err).To(BeNil()) @@ -249,7 +255,7 @@ var _ = Describe("LifeCycle handler", func() { return false } - h := NewLifeCycleHandler(recorder, snapshotter, storer) + h := NewLifeCycleHandler(recorder, snapshotter, storer, fakeClient) _, err := h.Handle(testContext(), vmSnapshot) Expect(err).To(BeNil()) @@ -271,7 +277,7 @@ var _ = Describe("LifeCycle handler", func() { return nil } - h := NewLifeCycleHandler(recorder, snapshotter, storer) + h := NewLifeCycleHandler(recorder, snapshotter, storer, fakeClient) _, err := h.Handle(testContext(), vmSnapshot) Expect(err).To(BeNil()) @@ -289,7 +295,7 @@ var _ = Describe("LifeCycle handler", func() { }) It("The snapshot of virtual machine is Ready", func() { - h := NewLifeCycleHandler(recorder, snapshotter, storer) + h := NewLifeCycleHandler(recorder, snapshotter, storer, fakeClient) _, err := h.Handle(testContext(), vmSnapshot) Expect(err).To(BeNil()) @@ -303,7 +309,7 @@ var _ = Describe("LifeCycle handler", func() { }) It("The snapshot of running virtual machine is consistent", func() { - h := NewLifeCycleHandler(recorder, snapshotter, storer) + h := NewLifeCycleHandler(recorder, snapshotter, storer, fakeClient) _, err := h.Handle(testContext(), vmSnapshot) Expect(err).To(BeNil()) @@ -315,7 +321,7 @@ var _ = Describe("LifeCycle handler", func() { vm.Status.Phase = virtv2.MachineStopped return vm, nil } - h := NewLifeCycleHandler(recorder, snapshotter, storer) + h := NewLifeCycleHandler(recorder, snapshotter, storer, fakeClient) _, err := h.Handle(testContext(), vmSnapshot) Expect(err).To(BeNil()) @@ -328,7 +334,7 @@ var _ = Describe("LifeCycle handler", func() { vdSnapshot.Status.Consistent = nil return vdSnapshot, nil } - h := NewLifeCycleHandler(recorder, snapshotter, storer) + h := NewLifeCycleHandler(recorder, snapshotter, storer, fakeClient) _, err := h.Handle(testContext(), vmSnapshot) Expect(err).To(BeNil()) From d71a90535b7d4425bf35ace6970c66ae9890b9d6 Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Fri, 25 Apr 2025 17:21:45 +0300 Subject: [PATCH 3/8] fix vm apiVersion Signed-off-by: Valeriy Khorunzhin --- .../pkg/controller/vmsnapshot/internal/life_cycle.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle.go b/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle.go index 0752a4c9fa..60902c7048 100644 --- a/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle.go +++ b/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle.go @@ -666,8 +666,9 @@ func (h LifeCycleHandler) fillStatusResources(ctx context.Context, vmSnapshot *v vmSnapshot.Status.Resources = []virtv2.ResourceRef{} vmSnapshot.Status.Resources = append(vmSnapshot.Status.Resources, virtv2.ResourceRef{ - Kind: virtv2.VirtualMachineKind, - Name: vm.Name, + Kind: virtv2.VirtualMachineKind, + ApiVersion: vm.APIVersion, + Name: vm.Name, }) for _, bdr := range vm.Status.BlockDeviceRefs { From 53ba16985a32f9fe08457ab84ad889e10daa04a9 Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Mon, 28 Apr 2025 18:38:21 +0300 Subject: [PATCH 4/8] add secret and vmip Signed-off-by: Valeriy Khorunzhin --- .../vmsnapshot/internal/life_cycle.go | 62 ++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle.go b/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle.go index 60902c7048..351d1766e0 100644 --- a/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle.go +++ b/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle.go @@ -666,11 +666,71 @@ func (h LifeCycleHandler) fillStatusResources(ctx context.Context, vmSnapshot *v vmSnapshot.Status.Resources = []virtv2.ResourceRef{} vmSnapshot.Status.Resources = append(vmSnapshot.Status.Resources, virtv2.ResourceRef{ - Kind: virtv2.VirtualMachineKind, + Kind: vm.Kind, ApiVersion: vm.APIVersion, Name: vm.Name, }) + if vmSnapshot.Spec.KeepIPAddress == virtv2.KeepIPAddressAlways { + vmip, err := object.FetchObject(ctx, types.NamespacedName{ + Namespace: vm.Namespace, + Name: vm.Status.VirtualMachineIPAddress, + }, h.client, &virtv2.VirtualMachineIPAddress{}) + if err != nil { + return err + } + + if vmip == nil { + return fmt.Errorf("the virtual machine ip address %q not found", vm.Status.VirtualMachineIPAddress) + } + + vmSnapshot.Status.Resources = append(vmSnapshot.Status.Resources, virtv2.ResourceRef{ + Kind: vmip.Kind, + ApiVersion: vmip.APIVersion, + Name: vmip.APIVersion, + }) + } + + if vm.Spec.Provisioning != nil { + var provisioningSecretName string + + switch vm.Spec.Provisioning.Type { + case virtv2.ProvisioningTypeSysprepRef: + if vm.Spec.Provisioning.SysprepRef == nil { + return errors.New("the virtual machine sysprep ref provisioning is nil") + } + + if vm.Spec.Provisioning.SysprepRef.Kind == virtv2.SysprepRefKindSecret { + provisioningSecretName = vm.Spec.Provisioning.SysprepRef.Name + } + + case virtv2.ProvisioningTypeUserDataRef: + if vm.Spec.Provisioning.UserDataRef == nil { + return errors.New("the virtual machine user data ref provisioning is nil") + } + + if vm.Spec.Provisioning.UserDataRef.Kind == virtv2.UserDataRefKindSecret { + provisioningSecretName = vm.Spec.Provisioning.UserDataRef.Name + } + } + + if provisioningSecretName != "" { + secretKey := types.NamespacedName{Name: provisioningSecretName, Namespace: vm.Namespace} + provisioner, err := object.FetchObject(ctx, secretKey, h.client, &corev1.Secret{}) + if err != nil { + return err + } + + if provisioner != nil { + vmSnapshot.Status.Resources = append(vmSnapshot.Status.Resources, virtv2.ResourceRef{ + Kind: provisioner.Kind, + ApiVersion: provisioner.APIVersion, + Name: provisioner.Name, + }) + } + } + } + for _, bdr := range vm.Status.BlockDeviceRefs { if bdr.Kind != virtv2.DiskDevice { continue From 28aa20ef7f2ced07e6ba323e2873c565ccbd283e Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Tue, 29 Apr 2025 11:27:35 +0300 Subject: [PATCH 5/8] refactoring Signed-off-by: Valeriy Khorunzhin --- .../vmsnapshot/internal/life_cycle.go | 86 ++++++++++--------- 1 file changed, 47 insertions(+), 39 deletions(-) diff --git a/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle.go b/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle.go index 351d1766e0..d5e99ab9f3 100644 --- a/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle.go +++ b/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle.go @@ -687,48 +687,20 @@ func (h LifeCycleHandler) fillStatusResources(ctx context.Context, vmSnapshot *v vmSnapshot.Status.Resources = append(vmSnapshot.Status.Resources, virtv2.ResourceRef{ Kind: vmip.Kind, ApiVersion: vmip.APIVersion, - Name: vmip.APIVersion, + Name: vmip.Name, }) } - if vm.Spec.Provisioning != nil { - var provisioningSecretName string - - switch vm.Spec.Provisioning.Type { - case virtv2.ProvisioningTypeSysprepRef: - if vm.Spec.Provisioning.SysprepRef == nil { - return errors.New("the virtual machine sysprep ref provisioning is nil") - } - - if vm.Spec.Provisioning.SysprepRef.Kind == virtv2.SysprepRefKindSecret { - provisioningSecretName = vm.Spec.Provisioning.SysprepRef.Name - } - - case virtv2.ProvisioningTypeUserDataRef: - if vm.Spec.Provisioning.UserDataRef == nil { - return errors.New("the virtual machine user data ref provisioning is nil") - } - - if vm.Spec.Provisioning.UserDataRef.Kind == virtv2.UserDataRefKindSecret { - provisioningSecretName = vm.Spec.Provisioning.UserDataRef.Name - } - } - - if provisioningSecretName != "" { - secretKey := types.NamespacedName{Name: provisioningSecretName, Namespace: vm.Namespace} - provisioner, err := object.FetchObject(ctx, secretKey, h.client, &corev1.Secret{}) - if err != nil { - return err - } - - if provisioner != nil { - vmSnapshot.Status.Resources = append(vmSnapshot.Status.Resources, virtv2.ResourceRef{ - Kind: provisioner.Kind, - ApiVersion: provisioner.APIVersion, - Name: provisioner.Name, - }) - } - } + provisioner, err := h.getProvisionerFromVM(ctx, vm) + if err != nil { + return err + } + if provisioner != nil { + vmSnapshot.Status.Resources = append(vmSnapshot.Status.Resources, virtv2.ResourceRef{ + Kind: provisioner.Kind, + ApiVersion: provisioner.APIVersion, + Name: provisioner.Name, + }) } for _, bdr := range vm.Status.BlockDeviceRefs { @@ -767,3 +739,39 @@ func (h LifeCycleHandler) fillStatusResources(ctx context.Context, vmSnapshot *v return nil } + +func (h LifeCycleHandler) getProvisionerFromVM(ctx context.Context, vm *virtv2.VirtualMachine) (*corev1.Secret, error) { + if vm.Spec.Provisioning != nil { + var provisioningSecretName string + + switch vm.Spec.Provisioning.Type { + case virtv2.ProvisioningTypeSysprepRef: + if vm.Spec.Provisioning.SysprepRef == nil { + return nil, nil + } + + if vm.Spec.Provisioning.SysprepRef.Kind == virtv2.SysprepRefKindSecret { + provisioningSecretName = vm.Spec.Provisioning.SysprepRef.Name + } + + case virtv2.ProvisioningTypeUserDataRef: + if vm.Spec.Provisioning.UserDataRef == nil { + return nil, nil + } + + if vm.Spec.Provisioning.UserDataRef.Kind == virtv2.UserDataRefKindSecret { + provisioningSecretName = vm.Spec.Provisioning.UserDataRef.Name + } + } + + if provisioningSecretName != "" { + secretKey := types.NamespacedName{Name: provisioningSecretName, Namespace: vm.Namespace} + provisioner, err := object.FetchObject(ctx, secretKey, h.client, &corev1.Secret{}) + return provisioner, err + } else { + return nil, nil + } + } else { + return nil, nil + } +} From d5803467abe56025313498f863c6778c6dca42f7 Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Tue, 29 Apr 2025 12:08:48 +0300 Subject: [PATCH 6/8] doc Signed-off-by: Valeriy Khorunzhin --- crds/doc-ru-virtualmachinesnapshots.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crds/doc-ru-virtualmachinesnapshots.yaml b/crds/doc-ru-virtualmachinesnapshots.yaml index 23551ab8a5..5f465ecad6 100644 --- a/crds/doc-ru-virtualmachinesnapshots.yaml +++ b/crds/doc-ru-virtualmachinesnapshots.yaml @@ -69,6 +69,8 @@ spec: * `Ready` — создание снимка успешно завершено, и он доступен для использования; * `Failed` — во время создания снимка виртуальной машины произошла ошибка; * `Terminating` — ресурс находится в процессе удаления. + resources: + description: Список ресурсов снимка. virtualDiskSnapshotNames: description: Имена созданных снимков виртуальных дисков. virtualMachineSnapshotSecretName: From 757a9476f6d1b16b9a66d4d03d54e9c783193ef1 Mon Sep 17 00:00:00 2001 From: Max Chervov Date: Wed, 30 Apr 2025 11:15:15 +0300 Subject: [PATCH 7/8] Minor description edits Signed-off-by: Max Chervov --- crds/virtualmachinesnapshots.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crds/virtualmachinesnapshots.yaml b/crds/virtualmachinesnapshots.yaml index dfcfbc3598..5fdfbd5581 100644 --- a/crds/virtualmachinesnapshots.yaml +++ b/crds/virtualmachinesnapshots.yaml @@ -196,17 +196,17 @@ spec: - Terminating type: string resources: - description: Snapshotted resource list + description: List of snapshot resources. items: properties: apiVersion: - description: Api version of resource + description: API version of the resource. type: string kind: - description: Kind of resource + description: Kind of the resource. type: string name: - description: Resource Name + description: Name of the resource. type: string type: object type: array From c5c1b06b34320a239af11c16d298c3ad30e0a39b Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Wed, 30 Apr 2025 17:39:58 +0300 Subject: [PATCH 8/8] resolve Signed-off-by: Valeriy Khorunzhin --- api/core/v1alpha2/virtual_machine_snapshot.go | 2 +- .../pkg/controller/vmsnapshot/internal/life_cycle_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api/core/v1alpha2/virtual_machine_snapshot.go b/api/core/v1alpha2/virtual_machine_snapshot.go index a329fd15be..5f9d768adc 100644 --- a/api/core/v1alpha2/virtual_machine_snapshot.go +++ b/api/core/v1alpha2/virtual_machine_snapshot.go @@ -89,7 +89,7 @@ type VirtualMachineSnapshotStatus struct { VirtualMachineSnapshotSecretName string `json:"virtualMachineSnapshotSecretName,omitempty"` // List of VirtualDiskSnapshot names for the snapshots taken from the virtual disks of the associated virtual machine. VirtualDiskSnapshotNames []string `json:"virtualDiskSnapshotNames,omitempty"` - // Snapshotted resource list + // List of snapshot resources. Resources []ResourceRef `json:"resources,omitempty"` // The latest detailed observations of the VirtualMachineSnapshot resource. Conditions []metav1.Condition `json:"conditions,omitempty"` diff --git a/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle_test.go b/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle_test.go index 6435200752..63e163b999 100644 --- a/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle_test.go +++ b/images/virtualization-artifact/pkg/controller/vmsnapshot/internal/life_cycle_test.go @@ -146,7 +146,7 @@ var _ = Describe("LifeCycle handler", func() { var err error fakeClient, err = testutil.NewFakeClientWithObjects(vd, vm, secret, vmSnapshot, vdSnapshot) - Expect(err).ShouldNot(HaveOccurred()) + Expect(err).NotTo(HaveOccurred()) recorder = &eventrecord.EventRecorderLoggerMock{ EventFunc: func(_ client.Object, _, _, _ string) {},