From 6f7529972ba01b58512d707886b1a99b43c9ed9e Mon Sep 17 00:00:00 2001 From: Roman Sysoev Date: Tue, 19 May 2026 16:55:23 +0300 Subject: [PATCH] chore(api): remove deprecated VirtualMachineRestore resource The VirtualMachineRestore resource is deprecated and should be fully removed. Use VirtualMachineOperation with type Restore/Clone instead. This commit removes: - The vmrestore controller and all its internal components - The VirtualMachineRestore API type and CRD - Related indexers, webhooks, and annotations Signed-off-by: Roman Sysoev --- .../typed/core/v1alpha2/core_client.go | 5 - .../core/v1alpha2/fake/fake_core_client.go | 4 - .../fake/fake_virtualmachinerestore.go | 52 -- .../core/v1alpha2/generated_expansion.go | 2 - .../core/v1alpha2/virtualmachinerestore.go | 70 -- .../core/v1alpha2/interface.go | 7 - .../core/v1alpha2/virtualmachinerestore.go | 102 --- .../informers/externalversions/generic.go | 2 - .../core/v1alpha2/expansion_generated.go | 8 - .../core/v1alpha2/virtualmachinerestore.go | 70 -- api/core/v1alpha2/common_types.go | 36 + api/core/v1alpha2/register.go | 2 - api/core/v1alpha2/virtual_machine_restore.go | 124 ---- .../vm-restore-condition/condition.go | 68 -- api/core/v1alpha2/zz_generated.deepcopy.go | 105 --- api/scripts/update-codegen.sh | 1 - crds/doc-ru-virtualmachinerestores.yaml | 70 -- crds/virtualmachinerestores.yaml | 199 ------ .../cmd/virtualization-controller/main.go | 7 - .../pkg/common/annotations/annotations.go | 2 - .../pkg/controller/indexer/indexer.go | 3 - .../controller/indexer/vm_restore_indexer.go | 34 - .../pkg/controller/reconciler/resource.go | 3 - .../vmrestore/internal/handler_test.go | 37 - .../vmrestore/internal/interfaces.go | 36 - .../vmrestore/internal/life_cycle.go | 650 ------------------ .../vmrestore/internal/life_cycle_test.go | 152 ---- .../pkg/controller/vmrestore/internal/mock.go | 333 --------- .../vmrestore/internal/restorer/errors.go | 28 - .../vmrestore/internal/restorer/overrider.go | 37 - .../internal/restorer/provisioner_restorer.go | 102 --- .../internal/restorer/vd_restorer.go | 154 ----- .../internal/restorer/vm_restorer.go | 159 ----- .../internal/restorer/vmbda_restorer.go | 126 ---- .../internal/restorer/vmip_restorer.go | 175 ----- .../internal/restorer/vmmac_restorer.go | 171 ----- .../internal/vm_snapshot_ready_to_use.go | 100 --- .../internal/watcher/kvvm_watcher.go | 111 --- .../vmrestore/internal/watcher/vd_watcher.go | 116 ---- .../vmrestore/internal/watcher/vm_watcher.go | 108 --- .../internal/watcher/vmbda_watcher.go | 137 ---- .../internal/watcher/vmrestore_watcher.go | 64 -- .../internal/watcher/vmsnapshot_watcher.go | 86 --- .../vmrestore/vmrestore_controller.go | 76 -- .../vmrestore/vmrestore_reconciler.go | 105 --- .../controller/vmrestore/vmrestore_webhook.go | 64 -- .../validation-webhook.yaml | 17 - 47 files changed, 36 insertions(+), 4084 deletions(-) delete mode 100644 api/client/generated/clientset/versioned/typed/core/v1alpha2/fake/fake_virtualmachinerestore.go delete mode 100644 api/client/generated/clientset/versioned/typed/core/v1alpha2/virtualmachinerestore.go delete mode 100644 api/client/generated/informers/externalversions/core/v1alpha2/virtualmachinerestore.go delete mode 100644 api/client/generated/listers/core/v1alpha2/virtualmachinerestore.go create mode 100644 api/core/v1alpha2/common_types.go delete mode 100644 api/core/v1alpha2/virtual_machine_restore.go delete mode 100644 api/core/v1alpha2/vm-restore-condition/condition.go delete mode 100644 crds/doc-ru-virtualmachinerestores.yaml delete mode 100644 crds/virtualmachinerestores.yaml delete mode 100644 images/virtualization-artifact/pkg/controller/indexer/vm_restore_indexer.go delete mode 100644 images/virtualization-artifact/pkg/controller/vmrestore/internal/handler_test.go delete mode 100644 images/virtualization-artifact/pkg/controller/vmrestore/internal/interfaces.go delete mode 100644 images/virtualization-artifact/pkg/controller/vmrestore/internal/life_cycle.go delete mode 100644 images/virtualization-artifact/pkg/controller/vmrestore/internal/life_cycle_test.go delete mode 100644 images/virtualization-artifact/pkg/controller/vmrestore/internal/mock.go delete mode 100644 images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/errors.go delete mode 100644 images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/overrider.go delete mode 100644 images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/provisioner_restorer.go delete mode 100644 images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/vd_restorer.go delete mode 100644 images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/vm_restorer.go delete mode 100644 images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/vmbda_restorer.go delete mode 100644 images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/vmip_restorer.go delete mode 100644 images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/vmmac_restorer.go delete mode 100644 images/virtualization-artifact/pkg/controller/vmrestore/internal/vm_snapshot_ready_to_use.go delete mode 100644 images/virtualization-artifact/pkg/controller/vmrestore/internal/watcher/kvvm_watcher.go delete mode 100644 images/virtualization-artifact/pkg/controller/vmrestore/internal/watcher/vd_watcher.go delete mode 100644 images/virtualization-artifact/pkg/controller/vmrestore/internal/watcher/vm_watcher.go delete mode 100644 images/virtualization-artifact/pkg/controller/vmrestore/internal/watcher/vmbda_watcher.go delete mode 100644 images/virtualization-artifact/pkg/controller/vmrestore/internal/watcher/vmrestore_watcher.go delete mode 100644 images/virtualization-artifact/pkg/controller/vmrestore/internal/watcher/vmsnapshot_watcher.go delete mode 100644 images/virtualization-artifact/pkg/controller/vmrestore/vmrestore_controller.go delete mode 100644 images/virtualization-artifact/pkg/controller/vmrestore/vmrestore_reconciler.go delete mode 100644 images/virtualization-artifact/pkg/controller/vmrestore/vmrestore_webhook.go diff --git a/api/client/generated/clientset/versioned/typed/core/v1alpha2/core_client.go b/api/client/generated/clientset/versioned/typed/core/v1alpha2/core_client.go index b47950fbe2..95d9f09723 100644 --- a/api/client/generated/clientset/versioned/typed/core/v1alpha2/core_client.go +++ b/api/client/generated/clientset/versioned/typed/core/v1alpha2/core_client.go @@ -42,7 +42,6 @@ type VirtualizationV1alpha2Interface interface { VirtualMachineMACAddressesGetter VirtualMachineMACAddressLeasesGetter VirtualMachineOperationsGetter - VirtualMachineRestoresGetter VirtualMachineSnapshotsGetter VirtualMachineSnapshotOperationsGetter } @@ -108,10 +107,6 @@ func (c *VirtualizationV1alpha2Client) VirtualMachineOperations(namespace string return newVirtualMachineOperations(c, namespace) } -func (c *VirtualizationV1alpha2Client) VirtualMachineRestores(namespace string) VirtualMachineRestoreInterface { - return newVirtualMachineRestores(c, namespace) -} - func (c *VirtualizationV1alpha2Client) VirtualMachineSnapshots(namespace string) VirtualMachineSnapshotInterface { return newVirtualMachineSnapshots(c, namespace) } diff --git a/api/client/generated/clientset/versioned/typed/core/v1alpha2/fake/fake_core_client.go b/api/client/generated/clientset/versioned/typed/core/v1alpha2/fake/fake_core_client.go index 94396c30e7..3e4d10a08e 100644 --- a/api/client/generated/clientset/versioned/typed/core/v1alpha2/fake/fake_core_client.go +++ b/api/client/generated/clientset/versioned/typed/core/v1alpha2/fake/fake_core_client.go @@ -84,10 +84,6 @@ func (c *FakeVirtualizationV1alpha2) VirtualMachineOperations(namespace string) return newFakeVirtualMachineOperations(c, namespace) } -func (c *FakeVirtualizationV1alpha2) VirtualMachineRestores(namespace string) v1alpha2.VirtualMachineRestoreInterface { - return newFakeVirtualMachineRestores(c, namespace) -} - func (c *FakeVirtualizationV1alpha2) VirtualMachineSnapshots(namespace string) v1alpha2.VirtualMachineSnapshotInterface { return newFakeVirtualMachineSnapshots(c, namespace) } diff --git a/api/client/generated/clientset/versioned/typed/core/v1alpha2/fake/fake_virtualmachinerestore.go b/api/client/generated/clientset/versioned/typed/core/v1alpha2/fake/fake_virtualmachinerestore.go deleted file mode 100644 index 15a9684d3b..0000000000 --- a/api/client/generated/clientset/versioned/typed/core/v1alpha2/fake/fake_virtualmachinerestore.go +++ /dev/null @@ -1,52 +0,0 @@ -/* -Copyright Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - corev1alpha2 "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned/typed/core/v1alpha2" - v1alpha2 "github.com/deckhouse/virtualization/api/core/v1alpha2" - gentype "k8s.io/client-go/gentype" -) - -// fakeVirtualMachineRestores implements VirtualMachineRestoreInterface -type fakeVirtualMachineRestores struct { - *gentype.FakeClientWithList[*v1alpha2.VirtualMachineRestore, *v1alpha2.VirtualMachineRestoreList] - Fake *FakeVirtualizationV1alpha2 -} - -func newFakeVirtualMachineRestores(fake *FakeVirtualizationV1alpha2, namespace string) corev1alpha2.VirtualMachineRestoreInterface { - return &fakeVirtualMachineRestores{ - gentype.NewFakeClientWithList[*v1alpha2.VirtualMachineRestore, *v1alpha2.VirtualMachineRestoreList]( - fake.Fake, - namespace, - v1alpha2.SchemeGroupVersion.WithResource("virtualmachinerestores"), - v1alpha2.SchemeGroupVersion.WithKind("VirtualMachineRestore"), - func() *v1alpha2.VirtualMachineRestore { return &v1alpha2.VirtualMachineRestore{} }, - func() *v1alpha2.VirtualMachineRestoreList { return &v1alpha2.VirtualMachineRestoreList{} }, - func(dst, src *v1alpha2.VirtualMachineRestoreList) { dst.ListMeta = src.ListMeta }, - func(list *v1alpha2.VirtualMachineRestoreList) []*v1alpha2.VirtualMachineRestore { - return gentype.ToPointerSlice(list.Items) - }, - func(list *v1alpha2.VirtualMachineRestoreList, items []*v1alpha2.VirtualMachineRestore) { - list.Items = gentype.FromPointerSlice(items) - }, - ), - fake, - } -} diff --git a/api/client/generated/clientset/versioned/typed/core/v1alpha2/generated_expansion.go b/api/client/generated/clientset/versioned/typed/core/v1alpha2/generated_expansion.go index 03f1be734a..3032ee8501 100644 --- a/api/client/generated/clientset/versioned/typed/core/v1alpha2/generated_expansion.go +++ b/api/client/generated/clientset/versioned/typed/core/v1alpha2/generated_expansion.go @@ -44,8 +44,6 @@ type VirtualMachineMACAddressLeaseExpansion interface{} type VirtualMachineOperationExpansion interface{} -type VirtualMachineRestoreExpansion interface{} - type VirtualMachineSnapshotExpansion interface{} type VirtualMachineSnapshotOperationExpansion interface{} diff --git a/api/client/generated/clientset/versioned/typed/core/v1alpha2/virtualmachinerestore.go b/api/client/generated/clientset/versioned/typed/core/v1alpha2/virtualmachinerestore.go deleted file mode 100644 index 988a0a6911..0000000000 --- a/api/client/generated/clientset/versioned/typed/core/v1alpha2/virtualmachinerestore.go +++ /dev/null @@ -1,70 +0,0 @@ -/* -Copyright Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package v1alpha2 - -import ( - context "context" - - scheme "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned/scheme" - corev1alpha2 "github.com/deckhouse/virtualization/api/core/v1alpha2" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - gentype "k8s.io/client-go/gentype" -) - -// VirtualMachineRestoresGetter has a method to return a VirtualMachineRestoreInterface. -// A group's client should implement this interface. -type VirtualMachineRestoresGetter interface { - VirtualMachineRestores(namespace string) VirtualMachineRestoreInterface -} - -// VirtualMachineRestoreInterface has methods to work with VirtualMachineRestore resources. -type VirtualMachineRestoreInterface interface { - Create(ctx context.Context, virtualMachineRestore *corev1alpha2.VirtualMachineRestore, opts v1.CreateOptions) (*corev1alpha2.VirtualMachineRestore, error) - Update(ctx context.Context, virtualMachineRestore *corev1alpha2.VirtualMachineRestore, opts v1.UpdateOptions) (*corev1alpha2.VirtualMachineRestore, error) - // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). - UpdateStatus(ctx context.Context, virtualMachineRestore *corev1alpha2.VirtualMachineRestore, opts v1.UpdateOptions) (*corev1alpha2.VirtualMachineRestore, error) - Delete(ctx context.Context, name string, opts v1.DeleteOptions) error - DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error - Get(ctx context.Context, name string, opts v1.GetOptions) (*corev1alpha2.VirtualMachineRestore, error) - List(ctx context.Context, opts v1.ListOptions) (*corev1alpha2.VirtualMachineRestoreList, error) - Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) - Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *corev1alpha2.VirtualMachineRestore, err error) - VirtualMachineRestoreExpansion -} - -// virtualMachineRestores implements VirtualMachineRestoreInterface -type virtualMachineRestores struct { - *gentype.ClientWithList[*corev1alpha2.VirtualMachineRestore, *corev1alpha2.VirtualMachineRestoreList] -} - -// newVirtualMachineRestores returns a VirtualMachineRestores -func newVirtualMachineRestores(c *VirtualizationV1alpha2Client, namespace string) *virtualMachineRestores { - return &virtualMachineRestores{ - gentype.NewClientWithList[*corev1alpha2.VirtualMachineRestore, *corev1alpha2.VirtualMachineRestoreList]( - "virtualmachinerestores", - c.RESTClient(), - scheme.ParameterCodec, - namespace, - func() *corev1alpha2.VirtualMachineRestore { return &corev1alpha2.VirtualMachineRestore{} }, - func() *corev1alpha2.VirtualMachineRestoreList { return &corev1alpha2.VirtualMachineRestoreList{} }, - ), - } -} diff --git a/api/client/generated/informers/externalversions/core/v1alpha2/interface.go b/api/client/generated/informers/externalversions/core/v1alpha2/interface.go index 419b47e1b8..ed97a49b94 100644 --- a/api/client/generated/informers/externalversions/core/v1alpha2/interface.go +++ b/api/client/generated/informers/externalversions/core/v1alpha2/interface.go @@ -52,8 +52,6 @@ type Interface interface { VirtualMachineMACAddressLeases() VirtualMachineMACAddressLeaseInformer // VirtualMachineOperations returns a VirtualMachineOperationInformer. VirtualMachineOperations() VirtualMachineOperationInformer - // VirtualMachineRestores returns a VirtualMachineRestoreInformer. - VirtualMachineRestores() VirtualMachineRestoreInformer // VirtualMachineSnapshots returns a VirtualMachineSnapshotInformer. VirtualMachineSnapshots() VirtualMachineSnapshotInformer // VirtualMachineSnapshotOperations returns a VirtualMachineSnapshotOperationInformer. @@ -141,11 +139,6 @@ func (v *version) VirtualMachineOperations() VirtualMachineOperationInformer { return &virtualMachineOperationInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } -// VirtualMachineRestores returns a VirtualMachineRestoreInformer. -func (v *version) VirtualMachineRestores() VirtualMachineRestoreInformer { - return &virtualMachineRestoreInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} -} - // VirtualMachineSnapshots returns a VirtualMachineSnapshotInformer. func (v *version) VirtualMachineSnapshots() VirtualMachineSnapshotInformer { return &virtualMachineSnapshotInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} diff --git a/api/client/generated/informers/externalversions/core/v1alpha2/virtualmachinerestore.go b/api/client/generated/informers/externalversions/core/v1alpha2/virtualmachinerestore.go deleted file mode 100644 index c2c62b62e7..0000000000 --- a/api/client/generated/informers/externalversions/core/v1alpha2/virtualmachinerestore.go +++ /dev/null @@ -1,102 +0,0 @@ -/* -Copyright Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package v1alpha2 - -import ( - context "context" - time "time" - - versioned "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned" - internalinterfaces "github.com/deckhouse/virtualization/api/client/generated/informers/externalversions/internalinterfaces" - corev1alpha2 "github.com/deckhouse/virtualization/api/client/generated/listers/core/v1alpha2" - apicorev1alpha2 "github.com/deckhouse/virtualization/api/core/v1alpha2" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - watch "k8s.io/apimachinery/pkg/watch" - cache "k8s.io/client-go/tools/cache" -) - -// VirtualMachineRestoreInformer provides access to a shared informer and lister for -// VirtualMachineRestores. -type VirtualMachineRestoreInformer interface { - Informer() cache.SharedIndexInformer - Lister() corev1alpha2.VirtualMachineRestoreLister -} - -type virtualMachineRestoreInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc - namespace string -} - -// NewVirtualMachineRestoreInformer constructs a new informer for VirtualMachineRestore type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewVirtualMachineRestoreInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredVirtualMachineRestoreInformer(client, namespace, resyncPeriod, indexers, nil) -} - -// NewFilteredVirtualMachineRestoreInformer constructs a new informer for VirtualMachineRestore type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewFilteredVirtualMachineRestoreInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { - return cache.NewSharedIndexInformer( - &cache.ListWatch{ - ListFunc: func(options v1.ListOptions) (runtime.Object, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.VirtualizationV1alpha2().VirtualMachineRestores(namespace).List(context.Background(), options) - }, - WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.VirtualizationV1alpha2().VirtualMachineRestores(namespace).Watch(context.Background(), options) - }, - ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.VirtualizationV1alpha2().VirtualMachineRestores(namespace).List(ctx, options) - }, - WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.VirtualizationV1alpha2().VirtualMachineRestores(namespace).Watch(ctx, options) - }, - }, - &apicorev1alpha2.VirtualMachineRestore{}, - resyncPeriod, - indexers, - ) -} - -func (f *virtualMachineRestoreInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredVirtualMachineRestoreInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *virtualMachineRestoreInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&apicorev1alpha2.VirtualMachineRestore{}, f.defaultInformer) -} - -func (f *virtualMachineRestoreInformer) Lister() corev1alpha2.VirtualMachineRestoreLister { - return corev1alpha2.NewVirtualMachineRestoreLister(f.Informer().GetIndexer()) -} diff --git a/api/client/generated/informers/externalversions/generic.go b/api/client/generated/informers/externalversions/generic.go index e8663a0736..8b16f3d58a 100644 --- a/api/client/generated/informers/externalversions/generic.go +++ b/api/client/generated/informers/externalversions/generic.go @@ -82,8 +82,6 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource return &genericInformer{resource: resource.GroupResource(), informer: f.Virtualization().V1alpha2().VirtualMachineMACAddressLeases().Informer()}, nil case v1alpha2.SchemeGroupVersion.WithResource("virtualmachineoperations"): return &genericInformer{resource: resource.GroupResource(), informer: f.Virtualization().V1alpha2().VirtualMachineOperations().Informer()}, nil - case v1alpha2.SchemeGroupVersion.WithResource("virtualmachinerestores"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Virtualization().V1alpha2().VirtualMachineRestores().Informer()}, nil case v1alpha2.SchemeGroupVersion.WithResource("virtualmachinesnapshots"): return &genericInformer{resource: resource.GroupResource(), informer: f.Virtualization().V1alpha2().VirtualMachineSnapshots().Informer()}, nil case v1alpha2.SchemeGroupVersion.WithResource("virtualmachinesnapshotoperations"): diff --git a/api/client/generated/listers/core/v1alpha2/expansion_generated.go b/api/client/generated/listers/core/v1alpha2/expansion_generated.go index 81d6c1fefb..e47e2ae835 100644 --- a/api/client/generated/listers/core/v1alpha2/expansion_generated.go +++ b/api/client/generated/listers/core/v1alpha2/expansion_generated.go @@ -110,14 +110,6 @@ type VirtualMachineOperationListerExpansion interface{} // VirtualMachineOperationNamespaceLister. type VirtualMachineOperationNamespaceListerExpansion interface{} -// VirtualMachineRestoreListerExpansion allows custom methods to be added to -// VirtualMachineRestoreLister. -type VirtualMachineRestoreListerExpansion interface{} - -// VirtualMachineRestoreNamespaceListerExpansion allows custom methods to be added to -// VirtualMachineRestoreNamespaceLister. -type VirtualMachineRestoreNamespaceListerExpansion interface{} - // VirtualMachineSnapshotListerExpansion allows custom methods to be added to // VirtualMachineSnapshotLister. type VirtualMachineSnapshotListerExpansion interface{} diff --git a/api/client/generated/listers/core/v1alpha2/virtualmachinerestore.go b/api/client/generated/listers/core/v1alpha2/virtualmachinerestore.go deleted file mode 100644 index 2d1d2144d0..0000000000 --- a/api/client/generated/listers/core/v1alpha2/virtualmachinerestore.go +++ /dev/null @@ -1,70 +0,0 @@ -/* -Copyright Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by lister-gen. DO NOT EDIT. - -package v1alpha2 - -import ( - corev1alpha2 "github.com/deckhouse/virtualization/api/core/v1alpha2" - labels "k8s.io/apimachinery/pkg/labels" - listers "k8s.io/client-go/listers" - cache "k8s.io/client-go/tools/cache" -) - -// VirtualMachineRestoreLister helps list VirtualMachineRestores. -// All objects returned here must be treated as read-only. -type VirtualMachineRestoreLister interface { - // List lists all VirtualMachineRestores in the indexer. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*corev1alpha2.VirtualMachineRestore, err error) - // VirtualMachineRestores returns an object that can list and get VirtualMachineRestores. - VirtualMachineRestores(namespace string) VirtualMachineRestoreNamespaceLister - VirtualMachineRestoreListerExpansion -} - -// virtualMachineRestoreLister implements the VirtualMachineRestoreLister interface. -type virtualMachineRestoreLister struct { - listers.ResourceIndexer[*corev1alpha2.VirtualMachineRestore] -} - -// NewVirtualMachineRestoreLister returns a new VirtualMachineRestoreLister. -func NewVirtualMachineRestoreLister(indexer cache.Indexer) VirtualMachineRestoreLister { - return &virtualMachineRestoreLister{listers.New[*corev1alpha2.VirtualMachineRestore](indexer, corev1alpha2.Resource("virtualmachinerestore"))} -} - -// VirtualMachineRestores returns an object that can list and get VirtualMachineRestores. -func (s *virtualMachineRestoreLister) VirtualMachineRestores(namespace string) VirtualMachineRestoreNamespaceLister { - return virtualMachineRestoreNamespaceLister{listers.NewNamespaced[*corev1alpha2.VirtualMachineRestore](s.ResourceIndexer, namespace)} -} - -// VirtualMachineRestoreNamespaceLister helps list and get VirtualMachineRestores. -// All objects returned here must be treated as read-only. -type VirtualMachineRestoreNamespaceLister interface { - // List lists all VirtualMachineRestores in the indexer for a given namespace. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*corev1alpha2.VirtualMachineRestore, err error) - // Get retrieves the VirtualMachineRestore from the indexer for a given namespace and name. - // Objects returned here must be treated as read-only. - Get(name string) (*corev1alpha2.VirtualMachineRestore, error) - VirtualMachineRestoreNamespaceListerExpansion -} - -// virtualMachineRestoreNamespaceLister implements the VirtualMachineRestoreNamespaceLister -// interface. -type virtualMachineRestoreNamespaceLister struct { - listers.ResourceIndexer[*corev1alpha2.VirtualMachineRestore] -} diff --git a/api/core/v1alpha2/common_types.go b/api/core/v1alpha2/common_types.go new file mode 100644 index 0000000000..67b275b9e2 --- /dev/null +++ b/api/core/v1alpha2/common_types.go @@ -0,0 +1,36 @@ +/* +Copyright 2024 Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha2 + +// NameReplacement represents a rule for redefining the virtual machine resource names. +type NameReplacement struct { + // Selector to choose resources for name replacement. + From NameReplacementFrom `json:"from"` + // New resource name. + // +kubebuilder:validation:MinLength=1 + To string `json:"to"` +} + +// NameReplacementFrom represents a selector to choose resources for name replacement. +type NameReplacementFrom struct { + // Kind of a resource to rename. + // +kubebuilder:validation:MinLength=1 + Kind string `json:"kind,omitempty"` + // Current name of a resource to rename. + // +kubebuilder:validation:MinLength=1 + Name string `json:"name"` +} \ No newline at end of file diff --git a/api/core/v1alpha2/register.go b/api/core/v1alpha2/register.go index 9ef8a57678..821755d18f 100644 --- a/api/core/v1alpha2/register.go +++ b/api/core/v1alpha2/register.go @@ -86,8 +86,6 @@ func addKnownTypes(scheme *runtime.Scheme) error { &VirtualMachineSnapshotList{}, &VirtualMachineSnapshotOperation{}, &VirtualMachineSnapshotOperationList{}, - &VirtualMachineRestore{}, - &VirtualMachineRestoreList{}, &VirtualMachineMACAddress{}, &VirtualMachineMACAddressList{}, &VirtualMachineMACAddressLease{}, diff --git a/api/core/v1alpha2/virtual_machine_restore.go b/api/core/v1alpha2/virtual_machine_restore.go deleted file mode 100644 index 42d6516f8d..0000000000 --- a/api/core/v1alpha2/virtual_machine_restore.go +++ /dev/null @@ -1,124 +0,0 @@ -/* -Copyright 2024 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// +kubebuilder:object:generate=true -// +groupName=virtualization.deckhouse.io -package v1alpha2 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -const ( - VirtualMachineRestoreKind = "VirtualMachineRestore" - VirtualMachineRestoreResource = "virtualmachinerestores" -) - -// VirtualMachineRestore provides a resource for restoring a virtual machine and all associated resources from a snapshot. -// -// +kubebuilder:deprecatedversion:warning="The VirtualMachineRestore resource is deprecated, consider using VirtualMachineOperation with type Restore/Clone" -// +kubebuilder:object:root=true -// +kubebuilder:metadata:labels={heritage=deckhouse,module=virtualization} -// +kubebuilder:subresource:status -// +kubebuilder:resource:categories=virtualization,scope=Namespaced,shortName={vmrestore},singular=virtualmachinerestore -// +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="VirtualMachineRestore phase." -// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="VirtualMachineRestore age." -// +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -type VirtualMachineRestore struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec VirtualMachineRestoreSpec `json:"spec"` - Status VirtualMachineRestoreStatus `json:"status,omitempty"` -} - -// VirtualMachineRestoreList contains a list of VirtualMachineRestore resources. -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -type VirtualMachineRestoreList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata"` - Items []VirtualMachineRestore `json:"items"` -} - -type VirtualMachineRestoreSpec struct { - // Virtual machine restore mode: - // - // * Safe — in this mode, the virtual machine will not be restored if unresolvable conflicts are detected during the restoration process. - // * Forced — in this mode, the virtual machine configuration will be updated and all associated resources will be recreated. The virtual machine may malfunction if the recovery process fails. Use the mode when you need to restore the virtual machine despite conflicts. - // +kubebuilder:validation:Optional - // +kubebuilder:validation:Enum=Safe;Forced - // +kubebuilder:default:=Safe - RestoreMode RestoreMode `json:"restoreMode,omitempty"` - // Snapshot name to restore a virtual machine from. - // - // +kubebuilder:validation:MinLength=1 - VirtualMachineSnapshotName string `json:"virtualMachineSnapshotName"` - // Renaming conventions for virtual machine resources. - NameReplacements []NameReplacement `json:"nameReplacements,omitempty"` -} - -type VirtualMachineRestoreStatus struct { - Phase VirtualMachineRestorePhase `json:"phase"` - // Contains details of the current API resource state. - Conditions []metav1.Condition `json:"conditions,omitempty"` - // Resource generation last processed by the controller. - ObservedGeneration int64 `json:"observedGeneration,omitempty"` -} - -// NameReplacement represents a rule for redefining the virtual machine resource names. -type NameReplacement struct { - // Selector to choose resources for name replacement. - From NameReplacementFrom `json:"from"` - // New resource name. - // +kubebuilder:validation:MinLength=1 - To string `json:"to"` -} - -// NameReplacementFrom represents a selector to choose resources for name replacement. -type NameReplacementFrom struct { - // Kind of a resource to rename. - // +kubebuilder:validation:MinLength=1 - Kind string `json:"kind,omitempty"` - // Current name of a resource to rename. - // +kubebuilder:validation:MinLength=1 - Name string `json:"name"` -} - -// VirtualMachineRestorePhase defines the current status of a resource: -// * `Pending`: The resource has been created and is on a waiting queue. -// * `InProgress`: A virtual machine is being restored from a snapshot. -// * `Ready`: A virtual machine has been successfully restored from a snapshot. -// * `Failed`: An error occurred when restoring a virtual machine from a snapshot. -// * `Terminating`: The resource is being deleted. -// -// +kubebuilder:validation:Enum={Pending,InProgress,Ready,Failed,Terminating} -type VirtualMachineRestorePhase string - -const ( - VirtualMachineRestorePhasePending VirtualMachineRestorePhase = "Pending" - VirtualMachineRestorePhaseInProgress VirtualMachineRestorePhase = "InProgress" - VirtualMachineRestorePhaseReady VirtualMachineRestorePhase = "Ready" - VirtualMachineRestorePhaseFailed VirtualMachineRestorePhase = "Failed" - VirtualMachineRestorePhaseTerminating VirtualMachineRestorePhase = "Terminating" -) - -type RestoreMode string - -const ( - RestoreModeSafe RestoreMode = "Safe" - RestoreModeForced RestoreMode = "Forced" -) diff --git a/api/core/v1alpha2/vm-restore-condition/condition.go b/api/core/v1alpha2/vm-restore-condition/condition.go deleted file mode 100644 index 6a1c67d240..0000000000 --- a/api/core/v1alpha2/vm-restore-condition/condition.go +++ /dev/null @@ -1,68 +0,0 @@ -/* -Copyright 2024 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package vmrestorecondition - -// Type represents the various condition types for the `VirtualMachineRestore`. -type Type string - -const ( - // VirtualMachineSnapshotReadyToUseType indicates that the virtual machine snapshot has been successfully taken and is ready for restore. - VirtualMachineSnapshotReadyToUseType Type = "VirtualMachineSnapshotReadyToUse" - // VirtualMachineRestoreReadyType indicates that the virtual machine restore has been successfully completed. - VirtualMachineRestoreReadyType Type = "VirtualMachineRestoreReady" -) - -type ( - // VirtualMachineSnapshotReadyToUseReason represents the various reasons for the `VirtualMachineSnapshotReadyToUse` condition type. - VirtualMachineSnapshotReadyToUseReason string - // VirtualMachineRestoreReadyReason represents the various reasons for the `VirtualMachineRestoreReady` condition type. - VirtualMachineRestoreReadyReason string -) - -const ( - // VirtualMachineSnapshotNotFound indicates that the specified virtual machine snapshot is absent. - VirtualMachineSnapshotNotFound VirtualMachineSnapshotReadyToUseReason = "VirtualMachineSnapshotNotFound" - // VirtualMachineSnapshotNotReady indicates that the specified virtual machine snapshot is not ready, or resources, such as virtual images to be restored, are not present in the cluster. - VirtualMachineSnapshotNotReady VirtualMachineSnapshotReadyToUseReason = "VirtualMachineSnapshotNotReady" - // VirtualMachineSnapshotReadyToUse indicates that the specified virtual machine snapshot is ready to restore. - VirtualMachineSnapshotReadyToUse VirtualMachineSnapshotReadyToUseReason = "VirtualMachineSnapshotReadyToUse" - - // VirtualMachineResourcesAreNotReady signifies that the virtual machine resources is not ready to the `force` restoration. - VirtualMachineResourcesAreNotReady VirtualMachineRestoreReadyReason = "VirtualMachineResourcesAreNotReady" - // VirtualMachineIsNotStopped signifies that the virtual machine is not ready to the `force` restoration. - VirtualMachineIsNotStopped VirtualMachineRestoreReadyReason = "VirtualMachineIsNotStopped" - // VirtualMachineSnapshotNotReadyToUse signifies that the virtual machine snapshot is not ready to use. - VirtualMachineSnapshotNotReadyToUse VirtualMachineRestoreReadyReason = "VirtualMachineSnapshotNotReadyToUse" - // VirtualMachineRestoreConflict signifies that the virtual machine cannot be restored as it's resources already exist. - VirtualMachineRestoreConflict VirtualMachineRestoreReadyReason = "VirtualMachineRestoreConflict" - // VirtualMachineRestoreFailed signifies that the restore process has failed. - VirtualMachineRestoreFailed VirtualMachineRestoreReadyReason = "VirtualMachineRestoreFailed" - // VirtualMachineRestoreReady signifies that the restore process is completed. - VirtualMachineRestoreReady VirtualMachineRestoreReadyReason = "VirtualMachineRestoreReady" -) - -func (t Type) String() string { - return string(t) -} - -func (r VirtualMachineSnapshotReadyToUseReason) String() string { - return string(r) -} - -func (r VirtualMachineRestoreReadyReason) String() string { - return string(r) -} diff --git a/api/core/v1alpha2/zz_generated.deepcopy.go b/api/core/v1alpha2/zz_generated.deepcopy.go index 8c6001319b..4908d29015 100644 --- a/api/core/v1alpha2/zz_generated.deepcopy.go +++ b/api/core/v1alpha2/zz_generated.deepcopy.go @@ -3064,111 +3064,6 @@ func (in *VirtualMachinePod) DeepCopy() *VirtualMachinePod { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *VirtualMachineRestore) DeepCopyInto(out *VirtualMachineRestore) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtualMachineRestore. -func (in *VirtualMachineRestore) DeepCopy() *VirtualMachineRestore { - if in == nil { - return nil - } - out := new(VirtualMachineRestore) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *VirtualMachineRestore) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *VirtualMachineRestoreList) DeepCopyInto(out *VirtualMachineRestoreList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]VirtualMachineRestore, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtualMachineRestoreList. -func (in *VirtualMachineRestoreList) DeepCopy() *VirtualMachineRestoreList { - if in == nil { - return nil - } - out := new(VirtualMachineRestoreList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *VirtualMachineRestoreList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *VirtualMachineRestoreSpec) DeepCopyInto(out *VirtualMachineRestoreSpec) { - *out = *in - if in.NameReplacements != nil { - in, out := &in.NameReplacements, &out.NameReplacements - *out = make([]NameReplacement, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtualMachineRestoreSpec. -func (in *VirtualMachineRestoreSpec) DeepCopy() *VirtualMachineRestoreSpec { - if in == nil { - return nil - } - out := new(VirtualMachineRestoreSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *VirtualMachineRestoreStatus) DeepCopyInto(out *VirtualMachineRestoreStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtualMachineRestoreStatus. -func (in *VirtualMachineRestoreStatus) DeepCopy() *VirtualMachineRestoreStatus { - if in == nil { - return nil - } - out := new(VirtualMachineRestoreStatus) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *VirtualMachineSnapshot) DeepCopyInto(out *VirtualMachineSnapshot) { *out = *in diff --git a/api/scripts/update-codegen.sh b/api/scripts/update-codegen.sh index 905b665369..fccf4f01da 100755 --- a/api/scripts/update-codegen.sh +++ b/api/scripts/update-codegen.sh @@ -35,7 +35,6 @@ function source::settings { ALLOWED_RESOURCE_GEN_CRD=("VirtualMachineClass" "VirtualMachineBlockDeviceAttachment" "VirtualMachineSnapshot" - "VirtualMachineRestore" "VirtualMachineOperation" "VirtualMachineSnapshotOperation" "VirtualDisk" diff --git a/crds/doc-ru-virtualmachinerestores.yaml b/crds/doc-ru-virtualmachinerestores.yaml deleted file mode 100644 index e917125419..0000000000 --- a/crds/doc-ru-virtualmachinerestores.yaml +++ /dev/null @@ -1,70 +0,0 @@ -spec: - versions: - - name: v1alpha2 - schema: - openAPIV3Schema: - description: |- - VirtualMachineRestore предоставляет ресурс для восстановления виртуальных машин из снимков. - properties: - spec: - properties: - restoreMode: - default: Safe - description: |- - Режим восстановления виртуальной машины: - - * Safe — безопасный режим. В этом режиме виртуальная машина не будет восстановлена, если в процессе восстановления будут обнаружены неразрешимые конфликты. - * Forced — режим принудительного восстановления. В этом режиме конфигурация виртуальной машины будет обновлена, а все связанные ресурсы будут пересозданы. Работа виртуальной машины может быть нарушена, если процесс восстановления завершится неудачно. Используйте, когда необходимо восстановить виртуальную машину несмотря на конфликты. - type: string - nameReplacements: - description: Правила переименования ресурсов виртуальной машины. - items: - description: | - NameReplacement представляет собой правило для переопределения имён ресурсов виртуальной машины. - properties: - from: - description: Селектор для выбора ресурсов для переименования. - properties: - kind: - description: Тип ресурса. - name: - description: Имя ресурса, которое нужно переименовать. - to: - description: Новое имя ресурса. - virtualMachineSnapshotName: - description: Имя снимка для восстановления виртуальной машины. - status: - properties: - conditions: - description: | - Последнее подтверждённое состояние данного ресурса. - items: - description: | - Подробные сведения об одном аспекте текущего состояния данного API-ресурса. - properties: - lastTransitionTime: - description: Время перехода условия из одного состояния в другое. - message: - description: Удобочитаемое сообщение с подробной информацией о последнем переходе. - observedGeneration: - description: | - `.metadata.generation`, на основе которого было установлено условие. - Например, если `.metadata.generation` в настоящее время имеет значение `12`, а `.status.conditions[x].observedgeneration` имеет значение `9`, то условие устарело. - reason: - description: Краткая причина последнего перехода состояния. - status: - description: | - Статус условия. Возможные значения: `True`, `False`, `Unknown`. - type: - description: Тип условия. - observedGeneration: - description: Поколение ресурса, которое в последний раз обрабатывалось контроллером. - phase: - description: |- - Текущее состояние ресурса VirtualMachineRestore: - - * `Pending` — ресурс был создан и находится в очереди ожидания; - * `InProgress` — идёт процесс восстановления виртуальной машины из снимка; - * `Ready` — виртуальная машина успешно восстановлена из снимка; - * `Failed` — произошла ошибка во время процесса восстановления виртуальной машины из снимка; - * `Terminating` — ресурс находится в процессе удаления. diff --git a/crds/virtualmachinerestores.yaml b/crds/virtualmachinerestores.yaml deleted file mode 100644 index 0259035ded..0000000000 --- a/crds/virtualmachinerestores.yaml +++ /dev/null @@ -1,199 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.18.0 - labels: - heritage: deckhouse - module: virtualization - name: virtualmachinerestores.virtualization.deckhouse.io -spec: - group: virtualization.deckhouse.io - names: - categories: - - virtualization - kind: VirtualMachineRestore - listKind: VirtualMachineRestoreList - plural: virtualmachinerestores - shortNames: - - vmrestore - singular: virtualmachinerestore - scope: Namespaced - versions: - - additionalPrinterColumns: - - description: VirtualMachineRestore phase. - jsonPath: .status.phase - name: Phase - type: string - - description: VirtualMachineRestore age. - jsonPath: .metadata.creationTimestamp - name: Age - type: date - deprecated: true - deprecationWarning: - The VirtualMachineRestore resource is deprecated, consider - using VirtualMachineOperation with type Restore/Clone - name: v1alpha2 - schema: - openAPIV3Schema: - description: - VirtualMachineRestore provides a resource for restoring a virtual - machine and all associated resources from a snapshot. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - properties: - nameReplacements: - description: Renaming conventions for virtual machine resources. - items: - description: - NameReplacement represents a rule for redefining the - virtual machine resource names. - properties: - from: - description: Selector to choose resources for name replacement. - properties: - kind: - description: Kind of a resource to rename. - minLength: 1 - type: string - name: - description: Current name of a resource to rename. - minLength: 1 - type: string - required: - - name - type: object - to: - description: New resource name. - minLength: 1 - type: string - required: - - from - - to - type: object - type: array - restoreMode: - default: Safe - description: |- - Virtual machine restore mode: - - * Safe — in this mode, the virtual machine will not be restored if unresolvable conflicts are detected during the restoration process. - * Forced — in this mode, the virtual machine configuration will be updated and all associated resources will be recreated. The virtual machine may malfunction if the recovery process fails. Use the mode when you need to restore the virtual machine despite conflicts. - enum: - - Safe - - Forced - type: string - virtualMachineSnapshotName: - description: Snapshot name to restore a virtual machine from. - minLength: 1 - type: string - required: - - virtualMachineSnapshotName - type: object - status: - properties: - conditions: - description: Contains details of the current API resource state. - items: - description: - Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - observedGeneration: - description: Resource generation last processed by the controller. - format: int64 - type: integer - phase: - description: |- - VirtualMachineRestorePhase defines the current status of a resource: - * `Pending`: The resource has been created and is on a waiting queue. - * `InProgress`: A virtual machine is being restored from a snapshot. - * `Ready`: A virtual machine has been successfully restored from a snapshot. - * `Failed`: An error occurred when restoring a virtual machine from a snapshot. - * `Terminating`: The resource is being deleted. - enum: - - Pending - - InProgress - - Ready - - Failed - - Terminating - type: string - required: - - phase - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} diff --git a/images/virtualization-artifact/cmd/virtualization-controller/main.go b/images/virtualization-artifact/cmd/virtualization-controller/main.go index f134d49e3a..d69a9d8d55 100644 --- a/images/virtualization-artifact/cmd/virtualization-controller/main.go +++ b/images/virtualization-artifact/cmd/virtualization-controller/main.go @@ -62,7 +62,6 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/controller/vmmac" "github.com/deckhouse/virtualization-controller/pkg/controller/vmmaclease" "github.com/deckhouse/virtualization-controller/pkg/controller/vmop" - "github.com/deckhouse/virtualization-controller/pkg/controller/vmrestore" "github.com/deckhouse/virtualization-controller/pkg/controller/vmsnapshot" "github.com/deckhouse/virtualization-controller/pkg/controller/vmsop" "github.com/deckhouse/virtualization-controller/pkg/controller/volumemigration" @@ -427,12 +426,6 @@ func main() { os.Exit(1) } - vmrestoreLogger := logger.NewControllerLogger(vmrestore.ControllerName, logLevel, logOutput, logDebugVerbosity, logDebugControllerList) - if err = vmrestore.NewController(ctx, mgr, vmrestoreLogger); err != nil { - log.Error(err.Error()) - os.Exit(1) - } - vmopLogger := logger.NewControllerLogger(vmop.ControllerName, logLevel, logOutput, logDebugVerbosity, logDebugControllerList) if err = vmop.SetupController(ctx, mgr, vmopLogger); err != nil { log.Error(err.Error()) diff --git a/images/virtualization-artifact/pkg/common/annotations/annotations.go b/images/virtualization-artifact/pkg/common/annotations/annotations.go index a487cab2b2..0f62a47acc 100644 --- a/images/virtualization-artifact/pkg/common/annotations/annotations.go +++ b/images/virtualization-artifact/pkg/common/annotations/annotations.go @@ -94,8 +94,6 @@ const ( AnnVMOPWorkloadUpdateImage = AnnAPIGroupV + "/workload-update-image" AnnVMOPWorkloadUpdateNodePlacementSum = AnnAPIGroupV + "/workload-update-node-placement-sum" AnnVMOPWorkloadUpdateHotplugResourcesSum = AnnAPIGroupV + "/workload-update-hotplug-resources-sum" - // AnnVMRestore is an annotation on a resource that indicates it was created by the vmrestore controller; the value is the UID of the `VirtualMachineRestore` resource. - AnnVMRestore = AnnAPIGroupV + "/vmrestore" // AnnVMOPEvacuation is an annotation on vmop that represents a vmop created by evacuation controller AnnVMOPEvacuation = AnnAPIGroupV + "/evacuation" // AnnVMOPVolumeMigration is an annotation on vmop that represents a vmop created by volume-migration controller diff --git a/images/virtualization-artifact/pkg/controller/indexer/indexer.go b/images/virtualization-artifact/pkg/controller/indexer/indexer.go index fe9abac103..6dfd115e74 100644 --- a/images/virtualization-artifact/pkg/controller/indexer/indexer.go +++ b/images/virtualization-artifact/pkg/controller/indexer/indexer.go @@ -53,8 +53,6 @@ const ( IndexFieldVMSnapshotByVM = "spec.virtualMachineName" IndexFieldVMSnapshotByVDSnapshot = "status.virtualDiskSnapshotNames" - IndexFieldVMRestoreByVMSnapshot = "spec.virtualMachineSnapshotName" - IndexFieldVMIPByVM = "status.virtualMachine" IndexFieldVMIPByAddress = "spec.staticIP|status.address" @@ -87,7 +85,6 @@ var IndexGetters = []IndexGetter{ IndexVMByProvisioningSecret, IndexVMSnapshotByVM, IndexVMSnapshotByVDSnapshot, - IndexVMRestoreByVMSnapshot, IndexVMIPByVM, IndexVDByVDSnapshot, IndexVDByStorageClass, diff --git a/images/virtualization-artifact/pkg/controller/indexer/vm_restore_indexer.go b/images/virtualization-artifact/pkg/controller/indexer/vm_restore_indexer.go deleted file mode 100644 index d488b6c05f..0000000000 --- a/images/virtualization-artifact/pkg/controller/indexer/vm_restore_indexer.go +++ /dev/null @@ -1,34 +0,0 @@ -/* -Copyright 2024 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package indexer - -import ( - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/deckhouse/virtualization/api/core/v1alpha2" -) - -func IndexVMRestoreByVMSnapshot() (obj client.Object, field string, extractValue client.IndexerFunc) { - return &v1alpha2.VirtualMachineRestore{}, IndexFieldVMRestoreByVMSnapshot, func(object client.Object) []string { - vmRestore, ok := object.(*v1alpha2.VirtualMachineRestore) - if !ok || vmRestore == nil { - return nil - } - - return []string{vmRestore.Spec.VirtualMachineSnapshotName} - } -} diff --git a/images/virtualization-artifact/pkg/controller/reconciler/resource.go b/images/virtualization-artifact/pkg/controller/reconciler/resource.go index 3507722c04..6fe0929f88 100644 --- a/images/virtualization-artifact/pkg/controller/reconciler/resource.go +++ b/images/virtualization-artifact/pkg/controller/reconciler/resource.go @@ -142,9 +142,6 @@ func rewriteObject(obj client.Object) { case v1alpha2.VirtualMachineClassKind: class := obj.(*v1alpha2.VirtualMachineClass) conds = class.Status.Conditions - case v1alpha2.VirtualMachineRestoreKind: - restore := obj.(*v1alpha2.VirtualMachineRestore) - conds = restore.Status.Conditions case v1alpha2.VirtualMachineSnapshotKind: snap := obj.(*v1alpha2.VirtualMachineSnapshot) conds = snap.Status.Conditions diff --git a/images/virtualization-artifact/pkg/controller/vmrestore/internal/handler_test.go b/images/virtualization-artifact/pkg/controller/vmrestore/internal/handler_test.go deleted file mode 100644 index c8ca88d5b9..0000000000 --- a/images/virtualization-artifact/pkg/controller/vmrestore/internal/handler_test.go +++ /dev/null @@ -1,37 +0,0 @@ -/* -Copyright 2026 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package internal - -import ( - "context" - "log/slog" - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "github.com/deckhouse/virtualization-controller/pkg/logger" -) - -func TestHandlers(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "VMRestore Handlers") -} - -func testContext() context.Context { - return logger.ToContext(context.Background(), slog.Default()) -} diff --git a/images/virtualization-artifact/pkg/controller/vmrestore/internal/interfaces.go b/images/virtualization-artifact/pkg/controller/vmrestore/internal/interfaces.go deleted file mode 100644 index 3e72cf4467..0000000000 --- a/images/virtualization-artifact/pkg/controller/vmrestore/internal/interfaces.go +++ /dev/null @@ -1,36 +0,0 @@ -/* -Copyright 2024 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package internal - -import ( - "context" - - corev1 "k8s.io/api/core/v1" - - "github.com/deckhouse/virtualization/api/core/v1alpha2" -) - -//go:generate go tool moq -rm -out mock.go . Restorer - -type Restorer interface { - RestoreVirtualMachine(ctx context.Context, secret *corev1.Secret) (*v1alpha2.VirtualMachine, error) - RestoreProvisioner(ctx context.Context, secret *corev1.Secret) (*corev1.Secret, error) - RestoreVirtualMachineIPAddress(ctx context.Context, secret *corev1.Secret) (*v1alpha2.VirtualMachineIPAddress, error) - RestoreVirtualMachineBlockDeviceAttachments(ctx context.Context, secret *corev1.Secret) ([]*v1alpha2.VirtualMachineBlockDeviceAttachment, error) - RestoreVirtualMachineMACAddresses(ctx context.Context, secret *corev1.Secret) ([]*v1alpha2.VirtualMachineMACAddress, error) - RestoreMACAddressOrder(ctx context.Context, secret *corev1.Secret) ([]string, error) -} diff --git a/images/virtualization-artifact/pkg/controller/vmrestore/internal/life_cycle.go b/images/virtualization-artifact/pkg/controller/vmrestore/internal/life_cycle.go deleted file mode 100644 index 75aa9e77ae..0000000000 --- a/images/virtualization-artifact/pkg/controller/vmrestore/internal/life_cycle.go +++ /dev/null @@ -1,650 +0,0 @@ -/* -Copyright 2024 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package internal - -import ( - "context" - "errors" - "fmt" - "strings" - - corev1 "k8s.io/api/core/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - virtv1 "kubevirt.io/api/core/v1" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - - vmopbuilder "github.com/deckhouse/virtualization-controller/pkg/builder/vmop" - "github.com/deckhouse/virtualization-controller/pkg/common/annotations" - "github.com/deckhouse/virtualization-controller/pkg/common/object" - "github.com/deckhouse/virtualization-controller/pkg/controller/conditions" - "github.com/deckhouse/virtualization-controller/pkg/controller/service" - svcrestorer "github.com/deckhouse/virtualization-controller/pkg/controller/service/restorer" - "github.com/deckhouse/virtualization-controller/pkg/controller/vmrestore/internal/restorer" - "github.com/deckhouse/virtualization-controller/pkg/eventrecord" - "github.com/deckhouse/virtualization/api/core/v1alpha2" - vmrestorecondition "github.com/deckhouse/virtualization/api/core/v1alpha2/vm-restore-condition" - "github.com/deckhouse/virtualization/api/core/v1alpha2/vmopcondition" -) - -const vdPrefix = "vd-" - -type LifeCycleHandler struct { - client client.Client - restorer Restorer - recorder eventrecord.EventRecorderLogger -} - -func NewLifeCycleHandler(client client.Client, restorer Restorer, recorder eventrecord.EventRecorderLogger) *LifeCycleHandler { - return &LifeCycleHandler{ - client: client, - restorer: restorer, - recorder: recorder, - } -} - -func (h LifeCycleHandler) Handle(ctx context.Context, vmRestore *v1alpha2.VirtualMachineRestore) (reconcile.Result, error) { - switch vmRestore.Status.Phase { - case v1alpha2.VirtualMachineRestorePhaseReady, - v1alpha2.VirtualMachineRestorePhaseFailed, - v1alpha2.VirtualMachineRestorePhaseTerminating: - return reconcile.Result{}, nil - } - - cb := conditions.NewConditionBuilder(vmrestorecondition.VirtualMachineRestoreReadyType) - defer func() { conditions.SetCondition(cb.Generation(vmRestore.Generation), &vmRestore.Status.Conditions) }() - - if !conditions.HasCondition(cb.GetType(), vmRestore.Status.Conditions) { - cb.Status(metav1.ConditionUnknown).Reason(conditions.ReasonUnknown) - } - - if vmRestore.Status.Phase == "" { - vmRestore.Status.Phase = v1alpha2.VirtualMachineRestorePhasePending - } - - if vmRestore.DeletionTimestamp != nil { - vmRestore.Status.Phase = v1alpha2.VirtualMachineRestorePhaseTerminating - cb.Status(metav1.ConditionUnknown).Reason(conditions.ReasonUnknown) - return reconcile.Result{}, nil - } - - if vmRestore.Status.Phase == v1alpha2.VirtualMachineRestorePhaseInProgress { - if vmRestore.Spec.RestoreMode == v1alpha2.RestoreModeForced { - err := h.startVirtualMachine(ctx, vmRestore) - if err != nil { - h.recorder.Event( - vmRestore, - corev1.EventTypeWarning, - v1alpha2.ReasonVMStartFailed, - err.Error(), - ) - } - } - - vmRestore.Status.Phase = v1alpha2.VirtualMachineRestorePhaseReady - cb.Status(metav1.ConditionTrue).Reason(vmrestorecondition.VirtualMachineRestoreReady) - - return reconcile.Result{}, nil - } - - vmSnapshotReadyToUseCondition, _ := conditions.GetCondition(vmrestorecondition.VirtualMachineSnapshotReadyToUseType, vmRestore.Status.Conditions) - if vmSnapshotReadyToUseCondition.Status != metav1.ConditionTrue { - vmRestore.Status.Phase = v1alpha2.VirtualMachineRestorePhasePending - cb. - Status(metav1.ConditionFalse). - Reason(vmrestorecondition.VirtualMachineSnapshotNotReadyToUse). - Message(fmt.Sprintf("Waiting for the virtual machine snapshot %q to be ready to use.", vmRestore.Spec.VirtualMachineSnapshotName)) - return reconcile.Result{}, nil - } - - vmSnapshotKey := types.NamespacedName{Namespace: vmRestore.Namespace, Name: vmRestore.Spec.VirtualMachineSnapshotName} - vmSnapshot, err := object.FetchObject(ctx, vmSnapshotKey, h.client, &v1alpha2.VirtualMachineSnapshot{}) - if err != nil { - setPhaseConditionToFailed(cb, &vmRestore.Status.Phase, err) - return reconcile.Result{}, err - } - - if vmSnapshot == nil { - err = fmt.Errorf("the virtual machine snapshot %q is nil, please report a bug", vmRestore.Spec.VirtualMachineSnapshotName) - setPhaseConditionToFailed(cb, &vmRestore.Status.Phase, err) - return reconcile.Result{}, err - } - - restorerSecretKey := types.NamespacedName{Namespace: vmSnapshot.Namespace, Name: vmSnapshot.Status.VirtualMachineSnapshotSecretName} - restorerSecret, err := object.FetchObject(ctx, restorerSecretKey, h.client, &corev1.Secret{}) - if err != nil { - setPhaseConditionToFailed(cb, &vmRestore.Status.Phase, err) - return reconcile.Result{}, err - } - - var ( - overrideValidators []OverrideValidator - runPolicy v1alpha2.RunPolicy - overridedVMName string - ) - - vm, err := h.restorer.RestoreVirtualMachine(ctx, restorerSecret) - if err != nil { - setPhaseConditionToFailed(cb, &vmRestore.Status.Phase, err) - return reconcile.Result{}, err - } - - if vmRestore.Spec.RestoreMode == v1alpha2.RestoreModeForced { - runPolicy = vm.Spec.RunPolicy - vm.Spec.RunPolicy = v1alpha2.AlwaysOffPolicy - } - - vmip, err := h.restorer.RestoreVirtualMachineIPAddress(ctx, restorerSecret) - if err != nil { - setPhaseConditionToFailed(cb, &vmRestore.Status.Phase, err) - return reconcile.Result{}, err - } - - if vmip != nil { - vm.Spec.VirtualMachineIPAddress = vmip.Name - overrideValidators = append(overrideValidators, restorer.NewVirtualMachineIPAddressOverrideValidator(vmip, h.client, string(vmRestore.UID))) - } - - vmmacs, err := h.restorer.RestoreVirtualMachineMACAddresses(ctx, restorerSecret) - if err != nil { - setPhaseConditionToFailed(cb, &vmRestore.Status.Phase, err) - return reconcile.Result{}, err - } - - macAddressOrder, err := h.restorer.RestoreMACAddressOrder(ctx, restorerSecret) - if err != nil { - setPhaseConditionToFailed(cb, &vmRestore.Status.Phase, err) - return reconcile.Result{}, err - } - - if len(vmmacs) > 0 { - macAddressNamesByAddress := make(map[string]string) - for _, vmmac := range vmmacs { - overrideValidators = append(overrideValidators, restorer.NewVirtualMachineMACAddressOverrideValidator(vmmac, h.client, string(vmRestore.UID))) - macAddressNamesByAddress[vmmac.Status.Address] = vmmac.Name - } - - for i := range vm.Spec.Networks { - ns := &vm.Spec.Networks[i] - if ns.Type == v1alpha2.NetworksTypeMain { - continue - } - - ns.VirtualMachineMACAddressName = macAddressNamesByAddress[macAddressOrder[i]] - } - } - - overrideValidators = append(overrideValidators, restorer.NewVirtualMachineOverrideValidator(vm, h.client, string(vmRestore.UID))) - - overridedVMName, err = h.getOverrridedVMName(overrideValidators) - if err != nil { - setPhaseConditionToFailed(cb, &vmRestore.Status.Phase, err) - return reconcile.Result{}, err - } - - vds, err := h.getVirtualDisks(ctx, vmSnapshot) - switch { - case err == nil: - case errors.Is(err, ErrVirtualDiskSnapshotNotFound): - vmRestore.Status.Phase = v1alpha2.VirtualMachineRestorePhasePending - cb. - Status(metav1.ConditionFalse). - Reason(vmrestorecondition.VirtualMachineSnapshotNotReady). - Message(service.CapitalizeFirstLetter(err.Error()) + ".") - return reconcile.Result{}, nil - default: - setPhaseConditionToFailed(cb, &vmRestore.Status.Phase, err) - return reconcile.Result{}, err - } - - vmbdas, err := h.restorer.RestoreVirtualMachineBlockDeviceAttachments(ctx, restorerSecret) - if err != nil { - setPhaseConditionToFailed(cb, &vmRestore.Status.Phase, err) - return reconcile.Result{}, err - } - - provisioner, err := h.restorer.RestoreProvisioner(ctx, restorerSecret) - if err != nil { - setPhaseConditionToFailed(cb, &vmRestore.Status.Phase, err) - return reconcile.Result{}, err - } - - for _, vd := range vds { - overrideValidators = append(overrideValidators, restorer.NewVirtualDiskOverrideValidator(vd, h.client, string(vmRestore.UID))) - } - - for _, vmbda := range vmbdas { - overrideValidators = append(overrideValidators, restorer.NewVirtualMachineBlockDeviceAttachmentsOverrideValidator(vmbda, h.client, string(vmRestore.UID))) - } - - if provisioner != nil { - overrideValidators = append(overrideValidators, restorer.NewProvisionerOverrideValidator(provisioner, h.client, string(vmRestore.UID))) - } - - var toCreate []client.Object - - if vmRestore.Spec.RestoreMode == v1alpha2.RestoreModeForced { - for _, ov := range overrideValidators { - ov.Override(vmRestore.Spec.NameReplacements) - - err := ov.ValidateWithForce(ctx) - switch { - case err == nil: - toCreate = append(toCreate, ov.Object()) - case errors.Is(err, restorer.ErrAlreadyInUse), errors.Is(err, restorer.ErrAlreadyExistsAndHasDiff): - vmRestore.Status.Phase = v1alpha2.VirtualMachineRestorePhaseFailed - cb. - Status(metav1.ConditionFalse). - Reason(vmrestorecondition.VirtualMachineRestoreConflict). - Message(service.CapitalizeFirstLetter(err.Error()) + ".") - return reconcile.Result{}, nil - case errors.Is(err, restorer.ErrAlreadyExists): - default: - setPhaseConditionToFailed(cb, &vmRestore.Status.Phase, err) - return reconcile.Result{}, err - } - } - - vmObj, err := object.FetchObject(ctx, types.NamespacedName{Name: overridedVMName, Namespace: vm.Namespace}, h.client, &v1alpha2.VirtualMachine{}) - if err != nil { - setPhaseConditionToFailed(cb, &vmRestore.Status.Phase, err) - return reconcile.Result{}, fmt.Errorf("failed to fetch the `VirtualMachine`: %w", err) - } - - if vmObj == nil { - err := errors.New("restoration with `Forced` mode can be applied only to an existing virtual machine; you can restore the virtual machine with `Safe` mode") - setPhaseConditionToFailed(cb, &vmRestore.Status.Phase, err) - return reconcile.Result{}, err - } else { - switch vmObj.Status.Phase { - case v1alpha2.MachinePending: - err := errors.New("a virtual machine cannot be restored from the pending phase with `Forced` mode; you can delete the virtual machine and restore it with `Safe` mode") - setPhaseConditionToFailed(cb, &vmRestore.Status.Phase, err) - return reconcile.Result{}, err - case v1alpha2.MachineStopped: - default: - if runPolicy != v1alpha2.AlwaysOffPolicy { - err := h.updateVMRunPolicy(ctx, vmObj, v1alpha2.AlwaysOffPolicy) - if err != nil { - if errors.Is(err, restorer.ErrUpdating) { - setPhaseConditionToPending(cb, &vmRestore.Status.Phase, vmrestorecondition.VirtualMachineIsNotStopped, err.Error()) - return reconcile.Result{}, nil - } - setPhaseConditionToFailed(cb, &vmRestore.Status.Phase, err) - return reconcile.Result{}, err - } - setPhaseConditionToPending(cb, &vmRestore.Status.Phase, vmrestorecondition.VirtualMachineIsNotStopped, "waiting for the virtual machine run policy will be updated") - return reconcile.Result{}, nil - } - - err := h.stopVirtualMachine(ctx, vm.Name, vm.Namespace, string(vmRestore.UID)) - if err != nil { - if errors.Is(err, restorer.ErrIncomplete) { - setPhaseConditionToPending(cb, &vmRestore.Status.Phase, vmrestorecondition.VirtualMachineIsNotStopped, "waiting for the virtual machine will be stopped") - return reconcile.Result{}, nil - } - setPhaseConditionToFailed(cb, &vmRestore.Status.Phase, err) - return reconcile.Result{}, err - } - } - } - - for _, ov := range overrideValidators { - err := ov.ProcessWithForce(ctx) - switch { - case err == nil: - case errors.Is(err, restorer.ErrRestoring), errors.Is(err, restorer.ErrUpdating): - setPhaseConditionToPending(cb, &vmRestore.Status.Phase, vmrestorecondition.VirtualMachineResourcesAreNotReady, err.Error()) - return reconcile.Result{}, nil - default: - setPhaseConditionToPending(cb, &vmRestore.Status.Phase, vmrestorecondition.VirtualMachineResourcesAreNotReady, err.Error()) - return reconcile.Result{}, err - } - } - } - - if vmRestore.Spec.RestoreMode == v1alpha2.RestoreModeSafe { - for _, ov := range overrideValidators { - ov.Override(vmRestore.Spec.NameReplacements) - - err = ov.Validate(ctx) - switch { - case err == nil: - case errors.Is(err, restorer.ErrAlreadyExists), errors.Is(err, restorer.ErrAlreadyInUse), errors.Is(err, restorer.ErrAlreadyExistsAndHasDiff): - vmRestore.Status.Phase = v1alpha2.VirtualMachineRestorePhaseFailed - cb. - Status(metav1.ConditionFalse). - Reason(vmrestorecondition.VirtualMachineRestoreConflict). - Message(service.CapitalizeFirstLetter(err.Error()) + ".") - return reconcile.Result{}, nil - default: - setPhaseConditionToFailed(cb, &vmRestore.Status.Phase, err) - return reconcile.Result{}, err - } - - toCreate = append(toCreate, ov.Object()) - } - } - - currentHotplugs, err := h.getCurrentVirtualMachineBlockDeviceAttachments(ctx, vm.Name, vm.Namespace, string(vmRestore.UID)) - if err != nil { - setPhaseConditionToPending(cb, &vmRestore.Status.Phase, vmrestorecondition.VirtualMachineResourcesAreNotReady, err.Error()) - return reconcile.Result{}, err - } - - err = h.deleteCurrentVirtualMachineBlockDeviceAttachments(ctx, currentHotplugs) - if err != nil { - setPhaseConditionToPending(cb, &vmRestore.Status.Phase, vmrestorecondition.VirtualMachineResourcesAreNotReady, err.Error()) - return reconcile.Result{}, err - } - - err = h.createBatch(ctx, toCreate...) - if err != nil { - setPhaseConditionToFailed(cb, &vmRestore.Status.Phase, err) - return reconcile.Result{}, err - } - - if vmRestore.Spec.RestoreMode == v1alpha2.RestoreModeForced { - err = h.checkKVVMDiskStatus(ctx, vm.Name, vm.Namespace) - if err != nil { - if errors.Is(err, restorer.ErrRestoring) { - setPhaseConditionToPending(cb, &vmRestore.Status.Phase, vmrestorecondition.VirtualMachineResourcesAreNotReady, err.Error()) - return reconcile.Result{}, nil - } - return reconcile.Result{}, err - } - - vmObj, err := object.FetchObject(ctx, types.NamespacedName{Name: overridedVMName, Namespace: vm.Namespace}, h.client, &v1alpha2.VirtualMachine{}) - if err != nil { - setPhaseConditionToFailed(cb, &vmRestore.Status.Phase, err) - return reconcile.Result{}, fmt.Errorf("failed to fetch the `VirtualMachine`: %w", err) - } - - err = h.updateVMRunPolicy(ctx, vmObj, runPolicy) - if err != nil { - if errors.Is(err, restorer.ErrUpdating) { - setPhaseConditionToPending(cb, &vmRestore.Status.Phase, vmrestorecondition.VirtualMachineResourcesAreNotReady, err.Error()) - return reconcile.Result{}, nil - } - setPhaseConditionToFailed(cb, &vmRestore.Status.Phase, err) - return reconcile.Result{}, err - } - } - - vmRestore.Status.Phase = v1alpha2.VirtualMachineRestorePhaseInProgress - cb. - Status(metav1.ConditionFalse). - Reason(vmrestorecondition.VirtualMachineSnapshotNotReady). - Message(fmt.Sprintf("The virtual machine %q is in the process of restore.", vmSnapshot.Spec.VirtualMachineName)) - return reconcile.Result{}, nil -} - -type OverrideValidator interface { - Object() client.Object - Override(rules []v1alpha2.NameReplacement) - Validate(ctx context.Context) error - ValidateWithForce(ctx context.Context) error - ProcessWithForce(ctx context.Context) error -} - -var ErrVirtualDiskSnapshotNotFound = errors.New("not found") - -func (h LifeCycleHandler) getVirtualDisks(ctx context.Context, vmSnapshot *v1alpha2.VirtualMachineSnapshot) ([]*v1alpha2.VirtualDisk, error) { - vds := make([]*v1alpha2.VirtualDisk, 0, len(vmSnapshot.Status.VirtualDiskSnapshotNames)) - - for _, vdSnapshotName := range vmSnapshot.Status.VirtualDiskSnapshotNames { - vdSnapshotKey := types.NamespacedName{Namespace: vmSnapshot.Namespace, Name: vdSnapshotName} - vdSnapshot, err := object.FetchObject(ctx, vdSnapshotKey, h.client, &v1alpha2.VirtualDiskSnapshot{}) - if err != nil { - return nil, fmt.Errorf("failed to fetch the virtual disk snapshot %q: %w", vdSnapshotKey.Name, err) - } - - if vdSnapshot == nil { - return nil, fmt.Errorf("the virtual disk snapshot %q %w", vdSnapshotName, ErrVirtualDiskSnapshotNotFound) - } - - vd := v1alpha2.VirtualDisk{ - TypeMeta: metav1.TypeMeta{ - Kind: v1alpha2.VirtualDiskKind, - APIVersion: v1alpha2.Version, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: vdSnapshot.Spec.VirtualDiskName, - Namespace: vdSnapshot.Namespace, - }, - Spec: v1alpha2.VirtualDiskSpec{ - DataSource: &v1alpha2.VirtualDiskDataSource{ - Type: v1alpha2.DataSourceTypeObjectRef, - ObjectRef: &v1alpha2.VirtualDiskObjectRef{ - Kind: v1alpha2.VirtualDiskObjectRefKindVirtualDiskSnapshot, - Name: vdSnapshot.Name, - }, - }, - }, - Status: v1alpha2.VirtualDiskStatus{ - AttachedToVirtualMachines: []v1alpha2.AttachedVirtualMachine{ - {Name: vmSnapshot.Spec.VirtualMachineName, Mounted: true}, - }, - }, - } - - err = svcrestorer.AddOriginalMetadata(ctx, &vd, vdSnapshot, h.client) - if err != nil { - return nil, fmt.Errorf("add original metadata: %w", err) - } - - vds = append(vds, &vd) - } - - return vds, nil -} - -func (h LifeCycleHandler) getCurrentVirtualMachineBlockDeviceAttachments(ctx context.Context, vmName, vmNamespace, vmRestoreUID string) ([]*v1alpha2.VirtualMachineBlockDeviceAttachment, error) { - vmbdas := &v1alpha2.VirtualMachineBlockDeviceAttachmentList{} - err := h.client.List(ctx, vmbdas, &client.ListOptions{Namespace: vmNamespace}) - if err != nil { - return nil, fmt.Errorf("failed to list the `VirtualMachineBlockDeviceAttachment`: %w", err) - } - - vmbdasByVM := make([]*v1alpha2.VirtualMachineBlockDeviceAttachment, 0, len(vmbdas.Items)) - for _, vmbda := range vmbdas.Items { - if vmbda.Spec.VirtualMachineName != vmName { - continue - } - if value, ok := vmbda.Annotations[annotations.AnnVMRestore]; ok && value == vmRestoreUID { - continue - } - vmbdasByVM = append(vmbdasByVM, &vmbda) - } - - return vmbdasByVM, nil -} - -func (h LifeCycleHandler) deleteCurrentVirtualMachineBlockDeviceAttachments(ctx context.Context, vmbdas []*v1alpha2.VirtualMachineBlockDeviceAttachment) error { - for _, vmbda := range vmbdas { - err := object.DeleteObject(ctx, h.client, client.Object(vmbda)) - if err != nil { - return fmt.Errorf("failed to delete the `VirtualMachineBlockDeviceAttachment` %s: %w", vmbda.Name, err) - } - } - - return nil -} - -func (h LifeCycleHandler) createBatch(ctx context.Context, objs ...client.Object) error { - for _, obj := range objs { - err := h.client.Create(ctx, obj) - if err != nil && !k8serrors.IsAlreadyExists(err) { - return fmt.Errorf("failed to create %s %q: %w", obj.GetObjectKind().GroupVersionKind().Kind, obj.GetName(), err) - } - } - - return nil -} - -func setPhaseConditionToFailed(cb *conditions.ConditionBuilder, phase *v1alpha2.VirtualMachineRestorePhase, err error) { - *phase = v1alpha2.VirtualMachineRestorePhaseFailed - cb. - Status(metav1.ConditionFalse). - Reason(vmrestorecondition.VirtualMachineRestoreFailed). - Message(service.CapitalizeFirstLetter(err.Error()) + ".") -} - -func setPhaseConditionToPending(cb *conditions.ConditionBuilder, phase *v1alpha2.VirtualMachineRestorePhase, reason vmrestorecondition.VirtualMachineRestoreReadyReason, msg string) { - *phase = v1alpha2.VirtualMachineRestorePhasePending - cb. - Status(metav1.ConditionFalse). - Reason(reason). - Message(service.CapitalizeFirstLetter(msg) + ".") -} - -func newVMRestoreVMOP(vmName, namespace, vmRestoreUID string, vmopType v1alpha2.VMOPType) *v1alpha2.VirtualMachineOperation { - return vmopbuilder.New( - vmopbuilder.WithGenerateName("vmrestore-"), - vmopbuilder.WithNamespace(namespace), - vmopbuilder.WithAnnotation(annotations.AnnVMOPRestore, vmRestoreUID), - vmopbuilder.WithType(vmopType), - vmopbuilder.WithVirtualMachine(vmName), - ) -} - -func (h LifeCycleHandler) getVMRestoreVMOP(ctx context.Context, vmNamespace, vmRestoreUID string, vmopType v1alpha2.VMOPType) (*v1alpha2.VirtualMachineOperation, error) { - vmops := &v1alpha2.VirtualMachineOperationList{} - err := h.client.List(ctx, vmops, &client.ListOptions{Namespace: vmNamespace}) - if err != nil { - return nil, err - } - - for _, vmop := range vmops.Items { - if v, ok := vmop.Annotations[annotations.AnnVMOPRestore]; ok { - if v == vmRestoreUID && vmop.Spec.Type == vmopType { - return &vmop, nil - } - } - } - - return nil, nil -} - -func (h LifeCycleHandler) stopVirtualMachine(ctx context.Context, vmName, vmNamespace, vmRestoreUID string) error { - vmopStop, err := h.getVMRestoreVMOP(ctx, vmNamespace, vmRestoreUID, v1alpha2.VMOPTypeStop) - if err != nil { - return fmt.Errorf("failed to list the `VirtualMachineOperations`: %w", err) - } - - if vmopStop == nil { - vmopStop := newVMRestoreVMOP(vmName, vmNamespace, vmRestoreUID, v1alpha2.VMOPTypeStop) - err := h.client.Create(ctx, vmopStop) - if err != nil { - return fmt.Errorf("failed to stop the `VirtualMachine`: %w", err) - } - return fmt.Errorf("the status of the virtual machine operation is %w", restorer.ErrIncomplete) - } - - conditionCompleted, _ := conditions.GetCondition(vmopcondition.TypeCompleted, vmopStop.Status.Conditions) - switch vmopStop.Status.Phase { - case v1alpha2.VMOPPhaseFailed: - return fmt.Errorf("failed to stop the `VirtualMachine`: %s", conditionCompleted.Message) - case v1alpha2.VMOPPhaseCompleted: - return nil - default: - return fmt.Errorf("the status of the `VirtualMachineOperation` is %w: %s", restorer.ErrIncomplete, conditionCompleted.Message) - } -} - -func (h LifeCycleHandler) startVirtualMachine(ctx context.Context, vmRestore *v1alpha2.VirtualMachineRestore) error { - vms := &v1alpha2.VirtualMachineList{} - err := h.client.List(ctx, vms, &client.ListOptions{Namespace: vmRestore.Namespace}) - if err != nil { - return fmt.Errorf("failed to list the `VirtualMachines`: %w", err) - } - - var vmName string - for _, vm := range vms.Items { - if v, ok := vm.Annotations[annotations.AnnVMRestore]; ok && v == string(vmRestore.UID) { - vmName = vm.Name - } - } - - vmKey := types.NamespacedName{Name: vmName, Namespace: vmRestore.Namespace} - vmObj, err := object.FetchObject(ctx, vmKey, h.client, &v1alpha2.VirtualMachine{}) - if err != nil { - return fmt.Errorf("failed to fetch the `VirtualMachine`: %w", err) - } - - if vmObj != nil { - if vmObj.Spec.RunPolicy != v1alpha2.AlwaysOnUnlessStoppedManually { - return nil - } - - if vmObj.Status.Phase == v1alpha2.MachineStopped { - vmopStart := newVMRestoreVMOP(vmName, vmRestore.Namespace, string(vmRestore.UID), v1alpha2.VMOPTypeStart) - err := h.client.Create(ctx, vmopStart) - if err != nil { - return fmt.Errorf("failed to start the `VirtualMachine`: %w", err) - } - } - } - - return nil -} - -func (h LifeCycleHandler) checkKVVMDiskStatus(ctx context.Context, vmName, vmNamespace string) error { - kvvmKey := types.NamespacedName{Name: vmName, Namespace: vmNamespace} - kvvm, err := object.FetchObject(ctx, kvvmKey, h.client, &virtv1.VirtualMachine{}) - if err != nil { - return fmt.Errorf("failed to fetch the `InternalVirtualMachine`: %w", err) - } - - if kvvm != nil { - for _, vss := range kvvm.Status.VolumeSnapshotStatuses { - if strings.HasPrefix(vss.Name, vdPrefix) && vss.Reason == restorer.ReasonPVCNotFound { - return fmt.Errorf("waiting for the `VirtualDisks` %w", restorer.ErrRestoring) - } - } - return nil - } - - return fmt.Errorf("failed to fetch the `InternalVirtualMachine`: %s", vmName) -} - -func (h LifeCycleHandler) getOverrridedVMName(overrideValidators []OverrideValidator) (string, error) { - for _, ov := range overrideValidators { - if ov.Object().GetObjectKind().GroupVersionKind().Kind == v1alpha2.VirtualMachineKind { - return ov.Object().GetName(), nil - } - } - - return "", fmt.Errorf("failed to get the `VirtualMachine` name") -} - -func (h LifeCycleHandler) updateVMRunPolicy(ctx context.Context, vmObj *v1alpha2.VirtualMachine, runPolicy v1alpha2.RunPolicy) error { - vmObj.Spec.RunPolicy = runPolicy - - err := h.client.Update(ctx, vmObj) - if err != nil { - if k8serrors.IsConflict(err) { - return fmt.Errorf("waiting for the virtual machine run policy %w", restorer.ErrUpdating) - } else { - return fmt.Errorf("failed to update the virtual machine run policy: %w", err) - } - } - - return nil -} diff --git a/images/virtualization-artifact/pkg/controller/vmrestore/internal/life_cycle_test.go b/images/virtualization-artifact/pkg/controller/vmrestore/internal/life_cycle_test.go deleted file mode 100644 index 052297b30c..0000000000 --- a/images/virtualization-artifact/pkg/controller/vmrestore/internal/life_cycle_test.go +++ /dev/null @@ -1,152 +0,0 @@ -/* -Copyright 2026 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package internal - -import ( - "context" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/deckhouse/virtualization-controller/pkg/common/testutil" - "github.com/deckhouse/virtualization-controller/pkg/eventrecord" - "github.com/deckhouse/virtualization/api/core/v1alpha2" - vmrestorecondition "github.com/deckhouse/virtualization/api/core/v1alpha2/vm-restore-condition" -) - -var _ = Describe("LifeCycleHandler", func() { - It("maps VirtualMachineMACAddressName by original network index", func() { - vm := &v1alpha2.VirtualMachine{ - TypeMeta: metav1.TypeMeta{ - Kind: v1alpha2.VirtualMachineKind, - APIVersion: v1alpha2.SchemeGroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "vm", - Namespace: "default", - }, - Spec: v1alpha2.VirtualMachineSpec{ - Networks: []v1alpha2.NetworksSpec{ - {Type: v1alpha2.NetworksTypeMain}, - {Type: v1alpha2.NetworksTypeNetwork}, - }, - }, - } - - vmmac := &v1alpha2.VirtualMachineMACAddress{ - TypeMeta: metav1.TypeMeta{ - Kind: v1alpha2.VirtualMachineMACAddressKind, - APIVersion: v1alpha2.SchemeGroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "vm-mac-secondary", - Namespace: "default", - }, - Status: v1alpha2.VirtualMachineMACAddressStatus{ - Address: "02:00:00:00:00:11", - VirtualMachine: "vm", - }, - } - - vmSnapshot := &v1alpha2.VirtualMachineSnapshot{ - ObjectMeta: metav1.ObjectMeta{ - Name: "snapshot", - Namespace: "default", - }, - Spec: v1alpha2.VirtualMachineSnapshotSpec{ - VirtualMachineName: "vm", - }, - Status: v1alpha2.VirtualMachineSnapshotStatus{ - VirtualMachineSnapshotSecretName: "restorer-secret", - }, - } - - vmRestore := &v1alpha2.VirtualMachineRestore{ - ObjectMeta: metav1.ObjectMeta{ - Name: "restore", - Namespace: "default", - UID: types.UID("restore-uid"), - }, - Spec: v1alpha2.VirtualMachineRestoreSpec{ - VirtualMachineSnapshotName: "snapshot", - RestoreMode: v1alpha2.RestoreModeSafe, - }, - Status: v1alpha2.VirtualMachineRestoreStatus{ - Conditions: []metav1.Condition{ - { - Type: vmrestorecondition.VirtualMachineSnapshotReadyToUseType.String(), - Status: metav1.ConditionTrue, - }, - }, - }, - } - - restorerSecret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "restorer-secret", - Namespace: "default", - }, - } - - fakeClient, err := testutil.NewFakeClientWithObjects(vmSnapshot, vmRestore, restorerSecret) - Expect(err).NotTo(HaveOccurred()) - - restorerMock := &RestorerMock{ - RestoreVirtualMachineFunc: func(context.Context, *corev1.Secret) (*v1alpha2.VirtualMachine, error) { - return vm.DeepCopy(), nil - }, - RestoreProvisionerFunc: func(context.Context, *corev1.Secret) (*corev1.Secret, error) { - return nil, nil - }, - RestoreVirtualMachineIPAddressFunc: func(context.Context, *corev1.Secret) (*v1alpha2.VirtualMachineIPAddress, error) { - return nil, nil - }, - RestoreVirtualMachineBlockDeviceAttachmentsFunc: func(context.Context, *corev1.Secret) ([]*v1alpha2.VirtualMachineBlockDeviceAttachment, error) { - return nil, nil - }, - RestoreVirtualMachineMACAddressesFunc: func(context.Context, *corev1.Secret) ([]*v1alpha2.VirtualMachineMACAddress, error) { - return []*v1alpha2.VirtualMachineMACAddress{vmmac.DeepCopy()}, nil - }, - RestoreMACAddressOrderFunc: func(context.Context, *corev1.Secret) ([]string, error) { - return []string{"", "02:00:00:00:00:11"}, nil - }, - } - - recorder := &eventrecord.EventRecorderLoggerMock{} - recorder.EventFunc = func(client.Object, string, string, string) {} - recorder.EventfFunc = func(client.Object, string, string, string, ...interface{}) {} - recorder.AnnotatedEventfFunc = func(client.Object, map[string]string, string, string, string, ...interface{}) {} - recorder.WithLoggingFunc = func(eventrecord.InfoLogger) eventrecord.EventRecorderLogger { - return recorder - } - - handler := NewLifeCycleHandler(fakeClient, restorerMock, recorder) - _, err = handler.Handle(testContext(), vmRestore) - Expect(err).NotTo(HaveOccurred()) - - restoredVM := &v1alpha2.VirtualMachine{} - err = fakeClient.Get(testContext(), types.NamespacedName{Name: "vm", Namespace: "default"}, restoredVM) - Expect(err).NotTo(HaveOccurred()) - - Expect(restoredVM.Spec.Networks[0].VirtualMachineMACAddressName).To(BeEmpty()) - Expect(restoredVM.Spec.Networks[1].VirtualMachineMACAddressName).To(Equal("vm-mac-secondary")) - }) -}) diff --git a/images/virtualization-artifact/pkg/controller/vmrestore/internal/mock.go b/images/virtualization-artifact/pkg/controller/vmrestore/internal/mock.go deleted file mode 100644 index 4165a3dd57..0000000000 --- a/images/virtualization-artifact/pkg/controller/vmrestore/internal/mock.go +++ /dev/null @@ -1,333 +0,0 @@ -// Code generated by moq; DO NOT EDIT. -// github.com/matryer/moq - -package internal - -import ( - "context" - "github.com/deckhouse/virtualization/api/core/v1alpha2" - corev1 "k8s.io/api/core/v1" - "sync" -) - -// Ensure, that RestorerMock does implement Restorer. -// If this is not the case, regenerate this file with moq. -var _ Restorer = &RestorerMock{} - -// RestorerMock is a mock implementation of Restorer. -// -// func TestSomethingThatUsesRestorer(t *testing.T) { -// -// // make and configure a mocked Restorer -// mockedRestorer := &RestorerMock{ -// RestoreMACAddressOrderFunc: func(ctx context.Context, secret *corev1.Secret) ([]string, error) { -// panic("mock out the RestoreMACAddressOrder method") -// }, -// RestoreProvisionerFunc: func(ctx context.Context, secret *corev1.Secret) (*corev1.Secret, error) { -// panic("mock out the RestoreProvisioner method") -// }, -// RestoreVirtualMachineFunc: func(ctx context.Context, secret *corev1.Secret) (*v1alpha2.VirtualMachine, error) { -// panic("mock out the RestoreVirtualMachine method") -// }, -// RestoreVirtualMachineBlockDeviceAttachmentsFunc: func(ctx context.Context, secret *corev1.Secret) ([]*v1alpha2.VirtualMachineBlockDeviceAttachment, error) { -// panic("mock out the RestoreVirtualMachineBlockDeviceAttachments method") -// }, -// RestoreVirtualMachineIPAddressFunc: func(ctx context.Context, secret *corev1.Secret) (*v1alpha2.VirtualMachineIPAddress, error) { -// panic("mock out the RestoreVirtualMachineIPAddress method") -// }, -// RestoreVirtualMachineMACAddressesFunc: func(ctx context.Context, secret *corev1.Secret) ([]*v1alpha2.VirtualMachineMACAddress, error) { -// panic("mock out the RestoreVirtualMachineMACAddresses method") -// }, -// } -// -// // use mockedRestorer in code that requires Restorer -// // and then make assertions. -// -// } -type RestorerMock struct { - // RestoreMACAddressOrderFunc mocks the RestoreMACAddressOrder method. - RestoreMACAddressOrderFunc func(ctx context.Context, secret *corev1.Secret) ([]string, error) - - // RestoreProvisionerFunc mocks the RestoreProvisioner method. - RestoreProvisionerFunc func(ctx context.Context, secret *corev1.Secret) (*corev1.Secret, error) - - // RestoreVirtualMachineFunc mocks the RestoreVirtualMachine method. - RestoreVirtualMachineFunc func(ctx context.Context, secret *corev1.Secret) (*v1alpha2.VirtualMachine, error) - - // RestoreVirtualMachineBlockDeviceAttachmentsFunc mocks the RestoreVirtualMachineBlockDeviceAttachments method. - RestoreVirtualMachineBlockDeviceAttachmentsFunc func(ctx context.Context, secret *corev1.Secret) ([]*v1alpha2.VirtualMachineBlockDeviceAttachment, error) - - // RestoreVirtualMachineIPAddressFunc mocks the RestoreVirtualMachineIPAddress method. - RestoreVirtualMachineIPAddressFunc func(ctx context.Context, secret *corev1.Secret) (*v1alpha2.VirtualMachineIPAddress, error) - - // RestoreVirtualMachineMACAddressesFunc mocks the RestoreVirtualMachineMACAddresses method. - RestoreVirtualMachineMACAddressesFunc func(ctx context.Context, secret *corev1.Secret) ([]*v1alpha2.VirtualMachineMACAddress, error) - - // calls tracks calls to the methods. - calls struct { - // RestoreMACAddressOrder holds details about calls to the RestoreMACAddressOrder method. - RestoreMACAddressOrder []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Secret is the secret argument value. - Secret *corev1.Secret - } - // RestoreProvisioner holds details about calls to the RestoreProvisioner method. - RestoreProvisioner []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Secret is the secret argument value. - Secret *corev1.Secret - } - // RestoreVirtualMachine holds details about calls to the RestoreVirtualMachine method. - RestoreVirtualMachine []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Secret is the secret argument value. - Secret *corev1.Secret - } - // RestoreVirtualMachineBlockDeviceAttachments holds details about calls to the RestoreVirtualMachineBlockDeviceAttachments method. - RestoreVirtualMachineBlockDeviceAttachments []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Secret is the secret argument value. - Secret *corev1.Secret - } - // RestoreVirtualMachineIPAddress holds details about calls to the RestoreVirtualMachineIPAddress method. - RestoreVirtualMachineIPAddress []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Secret is the secret argument value. - Secret *corev1.Secret - } - // RestoreVirtualMachineMACAddresses holds details about calls to the RestoreVirtualMachineMACAddresses method. - RestoreVirtualMachineMACAddresses []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // Secret is the secret argument value. - Secret *corev1.Secret - } - } - lockRestoreMACAddressOrder sync.RWMutex - lockRestoreProvisioner sync.RWMutex - lockRestoreVirtualMachine sync.RWMutex - lockRestoreVirtualMachineBlockDeviceAttachments sync.RWMutex - lockRestoreVirtualMachineIPAddress sync.RWMutex - lockRestoreVirtualMachineMACAddresses sync.RWMutex -} - -// RestoreMACAddressOrder calls RestoreMACAddressOrderFunc. -func (mock *RestorerMock) RestoreMACAddressOrder(ctx context.Context, secret *corev1.Secret) ([]string, error) { - if mock.RestoreMACAddressOrderFunc == nil { - panic("RestorerMock.RestoreMACAddressOrderFunc: method is nil but Restorer.RestoreMACAddressOrder was just called") - } - callInfo := struct { - Ctx context.Context - Secret *corev1.Secret - }{ - Ctx: ctx, - Secret: secret, - } - mock.lockRestoreMACAddressOrder.Lock() - mock.calls.RestoreMACAddressOrder = append(mock.calls.RestoreMACAddressOrder, callInfo) - mock.lockRestoreMACAddressOrder.Unlock() - return mock.RestoreMACAddressOrderFunc(ctx, secret) -} - -// RestoreMACAddressOrderCalls gets all the calls that were made to RestoreMACAddressOrder. -// Check the length with: -// -// len(mockedRestorer.RestoreMACAddressOrderCalls()) -func (mock *RestorerMock) RestoreMACAddressOrderCalls() []struct { - Ctx context.Context - Secret *corev1.Secret -} { - var calls []struct { - Ctx context.Context - Secret *corev1.Secret - } - mock.lockRestoreMACAddressOrder.RLock() - calls = mock.calls.RestoreMACAddressOrder - mock.lockRestoreMACAddressOrder.RUnlock() - return calls -} - -// RestoreProvisioner calls RestoreProvisionerFunc. -func (mock *RestorerMock) RestoreProvisioner(ctx context.Context, secret *corev1.Secret) (*corev1.Secret, error) { - if mock.RestoreProvisionerFunc == nil { - panic("RestorerMock.RestoreProvisionerFunc: method is nil but Restorer.RestoreProvisioner was just called") - } - callInfo := struct { - Ctx context.Context - Secret *corev1.Secret - }{ - Ctx: ctx, - Secret: secret, - } - mock.lockRestoreProvisioner.Lock() - mock.calls.RestoreProvisioner = append(mock.calls.RestoreProvisioner, callInfo) - mock.lockRestoreProvisioner.Unlock() - return mock.RestoreProvisionerFunc(ctx, secret) -} - -// RestoreProvisionerCalls gets all the calls that were made to RestoreProvisioner. -// Check the length with: -// -// len(mockedRestorer.RestoreProvisionerCalls()) -func (mock *RestorerMock) RestoreProvisionerCalls() []struct { - Ctx context.Context - Secret *corev1.Secret -} { - var calls []struct { - Ctx context.Context - Secret *corev1.Secret - } - mock.lockRestoreProvisioner.RLock() - calls = mock.calls.RestoreProvisioner - mock.lockRestoreProvisioner.RUnlock() - return calls -} - -// RestoreVirtualMachine calls RestoreVirtualMachineFunc. -func (mock *RestorerMock) RestoreVirtualMachine(ctx context.Context, secret *corev1.Secret) (*v1alpha2.VirtualMachine, error) { - if mock.RestoreVirtualMachineFunc == nil { - panic("RestorerMock.RestoreVirtualMachineFunc: method is nil but Restorer.RestoreVirtualMachine was just called") - } - callInfo := struct { - Ctx context.Context - Secret *corev1.Secret - }{ - Ctx: ctx, - Secret: secret, - } - mock.lockRestoreVirtualMachine.Lock() - mock.calls.RestoreVirtualMachine = append(mock.calls.RestoreVirtualMachine, callInfo) - mock.lockRestoreVirtualMachine.Unlock() - return mock.RestoreVirtualMachineFunc(ctx, secret) -} - -// RestoreVirtualMachineCalls gets all the calls that were made to RestoreVirtualMachine. -// Check the length with: -// -// len(mockedRestorer.RestoreVirtualMachineCalls()) -func (mock *RestorerMock) RestoreVirtualMachineCalls() []struct { - Ctx context.Context - Secret *corev1.Secret -} { - var calls []struct { - Ctx context.Context - Secret *corev1.Secret - } - mock.lockRestoreVirtualMachine.RLock() - calls = mock.calls.RestoreVirtualMachine - mock.lockRestoreVirtualMachine.RUnlock() - return calls -} - -// RestoreVirtualMachineBlockDeviceAttachments calls RestoreVirtualMachineBlockDeviceAttachmentsFunc. -func (mock *RestorerMock) RestoreVirtualMachineBlockDeviceAttachments(ctx context.Context, secret *corev1.Secret) ([]*v1alpha2.VirtualMachineBlockDeviceAttachment, error) { - if mock.RestoreVirtualMachineBlockDeviceAttachmentsFunc == nil { - panic("RestorerMock.RestoreVirtualMachineBlockDeviceAttachmentsFunc: method is nil but Restorer.RestoreVirtualMachineBlockDeviceAttachments was just called") - } - callInfo := struct { - Ctx context.Context - Secret *corev1.Secret - }{ - Ctx: ctx, - Secret: secret, - } - mock.lockRestoreVirtualMachineBlockDeviceAttachments.Lock() - mock.calls.RestoreVirtualMachineBlockDeviceAttachments = append(mock.calls.RestoreVirtualMachineBlockDeviceAttachments, callInfo) - mock.lockRestoreVirtualMachineBlockDeviceAttachments.Unlock() - return mock.RestoreVirtualMachineBlockDeviceAttachmentsFunc(ctx, secret) -} - -// RestoreVirtualMachineBlockDeviceAttachmentsCalls gets all the calls that were made to RestoreVirtualMachineBlockDeviceAttachments. -// Check the length with: -// -// len(mockedRestorer.RestoreVirtualMachineBlockDeviceAttachmentsCalls()) -func (mock *RestorerMock) RestoreVirtualMachineBlockDeviceAttachmentsCalls() []struct { - Ctx context.Context - Secret *corev1.Secret -} { - var calls []struct { - Ctx context.Context - Secret *corev1.Secret - } - mock.lockRestoreVirtualMachineBlockDeviceAttachments.RLock() - calls = mock.calls.RestoreVirtualMachineBlockDeviceAttachments - mock.lockRestoreVirtualMachineBlockDeviceAttachments.RUnlock() - return calls -} - -// RestoreVirtualMachineIPAddress calls RestoreVirtualMachineIPAddressFunc. -func (mock *RestorerMock) RestoreVirtualMachineIPAddress(ctx context.Context, secret *corev1.Secret) (*v1alpha2.VirtualMachineIPAddress, error) { - if mock.RestoreVirtualMachineIPAddressFunc == nil { - panic("RestorerMock.RestoreVirtualMachineIPAddressFunc: method is nil but Restorer.RestoreVirtualMachineIPAddress was just called") - } - callInfo := struct { - Ctx context.Context - Secret *corev1.Secret - }{ - Ctx: ctx, - Secret: secret, - } - mock.lockRestoreVirtualMachineIPAddress.Lock() - mock.calls.RestoreVirtualMachineIPAddress = append(mock.calls.RestoreVirtualMachineIPAddress, callInfo) - mock.lockRestoreVirtualMachineIPAddress.Unlock() - return mock.RestoreVirtualMachineIPAddressFunc(ctx, secret) -} - -// RestoreVirtualMachineIPAddressCalls gets all the calls that were made to RestoreVirtualMachineIPAddress. -// Check the length with: -// -// len(mockedRestorer.RestoreVirtualMachineIPAddressCalls()) -func (mock *RestorerMock) RestoreVirtualMachineIPAddressCalls() []struct { - Ctx context.Context - Secret *corev1.Secret -} { - var calls []struct { - Ctx context.Context - Secret *corev1.Secret - } - mock.lockRestoreVirtualMachineIPAddress.RLock() - calls = mock.calls.RestoreVirtualMachineIPAddress - mock.lockRestoreVirtualMachineIPAddress.RUnlock() - return calls -} - -// RestoreVirtualMachineMACAddresses calls RestoreVirtualMachineMACAddressesFunc. -func (mock *RestorerMock) RestoreVirtualMachineMACAddresses(ctx context.Context, secret *corev1.Secret) ([]*v1alpha2.VirtualMachineMACAddress, error) { - if mock.RestoreVirtualMachineMACAddressesFunc == nil { - panic("RestorerMock.RestoreVirtualMachineMACAddressesFunc: method is nil but Restorer.RestoreVirtualMachineMACAddresses was just called") - } - callInfo := struct { - Ctx context.Context - Secret *corev1.Secret - }{ - Ctx: ctx, - Secret: secret, - } - mock.lockRestoreVirtualMachineMACAddresses.Lock() - mock.calls.RestoreVirtualMachineMACAddresses = append(mock.calls.RestoreVirtualMachineMACAddresses, callInfo) - mock.lockRestoreVirtualMachineMACAddresses.Unlock() - return mock.RestoreVirtualMachineMACAddressesFunc(ctx, secret) -} - -// RestoreVirtualMachineMACAddressesCalls gets all the calls that were made to RestoreVirtualMachineMACAddresses. -// Check the length with: -// -// len(mockedRestorer.RestoreVirtualMachineMACAddressesCalls()) -func (mock *RestorerMock) RestoreVirtualMachineMACAddressesCalls() []struct { - Ctx context.Context - Secret *corev1.Secret -} { - var calls []struct { - Ctx context.Context - Secret *corev1.Secret - } - mock.lockRestoreVirtualMachineMACAddresses.RLock() - calls = mock.calls.RestoreVirtualMachineMACAddresses - mock.lockRestoreVirtualMachineMACAddresses.RUnlock() - return calls -} diff --git a/images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/errors.go b/images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/errors.go deleted file mode 100644 index f827ad1757..0000000000 --- a/images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/errors.go +++ /dev/null @@ -1,28 +0,0 @@ -/* -Copyright 2024 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package restorer - -import "errors" - -var ( - ErrAlreadyExists = errors.New("already exists") - ErrAlreadyExistsAndHasDiff = errors.New("already exists and does not have the same data content") - ErrAlreadyInUse = errors.New("already in use") - ErrRestoring = errors.New("will be restored") - ErrUpdating = errors.New("will be updated") - ErrIncomplete = errors.New("still incomplete") -) diff --git a/images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/overrider.go b/images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/overrider.go deleted file mode 100644 index f8abc3dda1..0000000000 --- a/images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/overrider.go +++ /dev/null @@ -1,37 +0,0 @@ -/* -Copyright 2024 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package restorer - -import "github.com/deckhouse/virtualization/api/core/v1alpha2" - -func overrideName(kind, name string, rules []v1alpha2.NameReplacement) string { - if name == "" { - return "" - } - - for _, rule := range rules { - if rule.From.Kind != "" && rule.From.Kind != kind { - continue - } - - if rule.From.Name == name { - return rule.To - } - } - - return name -} diff --git a/images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/provisioner_restorer.go b/images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/provisioner_restorer.go deleted file mode 100644 index 11ee92fc4f..0000000000 --- a/images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/provisioner_restorer.go +++ /dev/null @@ -1,102 +0,0 @@ -/* -Copyright 2024 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package restorer - -import ( - "bytes" - "context" - "fmt" - "maps" - - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/deckhouse/virtualization-controller/pkg/common/annotations" - "github.com/deckhouse/virtualization-controller/pkg/common/object" - "github.com/deckhouse/virtualization/api/core/v1alpha2" -) - -type ProvisionerOverrideValidator struct { - secret *corev1.Secret - client client.Client - vmRestoreUID string -} - -func NewProvisionerOverrideValidator(secretTmpl *corev1.Secret, client client.Client, vmRestoreUID string) *ProvisionerOverrideValidator { - if secretTmpl.Annotations != nil { - secretTmpl.Annotations[annotations.AnnVMRestore] = vmRestoreUID - } else { - secretTmpl.Annotations = make(map[string]string) - secretTmpl.Annotations[annotations.AnnVMRestore] = vmRestoreUID - } - return &ProvisionerOverrideValidator{ - secret: &corev1.Secret{ - TypeMeta: metav1.TypeMeta{ - Kind: secretTmpl.Kind, - APIVersion: secretTmpl.APIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: secretTmpl.Name, - Namespace: secretTmpl.Namespace, - Annotations: secretTmpl.Annotations, - Labels: secretTmpl.Labels, - }, - Immutable: secretTmpl.Immutable, - Data: secretTmpl.Data, - StringData: secretTmpl.StringData, - Type: secretTmpl.Type, - }, - client: client, - vmRestoreUID: vmRestoreUID, - } -} - -func (v *ProvisionerOverrideValidator) Override(rules []v1alpha2.NameReplacement) { - v.secret.Name = overrideName(v.secret.Kind, v.secret.Name, rules) -} - -func (v *ProvisionerOverrideValidator) Validate(ctx context.Context) error { - secretKey := types.NamespacedName{Namespace: v.secret.Namespace, Name: v.secret.Name} - existed, err := object.FetchObject(ctx, secretKey, v.client, &corev1.Secret{}) - if err != nil { - return err - } - - if existed == nil { - return nil - } - - if !maps.EqualFunc(existed.Data, v.secret.Data, bytes.Equal) { - return fmt.Errorf("the provisioner secret %q %w", secretKey.Name, ErrAlreadyExistsAndHasDiff) - } - - return nil -} - -func (v *ProvisionerOverrideValidator) ValidateWithForce(ctx context.Context) error { - return v.Validate(ctx) -} - -func (v *ProvisionerOverrideValidator) ProcessWithForce(ctx context.Context) error { - return nil -} - -func (v *ProvisionerOverrideValidator) Object() client.Object { - return v.secret -} diff --git a/images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/vd_restorer.go b/images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/vd_restorer.go deleted file mode 100644 index 8f16c0ffb3..0000000000 --- a/images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/vd_restorer.go +++ /dev/null @@ -1,154 +0,0 @@ -/* -Copyright 2024 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package restorer - -import ( - "context" - "fmt" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/deckhouse/virtualization-controller/pkg/common/annotations" - "github.com/deckhouse/virtualization-controller/pkg/common/object" - "github.com/deckhouse/virtualization/api/core/v1alpha2" -) - -type VirtualDiskOverrideValidator struct { - vd *v1alpha2.VirtualDisk - client client.Client - vmRestoreUID string -} - -func NewVirtualDiskOverrideValidator(vdTmpl *v1alpha2.VirtualDisk, client client.Client, vmRestoreUID string) *VirtualDiskOverrideValidator { - if vdTmpl.Annotations != nil { - vdTmpl.Annotations[annotations.AnnVMRestore] = vmRestoreUID - } else { - vdTmpl.Annotations = make(map[string]string) - vdTmpl.Annotations[annotations.AnnVMRestore] = vmRestoreUID - } - return &VirtualDiskOverrideValidator{ - vd: &v1alpha2.VirtualDisk{ - TypeMeta: metav1.TypeMeta{ - Kind: vdTmpl.Kind, - APIVersion: vdTmpl.APIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: vdTmpl.Name, - Namespace: vdTmpl.Namespace, - Annotations: vdTmpl.Annotations, - Labels: vdTmpl.Labels, - }, - Spec: vdTmpl.Spec, - Status: vdTmpl.Status, - }, - client: client, - vmRestoreUID: vmRestoreUID, - } -} - -func (v *VirtualDiskOverrideValidator) Override(rules []v1alpha2.NameReplacement) { - v.vd.Name = overrideName(v.vd.Kind, v.vd.Name, rules) -} - -func (v *VirtualDiskOverrideValidator) Validate(ctx context.Context) error { - vdKey := types.NamespacedName{Namespace: v.vd.Namespace, Name: v.vd.Name} - existed, err := object.FetchObject(ctx, vdKey, v.client, &v1alpha2.VirtualDisk{}) - if err != nil { - return err - } - - if existed != nil { - if value, ok := existed.Annotations[annotations.AnnVMRestore]; ok && value == v.vmRestoreUID { - return nil - } - return fmt.Errorf("the virtual disk %q %w", vdKey.Name, ErrAlreadyExists) - } - - return nil -} - -func (v *VirtualDiskOverrideValidator) ValidateWithForce(ctx context.Context) error { - vdKey := types.NamespacedName{Namespace: v.vd.Namespace, Name: v.vd.Name} - existed, err := object.FetchObject(ctx, vdKey, v.client, &v1alpha2.VirtualDisk{}) - if err != nil { - return err - } - - vmName := v.getVirtualMachineName() - - if existed != nil { - for _, a := range existed.Status.AttachedToVirtualMachines { - if a.Mounted && a.Name != vmName { - return fmt.Errorf("the virtual disk %q %w", existed.Name, ErrAlreadyInUse) - } - } - } - - return nil -} - -func (v *VirtualDiskOverrideValidator) ProcessWithForce(ctx context.Context) error { - vdKey := types.NamespacedName{Namespace: v.vd.Namespace, Name: v.vd.Name} - vdObj, err := object.FetchObject(ctx, vdKey, v.client, &v1alpha2.VirtualDisk{}) - if err != nil { - return fmt.Errorf("failed to fetch the `VirtualDisk`: %w", err) - } - - if object.IsTerminating(vdObj) { - return fmt.Errorf("waiting for the `VirtualDisk` %s %w", vdObj.Name, ErrRestoring) - } - - if vdObj != nil { - if value, ok := vdObj.Annotations[annotations.AnnVMRestore]; ok && value == v.vmRestoreUID { - return nil - } - err := v.client.Delete(ctx, vdObj) - if err != nil { - return fmt.Errorf("failed to delete the `VirtualDisk`: %w", err) - } - return fmt.Errorf("waiting for the `VirtualDisk` %s %w", vdObj.Name, ErrRestoring) - } - - return nil -} - -func (v *VirtualDiskOverrideValidator) Object() client.Object { - return &v1alpha2.VirtualDisk{ - TypeMeta: metav1.TypeMeta{ - Kind: v.vd.Kind, - APIVersion: v.vd.APIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: v.vd.Name, - Namespace: v.vd.Namespace, - Annotations: v.vd.Annotations, - Labels: v.vd.Labels, - }, - Spec: v.vd.Spec, - } -} - -func (v *VirtualDiskOverrideValidator) getVirtualMachineName() string { - for _, a := range v.vd.Status.AttachedToVirtualMachines { - if a.Mounted { - return a.Name - } - } - return "" -} diff --git a/images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/vm_restorer.go b/images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/vm_restorer.go deleted file mode 100644 index c57335d917..0000000000 --- a/images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/vm_restorer.go +++ /dev/null @@ -1,159 +0,0 @@ -/* -Copyright 2024 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package restorer - -import ( - "context" - "fmt" - - "k8s.io/apimachinery/pkg/api/equality" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/deckhouse/virtualization-controller/pkg/common/annotations" - "github.com/deckhouse/virtualization-controller/pkg/common/object" - "github.com/deckhouse/virtualization/api/core/v1alpha2" -) - -const ReasonPVCNotFound = "PVC not found" - -type VirtualMachineOverrideValidator struct { - vm *v1alpha2.VirtualMachine - client client.Client - vmRestoreUID string -} - -func NewVirtualMachineOverrideValidator(vmTmpl *v1alpha2.VirtualMachine, client client.Client, vmRestoreUID string) *VirtualMachineOverrideValidator { - if vmTmpl.Annotations != nil { - vmTmpl.Annotations[annotations.AnnVMRestore] = vmRestoreUID - } else { - vmTmpl.Annotations = make(map[string]string) - vmTmpl.Annotations[annotations.AnnVMRestore] = vmRestoreUID - } - - return &VirtualMachineOverrideValidator{ - vm: &v1alpha2.VirtualMachine{ - TypeMeta: metav1.TypeMeta{ - Kind: vmTmpl.Kind, - APIVersion: vmTmpl.APIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: vmTmpl.Name, - Namespace: vmTmpl.Namespace, - Annotations: vmTmpl.Annotations, - Labels: vmTmpl.Labels, - }, - Spec: vmTmpl.Spec, - }, - client: client, - vmRestoreUID: vmRestoreUID, - } -} - -func (v *VirtualMachineOverrideValidator) Override(rules []v1alpha2.NameReplacement) { - originalName := v.vm.Name - v.vm.Name = overrideName(v.vm.Kind, v.vm.Name, rules) - if v.vm.Name != originalName { - // Do not clone labels due to potential issues with traffic from services. - v.vm.Labels = map[string]string{} - } - - v.vm.Spec.VirtualMachineIPAddress = overrideName(v1alpha2.VirtualMachineIPAddressKind, v.vm.Spec.VirtualMachineIPAddress, rules) - - if v.vm.Spec.Provisioning != nil { - if v.vm.Spec.Provisioning.UserDataRef != nil { - if v.vm.Spec.Provisioning.UserDataRef.Kind == v1alpha2.UserDataRefKindSecret { - v.vm.Spec.Provisioning.UserDataRef.Name = overrideName( - string(v1alpha2.UserDataRefKindSecret), - v.vm.Spec.Provisioning.UserDataRef.Name, - rules, - ) - } - } - } - - for i := range v.vm.Spec.BlockDeviceRefs { - if v.vm.Spec.BlockDeviceRefs[i].Kind != v1alpha2.DiskDevice { - continue - } - - v.vm.Spec.BlockDeviceRefs[i].Name = overrideName(v1alpha2.VirtualDiskKind, v.vm.Spec.BlockDeviceRefs[i].Name, rules) - } -} - -func (v *VirtualMachineOverrideValidator) Validate(ctx context.Context) error { - vmKey := types.NamespacedName{Namespace: v.vm.Namespace, Name: v.vm.Name} - existed, err := object.FetchObject(ctx, vmKey, v.client, &v1alpha2.VirtualMachine{}) - if err != nil { - return err - } - - if existed != nil { - if value, ok := existed.Annotations[annotations.AnnVMRestore]; ok && value == v.vmRestoreUID { - return nil - } - return fmt.Errorf("the virtual machine %q %w", vmKey.Name, ErrAlreadyExists) - } - - return nil -} - -func (v *VirtualMachineOverrideValidator) ValidateWithForce(ctx context.Context) error { - return nil -} - -func (v *VirtualMachineOverrideValidator) ProcessWithForce(ctx context.Context) error { - vmKey := types.NamespacedName{Namespace: v.vm.Namespace, Name: v.vm.Name} - vmObj, err := object.FetchObject(ctx, vmKey, v.client, &v1alpha2.VirtualMachine{}) - if err != nil { - return fmt.Errorf("failed to fetch the `VirtualMachine`: %w", err) - } - - if vmObj != nil { - var ( - vmHasCorrectVMRestoreUID bool - vmHasVMSnapshotSpec bool - ) - - if value, ok := vmObj.Annotations[annotations.AnnVMRestore]; !ok || value != v.vmRestoreUID { - vmHasCorrectVMRestoreUID = false - vmObj.SetAnnotations(map[string]string{annotations.AnnVMRestore: v.vmRestoreUID}) - } - if !equality.Semantic.DeepEqual(vmObj.Spec, v.vm.Spec) { - vmHasVMSnapshotSpec = false - vmObj.Spec = v.vm.Spec - } - - if !vmHasCorrectVMRestoreUID || !vmHasVMSnapshotSpec { - updErr := v.client.Update(ctx, vmObj) - if updErr != nil { - if apierrors.IsConflict(updErr) { - return fmt.Errorf("waiting for the `VirtualMachine` %w", ErrUpdating) - } - return fmt.Errorf("failed to update the `VirtualMachine`: %w", updErr) - } - } - } - - return nil -} - -func (v *VirtualMachineOverrideValidator) Object() client.Object { - return v.vm -} diff --git a/images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/vmbda_restorer.go b/images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/vmbda_restorer.go deleted file mode 100644 index a85d8cffd0..0000000000 --- a/images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/vmbda_restorer.go +++ /dev/null @@ -1,126 +0,0 @@ -/* -Copyright 2024 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package restorer - -import ( - "context" - "fmt" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/deckhouse/virtualization-controller/pkg/common/annotations" - "github.com/deckhouse/virtualization-controller/pkg/common/object" - "github.com/deckhouse/virtualization/api/core/v1alpha2" -) - -type VirtualMachineBlockDeviceAttachmentsOverrideValidator struct { - vmbda *v1alpha2.VirtualMachineBlockDeviceAttachment - client client.Client - vmRestoreUID string -} - -func NewVirtualMachineBlockDeviceAttachmentsOverrideValidator(vmbdaTmpl *v1alpha2.VirtualMachineBlockDeviceAttachment, client client.Client, vmRestoreUID string) *VirtualMachineBlockDeviceAttachmentsOverrideValidator { - if vmbdaTmpl.Annotations != nil { - vmbdaTmpl.Annotations[annotations.AnnVMRestore] = vmRestoreUID - } else { - vmbdaTmpl.Annotations = make(map[string]string) - vmbdaTmpl.Annotations[annotations.AnnVMRestore] = vmRestoreUID - } - return &VirtualMachineBlockDeviceAttachmentsOverrideValidator{ - vmbda: &v1alpha2.VirtualMachineBlockDeviceAttachment{ - TypeMeta: metav1.TypeMeta{ - Kind: vmbdaTmpl.Kind, - APIVersion: vmbdaTmpl.APIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: vmbdaTmpl.Name, - Namespace: vmbdaTmpl.Namespace, - Annotations: vmbdaTmpl.Annotations, - Labels: vmbdaTmpl.Labels, - }, - Spec: vmbdaTmpl.Spec, - }, - client: client, - vmRestoreUID: vmRestoreUID, - } -} - -func (v *VirtualMachineBlockDeviceAttachmentsOverrideValidator) Override(rules []v1alpha2.NameReplacement) { - v.vmbda.Name = overrideName(v.vmbda.Kind, v.vmbda.Name, rules) - v.vmbda.Spec.VirtualMachineName = overrideName(v1alpha2.VirtualMachineKind, v.vmbda.Spec.VirtualMachineName, rules) - - switch v.vmbda.Spec.BlockDeviceRef.Kind { - case v1alpha2.VMBDAObjectRefKindVirtualDisk: - v.vmbda.Spec.BlockDeviceRef.Name = overrideName(v1alpha2.VirtualDiskKind, v.vmbda.Spec.BlockDeviceRef.Name, rules) - case v1alpha2.VMBDAObjectRefKindClusterVirtualImage: - v.vmbda.Spec.BlockDeviceRef.Name = overrideName(v1alpha2.ClusterVirtualImageKind, v.vmbda.Spec.BlockDeviceRef.Name, rules) - case v1alpha2.VMBDAObjectRefKindVirtualImage: - v.vmbda.Spec.BlockDeviceRef.Name = overrideName(v1alpha2.VirtualImageKind, v.vmbda.Spec.BlockDeviceRef.Name, rules) - } -} - -func (v *VirtualMachineBlockDeviceAttachmentsOverrideValidator) Validate(ctx context.Context) error { - vmbdaKey := types.NamespacedName{Namespace: v.vmbda.Namespace, Name: v.vmbda.Name} - existed, err := object.FetchObject(ctx, vmbdaKey, v.client, &v1alpha2.VirtualMachineBlockDeviceAttachment{}) - if err != nil { - return err - } - - if existed != nil { - if value, ok := existed.Annotations[annotations.AnnVMRestore]; ok && value == v.vmRestoreUID { - return nil - } - return fmt.Errorf("the virtual machine block device attachment %q %w", vmbdaKey.Name, ErrAlreadyExists) - } - - return nil -} - -func (v *VirtualMachineBlockDeviceAttachmentsOverrideValidator) ValidateWithForce(ctx context.Context) error { - return nil -} - -func (v *VirtualMachineBlockDeviceAttachmentsOverrideValidator) ProcessWithForce(ctx context.Context) error { - vmbdaKey := types.NamespacedName{Namespace: v.vmbda.Namespace, Name: v.vmbda.Name} - vmbdaObj, err := object.FetchObject(ctx, vmbdaKey, v.client, &v1alpha2.VirtualMachineBlockDeviceAttachment{}) - if err != nil { - return fmt.Errorf("failed to fetch the `VirtualMachineBlockDeviceAttachment`: %w", err) - } - - if object.IsTerminating(vmbdaObj) { - return fmt.Errorf("waiting for the `VirtualMachineBlockDeviceAttachment` %s %w", vmbdaObj.Name, ErrRestoring) - } - - if vmbdaObj != nil { - if value, ok := vmbdaObj.Annotations[annotations.AnnVMRestore]; ok && value == v.vmRestoreUID { - return nil - } - err = v.client.Delete(ctx, vmbdaObj) - if err != nil { - return fmt.Errorf("failed to delete the `VirtualMachineBlockDeviceAttachment`: %w", err) - } - return fmt.Errorf("waiting for the `VirtualMachineBlockDeviceAttachment` %s %w", vmbdaObj.Name, ErrRestoring) - } - - return nil -} - -func (v *VirtualMachineBlockDeviceAttachmentsOverrideValidator) Object() client.Object { - return v.vmbda -} diff --git a/images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/vmip_restorer.go b/images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/vmip_restorer.go deleted file mode 100644 index 958f44b068..0000000000 --- a/images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/vmip_restorer.go +++ /dev/null @@ -1,175 +0,0 @@ -/* -Copyright 2024 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package restorer - -import ( - "context" - "fmt" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/deckhouse/virtualization-controller/pkg/common/annotations" - "github.com/deckhouse/virtualization-controller/pkg/common/object" - "github.com/deckhouse/virtualization-controller/pkg/controller/indexer" - "github.com/deckhouse/virtualization/api/core/v1alpha2" -) - -type VirtualMachineIPAddressOverrideValidator struct { - vmip *v1alpha2.VirtualMachineIPAddress - client client.Client - vmRestoreUID string -} - -func NewVirtualMachineIPAddressOverrideValidator(vmipTmpl *v1alpha2.VirtualMachineIPAddress, client client.Client, vmRestoreUID string) *VirtualMachineIPAddressOverrideValidator { - if vmipTmpl.Annotations != nil { - vmipTmpl.Annotations[annotations.AnnVMRestore] = vmRestoreUID - } else { - vmipTmpl.Annotations = make(map[string]string) - vmipTmpl.Annotations[annotations.AnnVMRestore] = vmRestoreUID - } - return &VirtualMachineIPAddressOverrideValidator{ - vmip: &v1alpha2.VirtualMachineIPAddress{ - TypeMeta: metav1.TypeMeta{ - Kind: vmipTmpl.Kind, - APIVersion: vmipTmpl.APIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: vmipTmpl.Name, - Namespace: vmipTmpl.Namespace, - Annotations: vmipTmpl.Annotations, - Labels: vmipTmpl.Labels, - }, - Spec: vmipTmpl.Spec, - Status: vmipTmpl.Status, - }, - client: client, - vmRestoreUID: vmRestoreUID, - } -} - -func (v *VirtualMachineIPAddressOverrideValidator) Override(rules []v1alpha2.NameReplacement) { - v.vmip.Name = overrideName(v.vmip.Kind, v.vmip.Name, rules) -} - -func (v *VirtualMachineIPAddressOverrideValidator) Validate(ctx context.Context) error { - vmipKey := types.NamespacedName{Namespace: v.vmip.Namespace, Name: v.vmip.Name} - existed, err := object.FetchObject(ctx, vmipKey, v.client, &v1alpha2.VirtualMachineIPAddress{}) - if err != nil { - return err - } - - if existed == nil { - if v.vmip.Spec.StaticIP == "" { - return nil - } - - var vmips v1alpha2.VirtualMachineIPAddressList - err = v.client.List(ctx, &vmips, &client.ListOptions{ - Namespace: v.vmip.Namespace, - FieldSelector: fields.OneTermEqualSelector(indexer.IndexFieldVMIPByAddress, v.vmip.Spec.StaticIP), - }) - if err != nil { - return err - } - - if len(vmips.Items) > 0 { - return fmt.Errorf( - "the set address %q is %w by the different virtual machine ip address %q and cannot be used for the restored virtual machine", - v.vmip.Spec.StaticIP, ErrAlreadyInUse, vmips.Items[0].Name, - ) - } - - return nil - } - - if value, ok := existed.Annotations[annotations.AnnVMRestore]; ok && value == v.vmRestoreUID { - return nil - } - - if existed.Status.Phase == v1alpha2.VirtualMachineIPAddressPhaseAttached || existed.Status.VirtualMachine != "" { - return fmt.Errorf("the virtual machine ip address %q is %w and cannot be used for the restored virtual machine", vmipKey.Name, ErrAlreadyInUse) - } - - return nil -} - -func (v *VirtualMachineIPAddressOverrideValidator) ValidateWithForce(ctx context.Context) error { - vmipKey := types.NamespacedName{Namespace: v.vmip.Namespace, Name: v.vmip.Name} - existed, err := object.FetchObject(ctx, vmipKey, v.client, &v1alpha2.VirtualMachineIPAddress{}) - if err != nil { - return err - } - - vmName := v.vmip.Status.VirtualMachine - - if existed == nil { - if v.vmip.Spec.StaticIP == "" { - return nil - } - - var vmips v1alpha2.VirtualMachineIPAddressList - err = v.client.List(ctx, &vmips, &client.ListOptions{ - Namespace: v.vmip.Namespace, - FieldSelector: fields.OneTermEqualSelector(indexer.IndexFieldVMIPByAddress, v.vmip.Spec.StaticIP), - }) - if err != nil { - return err - } - - if len(vmips.Items) > 0 { - return fmt.Errorf( - "the set address %q is %w by the different virtual machine ip address %q and cannot be used for the restored virtual machine", - v.vmip.Spec.StaticIP, ErrAlreadyInUse, vmips.Items[0].Name, - ) - } - - return nil - } - - if existed.Status.Phase == v1alpha2.VirtualMachineIPAddressPhaseAttached && existed.Status.VirtualMachine == vmName { - return ErrAlreadyExists - } - - if existed.Status.Phase == v1alpha2.VirtualMachineIPAddressPhaseAttached || existed.Status.VirtualMachine != "" { - return fmt.Errorf("the virtual machine ip address %q is %w and cannot be used for the restored virtual machine", vmipKey.Name, ErrAlreadyInUse) - } - - return nil -} - -func (v *VirtualMachineIPAddressOverrideValidator) ProcessWithForce(ctx context.Context) error { - return nil -} - -func (v *VirtualMachineIPAddressOverrideValidator) Object() client.Object { - return &v1alpha2.VirtualMachineIPAddress{ - TypeMeta: metav1.TypeMeta{ - Kind: v.vmip.Kind, - APIVersion: v.vmip.APIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: v.vmip.Name, - Namespace: v.vmip.Namespace, - Annotations: v.vmip.Annotations, - Labels: v.vmip.Labels, - }, - Spec: v.vmip.Spec, - } -} diff --git a/images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/vmmac_restorer.go b/images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/vmmac_restorer.go deleted file mode 100644 index 78f38ca38e..0000000000 --- a/images/virtualization-artifact/pkg/controller/vmrestore/internal/restorer/vmmac_restorer.go +++ /dev/null @@ -1,171 +0,0 @@ -/* -Copyright 2024 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package restorer - -import ( - "context" - "fmt" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/deckhouse/virtualization-controller/pkg/common/annotations" - "github.com/deckhouse/virtualization-controller/pkg/common/object" - "github.com/deckhouse/virtualization-controller/pkg/controller/indexer" - "github.com/deckhouse/virtualization/api/core/v1alpha2" -) - -type VirtualMachineMACAddressOverrideValidator struct { - vmmac *v1alpha2.VirtualMachineMACAddress - client client.Client - vmRestoreUID string -} - -func NewVirtualMachineMACAddressOverrideValidator(vmmacTmpl *v1alpha2.VirtualMachineMACAddress, client client.Client, vmRestoreUID string) *VirtualMachineMACAddressOverrideValidator { - if vmmacTmpl.Annotations != nil { - vmmacTmpl.Annotations[annotations.AnnVMRestore] = vmRestoreUID - } else { - vmmacTmpl.Annotations = make(map[string]string) - vmmacTmpl.Annotations[annotations.AnnVMRestore] = vmRestoreUID - } - return &VirtualMachineMACAddressOverrideValidator{ - vmmac: &v1alpha2.VirtualMachineMACAddress{ - TypeMeta: metav1.TypeMeta{ - Kind: vmmacTmpl.Kind, - APIVersion: vmmacTmpl.APIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: vmmacTmpl.Name, - Namespace: vmmacTmpl.Namespace, - Annotations: vmmacTmpl.Annotations, - Labels: vmmacTmpl.Labels, - }, - Spec: vmmacTmpl.Spec, - Status: vmmacTmpl.Status, - }, - client: client, - vmRestoreUID: vmRestoreUID, - } -} - -func (v *VirtualMachineMACAddressOverrideValidator) Override(rules []v1alpha2.NameReplacement) { - v.vmmac.Name = overrideName(v.vmmac.Kind, v.vmmac.Name, rules) -} - -func (v *VirtualMachineMACAddressOverrideValidator) Validate(ctx context.Context) error { - vmmacKey := types.NamespacedName{Namespace: v.vmmac.Namespace, Name: v.vmmac.Name} - existed, err := object.FetchObject(ctx, vmmacKey, v.client, &v1alpha2.VirtualMachineMACAddress{}) - if err != nil { - return err - } - - if existed == nil { - if v.vmmac.Spec.Address == "" { - return nil - } - - var vmmacs v1alpha2.VirtualMachineMACAddressList - err = v.client.List(ctx, &vmmacs, &client.ListOptions{ - Namespace: v.vmmac.Namespace, - FieldSelector: fields.OneTermEqualSelector(indexer.IndexFieldVMMACByAddress, v.vmmac.Spec.Address), - }) - if err != nil { - return err - } - - if len(vmmacs.Items) > 0 { - return fmt.Errorf( - "the set address %q is %w by the different virtual machine mac address %q and cannot be used for the restored virtual machine", - v.vmmac.Spec.Address, ErrAlreadyInUse, vmmacs.Items[0].Name, - ) - } - - return nil - } - - if existed.Status.Phase == v1alpha2.VirtualMachineMACAddressPhaseAttached || existed.Status.VirtualMachine != "" { - return fmt.Errorf("the virtual machine mac address %q is %w and cannot be used for the restored virtual machine", vmmacKey.Name, ErrAlreadyInUse) - } - - return nil -} - -func (v *VirtualMachineMACAddressOverrideValidator) ValidateWithForce(ctx context.Context) error { - vmmacKey := types.NamespacedName{Namespace: v.vmmac.Namespace, Name: v.vmmac.Name} - existed, err := object.FetchObject(ctx, vmmacKey, v.client, &v1alpha2.VirtualMachineMACAddress{}) - if err != nil { - return err - } - - vmName := v.vmmac.Status.VirtualMachine - - if existed == nil { - if v.vmmac.Spec.Address == "" { - return nil - } - - var vmmacs v1alpha2.VirtualMachineMACAddressList - err = v.client.List(ctx, &vmmacs, &client.ListOptions{ - Namespace: v.vmmac.Namespace, - FieldSelector: fields.OneTermEqualSelector(indexer.IndexFieldVMMACByAddress, v.vmmac.Spec.Address), - }) - if err != nil { - return err - } - - if len(vmmacs.Items) > 0 { - return fmt.Errorf( - "the set address %q is %w by the different virtual machine mac address %q and cannot be used for the restored virtual machine", - v.vmmac.Spec.Address, ErrAlreadyInUse, vmmacs.Items[0].Name, - ) - } - - return nil - } - - if existed.Status.Phase == v1alpha2.VirtualMachineMACAddressPhaseAttached && existed.Status.VirtualMachine == vmName { - return ErrAlreadyExists - } - - if existed.Status.Phase == v1alpha2.VirtualMachineMACAddressPhaseAttached || existed.Status.VirtualMachine != "" { - return fmt.Errorf("the virtual machine mac address %q is %w and cannot be used for the restored virtual machine", vmmacKey.Name, ErrAlreadyInUse) - } - - return nil -} - -func (v *VirtualMachineMACAddressOverrideValidator) ProcessWithForce(_ context.Context) error { - return nil -} - -func (v *VirtualMachineMACAddressOverrideValidator) Object() client.Object { - return &v1alpha2.VirtualMachineMACAddress{ - TypeMeta: metav1.TypeMeta{ - Kind: v.vmmac.Kind, - APIVersion: v.vmmac.APIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: v.vmmac.Name, - Namespace: v.vmmac.Namespace, - Annotations: v.vmmac.Annotations, - Labels: v.vmmac.Labels, - }, - Spec: v.vmmac.Spec, - } -} diff --git a/images/virtualization-artifact/pkg/controller/vmrestore/internal/vm_snapshot_ready_to_use.go b/images/virtualization-artifact/pkg/controller/vmrestore/internal/vm_snapshot_ready_to_use.go deleted file mode 100644 index 06b71f6b07..0000000000 --- a/images/virtualization-artifact/pkg/controller/vmrestore/internal/vm_snapshot_ready_to_use.go +++ /dev/null @@ -1,100 +0,0 @@ -/* -Copyright 2024 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package internal - -import ( - "context" - "fmt" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "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/api/core/v1alpha2" - vmrestorecondition "github.com/deckhouse/virtualization/api/core/v1alpha2/vm-restore-condition" - "github.com/deckhouse/virtualization/api/core/v1alpha2/vmscondition" -) - -type VirtualMachineSnapshotReadyToUseHandler struct { - client client.Client -} - -func NewVirtualMachineSnapshotReadyToUseHandler(client client.Client) *VirtualMachineSnapshotReadyToUseHandler { - return &VirtualMachineSnapshotReadyToUseHandler{ - client: client, - } -} - -func (h VirtualMachineSnapshotReadyToUseHandler) Handle(ctx context.Context, vmRestore *v1alpha2.VirtualMachineRestore) (reconcile.Result, error) { - cb := conditions.NewConditionBuilder(vmrestorecondition.VirtualMachineSnapshotReadyToUseType) - defer func() { conditions.SetCondition(cb.Generation(vmRestore.Generation), &vmRestore.Status.Conditions) }() - - if !conditions.HasCondition(cb.GetType(), vmRestore.Status.Conditions) { - cb.Status(metav1.ConditionUnknown).Reason(conditions.ReasonUnknown) - } - - if vmRestore.DeletionTimestamp != nil { - cb.Status(metav1.ConditionUnknown).Reason(conditions.ReasonUnknown) - return reconcile.Result{}, nil - } - - vmSnapshotKey := types.NamespacedName{Name: vmRestore.Spec.VirtualMachineSnapshotName, Namespace: vmRestore.Namespace} - vmSnapshot, err := object.FetchObject(ctx, vmSnapshotKey, h.client, &v1alpha2.VirtualMachineSnapshot{}) - if err != nil { - return reconcile.Result{}, err - } - - if vmSnapshot == nil { - cb. - Status(metav1.ConditionFalse). - Reason(vmrestorecondition.VirtualMachineSnapshotNotFound). - Message(fmt.Sprintf("The virtual machine snapshot %q not found.", vmRestore.Spec.VirtualMachineSnapshotName)) - return reconcile.Result{}, nil - } - - if vmSnapshot.GetDeletionTimestamp() != nil { - cb. - Status(metav1.ConditionFalse). - Reason(vmrestorecondition.VirtualMachineSnapshotNotReady). - Message(fmt.Sprintf("The virtual machine snapshot %q is in the process if deleting.", vmSnapshot.Name)) - return reconcile.Result{}, nil - } - - vmSnapshotReady, _ := conditions.GetCondition(vmscondition.VirtualMachineSnapshotReadyType, vmSnapshot.Status.Conditions) - if vmSnapshotReady.Status != metav1.ConditionTrue || vmSnapshot.Status.Phase != v1alpha2.VirtualMachineSnapshotPhaseReady { - cb. - Status(metav1.ConditionFalse). - Reason(vmrestorecondition.VirtualMachineSnapshotNotReady). - Message(fmt.Sprintf("Waiting for the virtual machine snapshot %q to be ready for use.", vmSnapshot.Name)) - return reconcile.Result{}, nil - } - - if vmSnapshot.Generation != vmSnapshot.Status.ObservedGeneration { - cb. - Status(metav1.ConditionFalse). - Reason(vmrestorecondition.VirtualMachineSnapshotNotReady). - Message(fmt.Sprintf("Waiting for the virtual machine snapshot %q to be observed in its latest state generation.", vmSnapshot.Name)) - return reconcile.Result{}, nil - } - - cb.Status(metav1.ConditionTrue).Reason(vmrestorecondition.VirtualMachineSnapshotReadyToUse) - - return reconcile.Result{}, nil -} diff --git a/images/virtualization-artifact/pkg/controller/vmrestore/internal/watcher/kvvm_watcher.go b/images/virtualization-artifact/pkg/controller/vmrestore/internal/watcher/kvvm_watcher.go deleted file mode 100644 index d0eae8ad48..0000000000 --- a/images/virtualization-artifact/pkg/controller/vmrestore/internal/watcher/kvvm_watcher.go +++ /dev/null @@ -1,111 +0,0 @@ -/* -Copyright 2025 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package watcher - -import ( - "context" - "fmt" - - "k8s.io/apimachinery/pkg/types" - virtv1 "kubevirt.io/api/core/v1" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" - - "github.com/deckhouse/deckhouse/pkg/log" - "github.com/deckhouse/virtualization/api/core/v1alpha2" -) - -// This watcher is required for monitoring the statuses of InternalVirtualMachine disks, which must update their PVC during the restoration process. -// However, the VirtualMachineRestore controller should work only with VirtualMachine. -type InternalVirtualMachineWatcher struct { - client client.Client -} - -func NewInternalVirtualMachineWatcher(client client.Client) *InternalVirtualMachineWatcher { - return &InternalVirtualMachineWatcher{ - client: client, - } -} - -func (w InternalVirtualMachineWatcher) Watch(mgr manager.Manager, ctr controller.Controller) error { - if err := ctr.Watch( - source.Kind(mgr.GetCache(), &virtv1.VirtualMachine{}, - handler.TypedEnqueueRequestsFromMapFunc(w.enqueueRequests), - ), - ); err != nil { - return fmt.Errorf("error setting watch on VirtualMachine: %w", err) - } - return nil -} - -func (w InternalVirtualMachineWatcher) enqueueRequests(ctx context.Context, kvvm *virtv1.VirtualMachine) (requests []reconcile.Request) { - var vmRestores v1alpha2.VirtualMachineRestoreList - err := w.client.List(ctx, &vmRestores, &client.ListOptions{ - Namespace: kvvm.GetNamespace(), - }) - if err != nil { - log.Error(fmt.Sprintf("failed to list vmRestores: %s", err)) - return requests - } - - for _, vmRestore := range vmRestores.Items { - vmSnapshotName := vmRestore.Spec.VirtualMachineSnapshotName - var vmSnapshot v1alpha2.VirtualMachineSnapshot - err := w.client.Get(ctx, types.NamespacedName{Name: vmSnapshotName, Namespace: kvvm.GetNamespace()}, &vmSnapshot) - if err != nil { - log.Error(fmt.Sprintf("failed to get vmSnapshot: %s", err)) - return requests - } - - if w.isKvvmNameMatch(kvvm.Name, vmSnapshot.Spec.VirtualMachineName, vmRestore.Spec.NameReplacements) { - requests = append(requests, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Name: vmRestore.Name, - Namespace: vmRestore.Namespace, - }, - }) - } - } - - return requests -} - -func (w InternalVirtualMachineWatcher) isKvvmNameMatch(kvvmName, restoredName string, nameReplacements []v1alpha2.NameReplacement) bool { - var ( - isNameMatch bool - isNameReplacementMatch bool - ) - - isNameMatch = kvvmName == restoredName - - for _, nr := range nameReplacements { - if nr.From.Kind != v1alpha2.VirtualMachineKind { - continue - } - - if nr.From.Name == kvvmName { - isNameReplacementMatch = true - break - } - } - - return isNameMatch || isNameReplacementMatch -} diff --git a/images/virtualization-artifact/pkg/controller/vmrestore/internal/watcher/vd_watcher.go b/images/virtualization-artifact/pkg/controller/vmrestore/internal/watcher/vd_watcher.go deleted file mode 100644 index 883e12204e..0000000000 --- a/images/virtualization-artifact/pkg/controller/vmrestore/internal/watcher/vd_watcher.go +++ /dev/null @@ -1,116 +0,0 @@ -/* -Copyright 2025 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package watcher - -import ( - "context" - "fmt" - - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" - - "github.com/deckhouse/deckhouse/pkg/log" - "github.com/deckhouse/virtualization/api/core/v1alpha2" -) - -type VirtualDiskWatcher struct { - client client.Client -} - -func NewVirtualDiskWatcher(client client.Client) *VirtualDiskWatcher { - return &VirtualDiskWatcher{ - client: client, - } -} - -func (w VirtualDiskWatcher) Watch(mgr manager.Manager, ctr controller.Controller) error { - if err := ctr.Watch( - source.Kind(mgr.GetCache(), &v1alpha2.VirtualDisk{}, - handler.TypedEnqueueRequestsFromMapFunc(w.enqueueRequests), - ), - ); err != nil { - return fmt.Errorf("error setting watch on VirtualDisk: %w", err) - } - return nil -} - -func (w VirtualDiskWatcher) enqueueRequests(ctx context.Context, vd *v1alpha2.VirtualDisk) (requests []reconcile.Request) { - var vmRestores v1alpha2.VirtualMachineRestoreList - err := w.client.List(ctx, &vmRestores, &client.ListOptions{ - Namespace: vd.GetNamespace(), - }) - if err != nil { - log.Error(fmt.Sprintf("failed to list vmRestores: %s", err)) - return requests - } - - for _, vmRestore := range vmRestores.Items { - vmSnapshotName := vmRestore.Spec.VirtualMachineSnapshotName - var vmSnapshot v1alpha2.VirtualMachineSnapshot - err := w.client.Get(ctx, types.NamespacedName{Name: vmSnapshotName, Namespace: vd.GetNamespace()}, &vmSnapshot) - if err != nil { - log.Error(fmt.Sprintf("failed to get vmSnapshot: %s", err)) - return requests - } - for _, vdsnapshotName := range vmSnapshot.Status.VirtualDiskSnapshotNames { - var vdSnapshot v1alpha2.VirtualDiskSnapshot - err := w.client.Get(ctx, types.NamespacedName{Name: vdsnapshotName, Namespace: vd.GetNamespace()}, &vdSnapshot) - if err != nil { - log.Error(fmt.Sprintf("failed to get vdSnapshot: %s", err)) - return requests - } - - if w.isVdNameMatch(vd.Name, vdSnapshot.Spec.VirtualDiskName, vmRestore.Spec.NameReplacements) { - requests = append(requests, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Name: vmRestore.Name, - Namespace: vmRestore.Namespace, - }, - }) - } - } - } - - return requests -} - -func (w VirtualDiskWatcher) isVdNameMatch(vdName, restoredName string, nameReplacements []v1alpha2.NameReplacement) bool { - var ( - isNameMatch bool - isNameReplacementMatch bool - ) - - isNameMatch = vdName == restoredName - - for _, nr := range nameReplacements { - if nr.From.Kind != v1alpha2.VirtualDiskKind { - continue - } - - if nr.From.Name == vdName { - isNameReplacementMatch = true - break - } - } - - return isNameMatch || isNameReplacementMatch -} diff --git a/images/virtualization-artifact/pkg/controller/vmrestore/internal/watcher/vm_watcher.go b/images/virtualization-artifact/pkg/controller/vmrestore/internal/watcher/vm_watcher.go deleted file mode 100644 index 55c8e9cf72..0000000000 --- a/images/virtualization-artifact/pkg/controller/vmrestore/internal/watcher/vm_watcher.go +++ /dev/null @@ -1,108 +0,0 @@ -/* -Copyright 2025 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package watcher - -import ( - "context" - "fmt" - - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" - - "github.com/deckhouse/deckhouse/pkg/log" - "github.com/deckhouse/virtualization/api/core/v1alpha2" -) - -type VirtualMachineWatcher struct { - client client.Client -} - -func NewVirtualMachineWatcher(client client.Client) *VirtualMachineWatcher { - return &VirtualMachineWatcher{ - client: client, - } -} - -func (w VirtualMachineWatcher) Watch(mgr manager.Manager, ctr controller.Controller) error { - if err := ctr.Watch( - source.Kind(mgr.GetCache(), &v1alpha2.VirtualMachine{}, - handler.TypedEnqueueRequestsFromMapFunc(w.enqueueRequests), - ), - ); err != nil { - return fmt.Errorf("error setting watch on VirtualMachine: %w", err) - } - return nil -} - -func (w VirtualMachineWatcher) enqueueRequests(ctx context.Context, vm *v1alpha2.VirtualMachine) (requests []reconcile.Request) { - var vmRestores v1alpha2.VirtualMachineRestoreList - err := w.client.List(ctx, &vmRestores, &client.ListOptions{ - Namespace: vm.GetNamespace(), - }) - if err != nil { - log.Error(fmt.Sprintf("failed to list vmRestores: %s", err)) - return requests - } - - for _, vmRestore := range vmRestores.Items { - vmSnapshotName := vmRestore.Spec.VirtualMachineSnapshotName - var vmSnapshot v1alpha2.VirtualMachineSnapshot - err := w.client.Get(ctx, types.NamespacedName{Name: vmSnapshotName, Namespace: vm.GetNamespace()}, &vmSnapshot) - if err != nil { - log.Error(fmt.Sprintf("failed to get vmSnapshot: %s", err)) - return requests - } - - if w.isVMNameMatch(vm.Name, vmSnapshot.Spec.VirtualMachineName, vmRestore.Spec.NameReplacements) { - requests = append(requests, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Name: vmRestore.Name, - Namespace: vmRestore.Namespace, - }, - }) - } - } - - return requests -} - -func (w VirtualMachineWatcher) isVMNameMatch(vmName, restoredName string, nameReplacements []v1alpha2.NameReplacement) bool { - var ( - isNameMatch bool - isNameReplacementMatch bool - ) - - isNameMatch = vmName == restoredName - - for _, nr := range nameReplacements { - if nr.From.Kind != v1alpha2.VirtualMachineKind { - continue - } - - if nr.From.Name == vmName { - isNameReplacementMatch = true - break - } - } - - return isNameMatch || isNameReplacementMatch -} diff --git a/images/virtualization-artifact/pkg/controller/vmrestore/internal/watcher/vmbda_watcher.go b/images/virtualization-artifact/pkg/controller/vmrestore/internal/watcher/vmbda_watcher.go deleted file mode 100644 index e8a73040da..0000000000 --- a/images/virtualization-artifact/pkg/controller/vmrestore/internal/watcher/vmbda_watcher.go +++ /dev/null @@ -1,137 +0,0 @@ -/* -Copyright 2025 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package watcher - -import ( - "context" - "fmt" - - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" - - "github.com/deckhouse/deckhouse/pkg/log" - "github.com/deckhouse/virtualization-controller/pkg/common/object" - vmrestore "github.com/deckhouse/virtualization-controller/pkg/controller/vmrestore/internal" - "github.com/deckhouse/virtualization/api/core/v1alpha2" -) - -type VirtualMachineBlockDeviceAttachmentWatcher struct { - client client.Client - restorer vmrestore.Restorer -} - -func NewVirtualMachineBlockDeviceAttachmentWatcher(client client.Client, restorer vmrestore.Restorer) *VirtualMachineBlockDeviceAttachmentWatcher { - return &VirtualMachineBlockDeviceAttachmentWatcher{ - client: client, - restorer: restorer, - } -} - -func (w VirtualMachineBlockDeviceAttachmentWatcher) Watch(mgr manager.Manager, ctr controller.Controller) error { - if err := ctr.Watch( - source.Kind(mgr.GetCache(), &v1alpha2.VirtualMachineBlockDeviceAttachment{}, - handler.TypedEnqueueRequestsFromMapFunc(w.enqueueRequests), - ), - ); err != nil { - return fmt.Errorf("error setting watch on VirtualMachineBlockDeviceAttachment: %w", err) - } - return nil -} - -func (w VirtualMachineBlockDeviceAttachmentWatcher) enqueueRequests(ctx context.Context, vmbda *v1alpha2.VirtualMachineBlockDeviceAttachment) (requests []reconcile.Request) { - var vmRestores v1alpha2.VirtualMachineRestoreList - err := w.client.List(ctx, &vmRestores, &client.ListOptions{ - Namespace: vmbda.GetNamespace(), - }) - if err != nil { - log.Error(fmt.Sprintf("failed to list vmRestores: %s", err)) - return requests - } - - for _, vmRestore := range vmRestores.Items { - vmSnapshotName := vmRestore.Spec.VirtualMachineSnapshotName - var vmSnapshot v1alpha2.VirtualMachineSnapshot - err := w.client.Get(ctx, types.NamespacedName{Name: vmSnapshotName, Namespace: vmbda.GetNamespace()}, &vmSnapshot) - if err != nil { - log.Error(fmt.Sprintf("failed to get vmSnapshot: %s", err)) - return requests - } - - if vmSnapshot.Status.VirtualMachineSnapshotSecretName == "" { - continue - } - - restorerSecretKey := types.NamespacedName{Namespace: vmSnapshot.Namespace, Name: vmSnapshot.Status.VirtualMachineSnapshotSecretName} - restorerSecret, err := object.FetchObject(ctx, restorerSecretKey, w.client, &corev1.Secret{}) - if err != nil { - log.Error(fmt.Sprintf("failed to get virtualMachineSnapshotSecret: %s", err)) - return requests - } - - if restorerSecret == nil { - log.Error(fmt.Sprintf("virtualMachineSnapshotSecret %q not found", vmSnapshot.Status.VirtualMachineSnapshotSecretName)) - return requests - } - - vmbdas, err := w.restorer.RestoreVirtualMachineBlockDeviceAttachments(ctx, restorerSecret) - if err != nil { - log.Error(fmt.Sprintf("failed to extract vmbda resources from the virtualMachineSnapshotSecret: %s", err)) - return requests - } - - for _, eVmbda := range vmbdas { - if w.isVmbdaNameMatch(vmbda.Name, eVmbda.Name, vmRestore.Spec.NameReplacements) { - requests = append(requests, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Name: vmRestore.Name, - Namespace: vmRestore.Namespace, - }, - }) - } - } - } - - return requests -} - -func (w VirtualMachineBlockDeviceAttachmentWatcher) isVmbdaNameMatch(vmbdaName, restoredName string, nameReplacements []v1alpha2.NameReplacement) bool { - var ( - isNameMatch bool - isNameReplacementMatch bool - ) - - isNameMatch = vmbdaName == restoredName - - for _, nr := range nameReplacements { - if nr.From.Kind != v1alpha2.VirtualMachineBlockDeviceAttachmentKind { - continue - } - - if nr.From.Name == vmbdaName { - isNameReplacementMatch = true - break - } - } - - return isNameMatch || isNameReplacementMatch -} diff --git a/images/virtualization-artifact/pkg/controller/vmrestore/internal/watcher/vmrestore_watcher.go b/images/virtualization-artifact/pkg/controller/vmrestore/internal/watcher/vmrestore_watcher.go deleted file mode 100644 index ce112c96e3..0000000000 --- a/images/virtualization-artifact/pkg/controller/vmrestore/internal/watcher/vmrestore_watcher.go +++ /dev/null @@ -1,64 +0,0 @@ -/* -Copyright 2024 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package watcher - -import ( - "fmt" - - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/event" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/predicate" - "sigs.k8s.io/controller-runtime/pkg/source" - - "github.com/deckhouse/virtualization/api/core/v1alpha2" -) - -type VirtualMachineRestoreWatcher struct { - client client.Client -} - -func NewVirtualMachineRestoreWatcher(client client.Client) *VirtualMachineRestoreWatcher { - return &VirtualMachineRestoreWatcher{ - client: client, - } -} - -func (w VirtualMachineRestoreWatcher) Watch(mgr manager.Manager, ctr controller.Controller) error { - if err := ctr.Watch( - source.Kind(mgr.GetCache(), &v1alpha2.VirtualMachineRestore{}, - &handler.TypedEnqueueRequestForObject[*v1alpha2.VirtualMachineRestore]{}, - predicate.TypedFuncs[*v1alpha2.VirtualMachineRestore]{ - UpdateFunc: func(e event.TypedUpdateEvent[*v1alpha2.VirtualMachineRestore]) bool { - oldPhase := e.ObjectOld.Status.Phase - newPhase := e.ObjectNew.Status.Phase - - if oldPhase != newPhase { - return true - } - - return e.ObjectOld.GetGeneration() != e.ObjectNew.GetGeneration() - }, - }, - ), - ); err != nil { - return fmt.Errorf("error setting watch on VirtualMachineRestore: %w", err) - } - return nil -} diff --git a/images/virtualization-artifact/pkg/controller/vmrestore/internal/watcher/vmsnapshot_watcher.go b/images/virtualization-artifact/pkg/controller/vmrestore/internal/watcher/vmsnapshot_watcher.go deleted file mode 100644 index 4d664d3787..0000000000 --- a/images/virtualization-artifact/pkg/controller/vmrestore/internal/watcher/vmsnapshot_watcher.go +++ /dev/null @@ -1,86 +0,0 @@ -/* -Copyright 2024 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package watcher - -import ( - "context" - "fmt" - - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/event" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/predicate" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" - - "github.com/deckhouse/deckhouse/pkg/log" - "github.com/deckhouse/virtualization-controller/pkg/controller/indexer" - "github.com/deckhouse/virtualization/api/core/v1alpha2" -) - -type VirtualMachineSnapshotWatcher struct { - client client.Client -} - -func NewVirtualMachineSnapshotWatcher(client client.Client) *VirtualMachineSnapshotWatcher { - return &VirtualMachineSnapshotWatcher{ - client: client, - } -} - -func (w VirtualMachineSnapshotWatcher) Watch(mgr manager.Manager, ctr controller.Controller) error { - if err := ctr.Watch( - source.Kind(mgr.GetCache(), &v1alpha2.VirtualMachineSnapshot{}, - handler.TypedEnqueueRequestsFromMapFunc(w.enqueueRequests), - predicate.TypedFuncs[*v1alpha2.VirtualMachineSnapshot]{ - UpdateFunc: func(e event.TypedUpdateEvent[*v1alpha2.VirtualMachineSnapshot]) bool { - return e.ObjectOld.Status.Phase != e.ObjectNew.Status.Phase - }, - }, - ), - ); err != nil { - return fmt.Errorf("error setting watch on VirtualMachineSnapshot: %w", err) - } - return nil -} - -func (w VirtualMachineSnapshotWatcher) enqueueRequests(ctx context.Context, vmSnapshot *v1alpha2.VirtualMachineSnapshot) (requests []reconcile.Request) { - var vmRestores v1alpha2.VirtualMachineRestoreList - err := w.client.List(ctx, &vmRestores, &client.ListOptions{ - Namespace: vmSnapshot.GetNamespace(), - FieldSelector: fields.OneTermEqualSelector(indexer.IndexFieldVMRestoreByVMSnapshot, vmSnapshot.GetName()), - }) - if err != nil { - log.Error(fmt.Sprintf("failed to list virtual machine restores: %s", err)) - return requests - } - - for _, vmRestore := range vmRestores.Items { - requests = append(requests, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Name: vmRestore.Name, - Namespace: vmRestore.Namespace, - }, - }) - } - - return requests -} diff --git a/images/virtualization-artifact/pkg/controller/vmrestore/vmrestore_controller.go b/images/virtualization-artifact/pkg/controller/vmrestore/vmrestore_controller.go deleted file mode 100644 index fc04c570d1..0000000000 --- a/images/virtualization-artifact/pkg/controller/vmrestore/vmrestore_controller.go +++ /dev/null @@ -1,76 +0,0 @@ -/* -Copyright 2024 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package vmrestore - -import ( - "context" - "time" - - "k8s.io/utils/ptr" - "sigs.k8s.io/controller-runtime/pkg/builder" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/manager" - - "github.com/deckhouse/deckhouse/pkg/log" - "github.com/deckhouse/virtualization-controller/pkg/controller/service/restorer" - "github.com/deckhouse/virtualization-controller/pkg/controller/vmrestore/internal" - "github.com/deckhouse/virtualization-controller/pkg/eventrecord" - "github.com/deckhouse/virtualization-controller/pkg/logger" - "github.com/deckhouse/virtualization/api/core/v1alpha2" -) - -const ControllerName = "vmrestore-controller" - -func NewController( - ctx context.Context, - mgr manager.Manager, - log *log.Logger, -) error { - recorder := eventrecord.NewEventRecorderLogger(mgr, ControllerName) - reconciler := NewReconciler( - mgr.GetClient(), - internal.NewVirtualMachineSnapshotReadyToUseHandler(mgr.GetClient()), - internal.NewLifeCycleHandler(mgr.GetClient(), restorer.NewSecretRestorer(mgr.GetClient()), recorder), - ) - - vmRestoreController, err := controller.New(ControllerName, mgr, controller.Options{ - Reconciler: reconciler, - RecoverPanic: ptr.To(true), - LogConstructor: logger.NewConstructor(log), - CacheSyncTimeout: 10 * time.Minute, - UsePriorityQueue: ptr.To(true), - }) - if err != nil { - return err - } - - err = reconciler.SetupController(ctx, mgr, vmRestoreController) - if err != nil { - return err - } - - if err = builder.WebhookManagedBy(mgr). - For(&v1alpha2.VirtualMachineRestore{}). - WithValidator(NewValidator()). - Complete(); err != nil { - return err - } - - log.Info("Initialized VirtualMachineRestore controller") - - return nil -} diff --git a/images/virtualization-artifact/pkg/controller/vmrestore/vmrestore_reconciler.go b/images/virtualization-artifact/pkg/controller/vmrestore/vmrestore_reconciler.go deleted file mode 100644 index 6925c15748..0000000000 --- a/images/virtualization-artifact/pkg/controller/vmrestore/vmrestore_reconciler.go +++ /dev/null @@ -1,105 +0,0 @@ -/* -Copyright 2024 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package vmrestore - -import ( - "context" - "fmt" - "reflect" - - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - - "github.com/deckhouse/virtualization-controller/pkg/controller/reconciler" - "github.com/deckhouse/virtualization-controller/pkg/controller/service/restorer" - "github.com/deckhouse/virtualization-controller/pkg/controller/vmrestore/internal/watcher" - "github.com/deckhouse/virtualization/api/core/v1alpha2" -) - -type Handler interface { - Handle(ctx context.Context, vmRestore *v1alpha2.VirtualMachineRestore) (reconcile.Result, error) -} - -type Watcher interface { - Watch(mgr manager.Manager, ctr controller.Controller) error -} - -type Reconciler struct { - handlers []Handler - client client.Client -} - -func NewReconciler(client client.Client, handlers ...Handler) *Reconciler { - return &Reconciler{ - client: client, - handlers: handlers, - } -} - -func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) { - vmRestore := reconciler.NewResource(req.NamespacedName, r.client, r.factory, r.statusGetter) - - err := vmRestore.Fetch(ctx) - if err != nil { - return reconcile.Result{}, err - } - - if vmRestore.IsEmpty() { - return reconcile.Result{}, nil - } - - rec := reconciler.NewBaseReconciler[Handler](r.handlers) - rec.SetHandlerExecutor(func(ctx context.Context, h Handler) (reconcile.Result, error) { - return h.Handle(ctx, vmRestore.Changed()) - }) - rec.SetResourceUpdater(func(ctx context.Context) error { - vmRestore.Changed().Status.ObservedGeneration = vmRestore.Changed().Generation - - return vmRestore.Update(ctx) - }) - - return rec.Reconcile(ctx) -} - -func (r *Reconciler) SetupController(_ context.Context, mgr manager.Manager, ctr controller.Controller) error { - restorer := restorer.NewSecretRestorer(r.client) - for _, w := range []Watcher{ - watcher.NewVirtualMachineRestoreWatcher(mgr.GetClient()), - watcher.NewVirtualMachineSnapshotWatcher(mgr.GetClient()), - watcher.NewVirtualMachineWatcher(mgr.GetClient()), - watcher.NewVirtualDiskWatcher(mgr.GetClient()), - watcher.NewVirtualMachineBlockDeviceAttachmentWatcher(mgr.GetClient(), restorer), - watcher.NewInternalVirtualMachineWatcher(mgr.GetClient()), - } { - err := w.Watch(mgr, ctr) - if err != nil { - return fmt.Errorf("failed to run watcher %s: %w", reflect.TypeOf(w).Elem().Name(), err) - } - } - - return nil -} - -func (r *Reconciler) factory() *v1alpha2.VirtualMachineRestore { - return &v1alpha2.VirtualMachineRestore{} -} - -func (r *Reconciler) statusGetter(obj *v1alpha2.VirtualMachineRestore) v1alpha2.VirtualMachineRestoreStatus { - return obj.Status -} diff --git a/images/virtualization-artifact/pkg/controller/vmrestore/vmrestore_webhook.go b/images/virtualization-artifact/pkg/controller/vmrestore/vmrestore_webhook.go deleted file mode 100644 index 62a4b1dfce..0000000000 --- a/images/virtualization-artifact/pkg/controller/vmrestore/vmrestore_webhook.go +++ /dev/null @@ -1,64 +0,0 @@ -/* -Copyright 2024 Flant JSC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package vmrestore - -import ( - "context" - "fmt" - - "k8s.io/apimachinery/pkg/runtime" - "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - - "github.com/deckhouse/virtualization-controller/pkg/logger" - "github.com/deckhouse/virtualization/api/core/v1alpha2" -) - -type Validator struct{} - -func NewValidator() *Validator { - return &Validator{} -} - -func (v *Validator) ValidateCreate(ctx context.Context, _ runtime.Object) (admission.Warnings, error) { - return nil, nil -} - -func (v *Validator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) { - oldVMRestore, ok := oldObj.(*v1alpha2.VirtualMachineRestore) - if !ok { - return nil, fmt.Errorf("expected an old VirtualMachineRestore but got a %T", newObj) - } - - newVMRestore, ok := newObj.(*v1alpha2.VirtualMachineRestore) - if !ok { - return nil, fmt.Errorf("expected a new VirtualMachineRestore but got a %T", newObj) - } - - logger.FromContext(ctx).Info("Validating VirtualMachineRestore") - - if oldVMRestore.Generation != newVMRestore.Generation { - return nil, fmt.Errorf("VirtualMachineRestore is an idempotent resource: specification changes are not available") - } - - return nil, nil -} - -func (v *Validator) ValidateDelete(ctx context.Context, _ runtime.Object) (admission.Warnings, error) { - err := fmt.Errorf("misconfigured webhook rules: delete operation not implemented") - logger.FromContext(ctx).Error("Ensure the correctness of ValidatingWebhookConfiguration", "err", err) - return nil, nil -} diff --git a/templates/virtualization-controller/validation-webhook.yaml b/templates/virtualization-controller/validation-webhook.yaml index 9ca31adaa8..a06879cfdb 100644 --- a/templates/virtualization-controller/validation-webhook.yaml +++ b/templates/virtualization-controller/validation-webhook.yaml @@ -192,23 +192,6 @@ webhooks: {{ .Values.virtualization.internal.controller.cert.ca | b64enc }} admissionReviewVersions: ["v1"] sideEffects: None - - name: "vmrestore.virtualization-controller.validate.d8-virtualization" - rules: - - apiGroups: ["virtualization.deckhouse.io"] - apiVersions: ["v1alpha2"] - operations: ["CREATE", "UPDATE"] - resources: ["virtualmachinerestores"] - scope: "Namespaced" - clientConfig: - service: - namespace: d8-{{ .Chart.Name }} - name: virtualization-controller - path: /validate-virtualization-deckhouse-io-v1alpha2-virtualmachinerestore - port: 443 - caBundle: | - {{ .Values.virtualization.internal.controller.cert.ca | b64enc }} - admissionReviewVersions: ["v1"] - sideEffects: None - name: "vmclass-v1alpha2.virtualization-controller.validate.d8-virtualization" rules: - apiGroups: ["virtualization.deckhouse.io"]