From 9a2f74097f0189446b502d8708fd6ca3f7602109 Mon Sep 17 00:00:00 2001 From: Danil-Grigorev Date: Thu, 29 Aug 2024 14:36:40 +0200 Subject: [PATCH] Perform ETCD snapshot restore out of webhook ownership references creation Signed-off-by: Danil-Grigorev --- .../etcdsnapshot_secret_controller.go | 110 ++++++++++++++++++ exp/etcdrestore/main.go | 8 ++ exp/etcdrestore/webhooks/rke2config.go | 12 +- exp/etcdrestore/webhooks/rke2config_test.go | 4 +- 4 files changed, 129 insertions(+), 5 deletions(-) create mode 100644 exp/etcdrestore/controllers/etcdsnapshot_secret_controller.go diff --git a/exp/etcdrestore/controllers/etcdsnapshot_secret_controller.go b/exp/etcdrestore/controllers/etcdsnapshot_secret_controller.go new file mode 100644 index 00000000..fd02e71b --- /dev/null +++ b/exp/etcdrestore/controllers/etcdsnapshot_secret_controller.go @@ -0,0 +1,110 @@ +/* +Copyright © 2023 - 2024 SUSE LLC + +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 controllers + +import ( + "context" + "fmt" + + corev1 "k8s.io/api/core/v1" + + bootstrapv1 "github.com/rancher/cluster-api-provider-rke2/bootstrap/api/v1beta1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/predicate" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + "github.com/rancher/turtles/exp/etcdrestore/webhooks" +) + +// ETCDSnapshotSecretReconciler reconciles an EtcdMachineSnapshot object. +type ETCDSnapshotSecretReconciler struct { + client.Client +} + +func secretFilter(obj client.Object) bool { + rke2ConfigName, found := obj.GetLabels()[webhooks.RKE2ConfigNameLabel] + + owned := false + for _, owner := range obj.GetOwnerReferences() { + if owner.Name == rke2ConfigName { + owned = true + break + } + } + + return found && !owned +} + +// SetupWithManager sets up the controller with the Manager. +func (r *ETCDSnapshotSecretReconciler) SetupWithManager(_ context.Context, mgr ctrl.Manager, _ controller.Options) error { + err := ctrl.NewControllerManagedBy(mgr). + For(&corev1.Secret{}). + WithEventFilter(predicate.NewPredicateFuncs(secretFilter)). + Complete(reconcile.AsReconciler(mgr.GetClient(), r)) + if err != nil { + return fmt.Errorf("creating ETCDSnapshotSecretReconciler controller: %w", err) + } + + return nil +} + +// Reconcile reconciles the EtcdMachineSnapshot object. +func (r *ETCDSnapshotSecretReconciler) Reconcile(ctx context.Context, secret *corev1.Secret) (ctrl.Result, error) { + log := log.FromContext(ctx) + + rke2ConfigName, found := secret.GetLabels()[webhooks.RKE2ConfigNameLabel] + if !found { + return ctrl.Result{}, nil + } + + rke2Config := &bootstrapv1.RKE2Config{} + + if err := r.Client.Get(ctx, client.ObjectKey{ + Name: rke2ConfigName, + Namespace: secret.Namespace, + }, rke2Config); apierrors.IsNotFound(err) { + return ctrl.Result{}, nil + } else if err != nil { + log.Error(err, "Unable to fetch RKE2Config instance") + + return ctrl.Result{}, err + } + + if len(secret.OwnerReferences) == 0 { + secret.OwnerReferences = []metav1.OwnerReference{} + } + + secret.OwnerReferences = append(secret.OwnerReferences, metav1.OwnerReference{ + APIVersion: rke2Config.APIVersion, + Kind: rke2Config.Kind, + Name: rke2Config.Name, + UID: rke2Config.UID, + }) + + if err := r.Client.Patch(ctx, secret, client.Apply); err != nil { + log.Error(err, "Unable to patch Secret with RKE2Config ownership") + + return ctrl.Result{}, err + } + + return ctrl.Result{}, nil +} diff --git a/exp/etcdrestore/main.go b/exp/etcdrestore/main.go index 38e885a0..a6a33d36 100644 --- a/exp/etcdrestore/main.go +++ b/exp/etcdrestore/main.go @@ -251,6 +251,14 @@ func setupReconcilers(ctx context.Context, mgr ctrl.Manager) { os.Exit(1) } + setupLog.Info("enabling ETCDSnapshotSecret controller") + + if err := (&expcontrollers.ETCDSnapshotSecretReconciler{ + Client: mgr.GetClient(), + }).SetupWithManager(ctx, mgr, controller.Options{MaxConcurrentReconciles: concurrencyNumber}); err != nil { + setupLog.Error(err, "unable to create ETCDSnapshotSecret controller") + os.Exit(1) + } } func setupWebhooks(mgr ctrl.Manager) { diff --git a/exp/etcdrestore/webhooks/rke2config.go b/exp/etcdrestore/webhooks/rke2config.go index 9f86d276..d5ddfe0c 100644 --- a/exp/etcdrestore/webhooks/rke2config.go +++ b/exp/etcdrestore/webhooks/rke2config.go @@ -43,7 +43,7 @@ import ( ) const ( - rke2ConfigNameLabel = "cluster-api.cattle.io/rke2config-name" + RKE2ConfigNameLabel = "cluster-api.cattle.io/rke2config-name" planSecretNameLabel = "cluster-api.cattle.io/plan-secret-name" serviceAccountSecretLabel = "cluster-api.cattle.io/service-account.name" secretTypeMachinePlan = "cluster-api.cattle.io/machine-plan" @@ -189,7 +189,7 @@ func (r *RKE2ConfigWebhook) createServiceAccount(planSecretName string, rke2Conf Name: planSecretName, Namespace: rke2Config.Namespace, Labels: map[string]string{ - rke2ConfigNameLabel: rke2Config.Name, + RKE2ConfigNameLabel: rke2Config.Name, planSecretNameLabel: planSecretName, }, }, @@ -203,7 +203,7 @@ func (r *RKE2ConfigWebhook) createSecret(planSecretName string, rke2Config *boot Name: planSecretName, Namespace: rke2Config.Namespace, Labels: map[string]string{ - rke2ConfigNameLabel: rke2Config.Name, + RKE2ConfigNameLabel: rke2Config.Name, }, }, Type: secretTypeMachinePlan, @@ -379,6 +379,9 @@ func (r *RKE2ConfigWebhook) createConnectInfoJson(ctx context.Context, rke2Confi ObjectMeta: metav1.ObjectMeta{ Name: connectInfoConfigSecretName, Namespace: rke2Config.Namespace, + Labels: map[string]string{ + RKE2ConfigNameLabel: rke2Config.Name, + }, }, Data: map[string][]byte{ connectInfoConfigKey: connectInfoConfigJson, @@ -428,6 +431,9 @@ func (r *RKE2ConfigWebhook) createSystemAgentInstallScript(ctx context.Context, ObjectMeta: metav1.ObjectMeta{ Name: installScriptSecretName, Namespace: rke2Config.Namespace, + Labels: map[string]string{ + RKE2ConfigNameLabel: rke2Config.Name, + }, }, Data: map[string][]byte{ installScriptKey: []byte(fmt.Sprintf("%s%s%s", serverUrlBash, binaryURL, installSh)), diff --git a/exp/etcdrestore/webhooks/rke2config_test.go b/exp/etcdrestore/webhooks/rke2config_test.go index f6c907db..17179255 100644 --- a/exp/etcdrestore/webhooks/rke2config_test.go +++ b/exp/etcdrestore/webhooks/rke2config_test.go @@ -124,7 +124,7 @@ var _ = Describe("RKE2ConfigWebhook tests", func() { Expect(serviceAccount.ObjectMeta.Name).To(Equal(planSecretName)) Expect(serviceAccount.ObjectMeta.Namespace).To(Equal(rke2Config.Namespace)) - Expect(serviceAccount.ObjectMeta.Labels[rke2ConfigNameLabel]).To(Equal(rke2Config.Name)) + Expect(serviceAccount.ObjectMeta.Labels[RKE2ConfigNameLabel]).To(Equal(rke2Config.Name)) Expect(serviceAccount.ObjectMeta.Labels[planSecretNameLabel]).To(Equal(planSecretName)) }) @@ -133,7 +133,7 @@ var _ = Describe("RKE2ConfigWebhook tests", func() { Expect(secret.ObjectMeta.Name).To(Equal(planSecretName)) Expect(secret.ObjectMeta.Namespace).To(Equal(rke2Config.Namespace)) - Expect(secret.ObjectMeta.Labels[rke2ConfigNameLabel]).To(Equal(rke2Config.Name)) + Expect(secret.ObjectMeta.Labels[RKE2ConfigNameLabel]).To(Equal(rke2Config.Name)) Expect(string(secret.Type)).To(Equal(secretTypeMachinePlan)) })