From ca88458e4b76906ea00d9692506f585e2540b47f Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Fri, 12 Dec 2025 14:22:31 +0300 Subject: [PATCH] watch Signed-off-by: Valeriy Khorunzhin --- .../pkg/controller/indexer/indexer.go | 48 +++++++--- .../vm/internal/watcher/secret_watcher.go | 90 +++++++++++++++++++ .../pkg/controller/vm/vm_reconciler.go | 1 + 3 files changed, 126 insertions(+), 13 deletions(-) create mode 100644 images/virtualization-artifact/pkg/controller/vm/internal/watcher/secret_watcher.go diff --git a/images/virtualization-artifact/pkg/controller/indexer/indexer.go b/images/virtualization-artifact/pkg/controller/indexer/indexer.go index bc24be429f..9fba3bc79b 100644 --- a/images/virtualization-artifact/pkg/controller/indexer/indexer.go +++ b/images/virtualization-artifact/pkg/controller/indexer/indexer.go @@ -22,7 +22,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/manager" - virtv2 "github.com/deckhouse/virtualization/api/core/v1alpha2" + "github.com/deckhouse/virtualization/api/core/v1alpha2" ) const ( @@ -57,6 +57,8 @@ const ( IndexFieldVMMACByAddress = "spec.address|status.address" IndexFieldVMMACLeaseByVMMAC = "spec.virtualMachineMACAddressRef.Name" + + IndexFieldVMByProvisioningSecret = "spec.provisioning.secretRef" ) var IndexGetters = []IndexGetter{ @@ -65,6 +67,7 @@ var IndexGetters = []IndexGetter{ IndexVMByVI, IndexVMByCVI, IndexVMByNode, + IndexVMByProvisioningSecret, IndexVMSnapshotByVM, IndexVMSnapshotByVDSnapshot, IndexVMRestoreByVMSnapshot, @@ -94,8 +97,8 @@ func IndexALL(ctx context.Context, mgr manager.Manager) error { } func IndexVMByClass() (obj client.Object, field string, extractValue client.IndexerFunc) { - return &virtv2.VirtualMachine{}, IndexFieldVMByClass, func(object client.Object) []string { - vm, ok := object.(*virtv2.VirtualMachine) + return &v1alpha2.VirtualMachine{}, IndexFieldVMByClass, func(object client.Object) []string { + vm, ok := object.(*v1alpha2.VirtualMachine) if !ok || vm == nil { return nil } @@ -104,26 +107,26 @@ func IndexVMByClass() (obj client.Object, field string, extractValue client.Inde } func IndexVMByVD() (obj client.Object, field string, extractValue client.IndexerFunc) { - return &virtv2.VirtualMachine{}, IndexFieldVMByVD, func(object client.Object) []string { - return getBlockDeviceNamesByKind(object, virtv2.DiskDevice) + return &v1alpha2.VirtualMachine{}, IndexFieldVMByVD, func(object client.Object) []string { + return getBlockDeviceNamesByKind(object, v1alpha2.DiskDevice) } } func IndexVMByVI() (obj client.Object, field string, extractValue client.IndexerFunc) { - return &virtv2.VirtualMachine{}, IndexFieldVMByVI, func(object client.Object) []string { - return getBlockDeviceNamesByKind(object, virtv2.ImageDevice) + return &v1alpha2.VirtualMachine{}, IndexFieldVMByVI, func(object client.Object) []string { + return getBlockDeviceNamesByKind(object, v1alpha2.ImageDevice) } } func IndexVMByCVI() (obj client.Object, field string, extractValue client.IndexerFunc) { - return &virtv2.VirtualMachine{}, IndexFieldVMByCVI, func(object client.Object) []string { - return getBlockDeviceNamesByKind(object, virtv2.ClusterImageDevice) + return &v1alpha2.VirtualMachine{}, IndexFieldVMByCVI, func(object client.Object) []string { + return getBlockDeviceNamesByKind(object, v1alpha2.ClusterImageDevice) } } func IndexVMByNode() (obj client.Object, field string, extractValue client.IndexerFunc) { - return &virtv2.VirtualMachine{}, IndexFieldVMByNode, func(object client.Object) []string { - vm, ok := object.(*virtv2.VirtualMachine) + return &v1alpha2.VirtualMachine{}, IndexFieldVMByNode, func(object client.Object) []string { + vm, ok := object.(*v1alpha2.VirtualMachine) if !ok || vm == nil || vm.Status.Node == "" { return nil } @@ -131,8 +134,27 @@ func IndexVMByNode() (obj client.Object, field string, extractValue client.Index } } -func getBlockDeviceNamesByKind(obj client.Object, kind virtv2.BlockDeviceKind) []string { - vm, ok := obj.(*virtv2.VirtualMachine) +func IndexVMByProvisioningSecret() (obj client.Object, field string, extractValue client.IndexerFunc) { + return &v1alpha2.VirtualMachine{}, IndexFieldVMByProvisioningSecret, func(object client.Object) []string { + vm, ok := object.(*v1alpha2.VirtualMachine) + if !ok || vm == nil || vm.Spec.Provisioning == nil { + return nil + } + + var secrets []string + if vm.Spec.Provisioning.UserDataRef != nil && vm.Spec.Provisioning.UserDataRef.Kind == v1alpha2.UserDataRefKindSecret { + secrets = append(secrets, vm.Spec.Provisioning.UserDataRef.Name) + } + if vm.Spec.Provisioning.SysprepRef != nil && vm.Spec.Provisioning.SysprepRef.Kind == v1alpha2.SysprepRefKindSecret { + secrets = append(secrets, vm.Spec.Provisioning.SysprepRef.Name) + } + + return secrets + } +} + +func getBlockDeviceNamesByKind(obj client.Object, kind v1alpha2.BlockDeviceKind) []string { + vm, ok := obj.(*v1alpha2.VirtualMachine) if !ok || vm == nil { return nil } diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/watcher/secret_watcher.go b/images/virtualization-artifact/pkg/controller/vm/internal/watcher/secret_watcher.go new file mode 100644 index 0000000000..f8684edf7c --- /dev/null +++ b/images/virtualization-artifact/pkg/controller/vm/internal/watcher/secret_watcher.go @@ -0,0 +1,90 @@ +/* +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" + "log/slog" + + corev1 "k8s.io/api/core/v1" + "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/virtualization-controller/pkg/controller/indexer" + "github.com/deckhouse/virtualization/api/core/v1alpha2" +) + +func NewSecretWatcher(client client.Client) *SecretWatcher { + return &SecretWatcher{ + client: client, + logger: slog.Default().With("watcher", "secret"), + } +} + +type SecretWatcher struct { + client client.Client + logger *slog.Logger +} + +func (w *SecretWatcher) Watch(mgr manager.Manager, ctr controller.Controller) error { + if err := ctr.Watch( + source.Kind( + mgr.GetCache(), + &corev1.Secret{}, + handler.TypedEnqueueRequestsFromMapFunc(w.enqueue), + predicate.TypedFuncs[*corev1.Secret]{ + DeleteFunc: func(e event.TypedDeleteEvent[*corev1.Secret]) bool { return false }, + }, + ), + ); err != nil { + return fmt.Errorf("error setting watch on Secret: %w", err) + } + return nil +} + +func (w *SecretWatcher) enqueue(ctx context.Context, secret *corev1.Secret) []reconcile.Request { + var vms v1alpha2.VirtualMachineList + err := w.client.List(ctx, &vms, &client.ListOptions{ + Namespace: secret.Namespace, + FieldSelector: fields.OneTermEqualSelector(indexer.IndexFieldVMByProvisioningSecret, secret.Name), + }) + if err != nil { + w.logger.Error(fmt.Sprintf("failed to list virtual machines: %v", err)) + return nil + } + + var result []reconcile.Request + for _, vm := range vms.Items { + result = append(result, reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: vm.GetName(), + Namespace: vm.GetNamespace(), + }, + }) + } + + return result +} diff --git a/images/virtualization-artifact/pkg/controller/vm/vm_reconciler.go b/images/virtualization-artifact/pkg/controller/vm/vm_reconciler.go index b9b0ad792a..d8fcbd3b56 100644 --- a/images/virtualization-artifact/pkg/controller/vm/vm_reconciler.go +++ b/images/virtualization-artifact/pkg/controller/vm/vm_reconciler.go @@ -73,6 +73,7 @@ func (r *Reconciler) SetupController(_ context.Context, mgr manager.Manager, ctr watcher.NewVirtualMachineSnapshotWatcher(), watcher.NewVMOPWatcher(), watcher.NewVMMACWatcher(), + watcher.NewSecretWatcher(mgr.GetClient()), } { err := w.Watch(mgr, ctr) if err != nil {