From b081fe9c7c9f5d3e096d09eec04d33b69d2b4674 Mon Sep 17 00:00:00 2001 From: Wahab Ali Date: Thu, 9 Jan 2025 20:39:17 +0500 Subject: [PATCH] Setup controllers dependent on Sveltos CRDs after its provider is installed --- cmd/main.go | 19 ---- .../clusterdeployment_controller.go | 63 ++++++----- .../clusterdeployment_controller_test.go | 8 +- internal/controller/management_controller.go | 107 +++++++++++++----- .../controller/management_controller_test.go | 10 +- .../multiclusterservice_controller.go | 24 ++-- .../multiclusterservice_controller_test.go | 4 +- 7 files changed, 138 insertions(+), 97 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 00e652f1..59682e3c 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -228,19 +228,7 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "ProviderTemplate") os.Exit(1) } - if err = (&controller.ClusterDeploymentReconciler{ - Client: mgr.GetClient(), - Config: mgr.GetConfig(), - DynamicClient: dc, - SystemNamespace: currentNamespace, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "ClusterDeployment") - os.Exit(1) - } if err = (&controller.ManagementReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - Config: mgr.GetConfig(), DynamicClient: dc, SystemNamespace: currentNamespace, CreateAccessManagement: createAccessManagement, @@ -310,13 +298,6 @@ func main() { os.Exit(1) } - if err = (&controller.MultiClusterServiceReconciler{ - Client: mgr.GetClient(), - SystemNamespace: currentNamespace, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "MultiClusterService") - os.Exit(1) - } // TODO (zerospiel): disabled until the #605 // if err = (&controller.BackupReconciler{ // Client: mgr.GetClient(), diff --git a/internal/controller/clusterdeployment_controller.go b/internal/controller/clusterdeployment_controller.go index 790cc9ff..45ceb0ff 100644 --- a/internal/controller/clusterdeployment_controller.go +++ b/internal/controller/clusterdeployment_controller.go @@ -66,9 +66,9 @@ type helmActor interface { // ClusterDeploymentReconciler reconciles a ClusterDeployment object type ClusterDeploymentReconciler struct { - client.Client + client client.Client helmActor - Config *rest.Config + config *rest.Config DynamicClient *dynamic.DynamicClient SystemNamespace string } @@ -80,7 +80,7 @@ func (r *ClusterDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Re l.Info("Reconciling ClusterDeployment") clusterDeployment := &kcm.ClusterDeployment{} - if err := r.Get(ctx, req.NamespacedName, clusterDeployment); err != nil { + if err := r.client.Get(ctx, req.NamespacedName, clusterDeployment); err != nil { if apierrors.IsNotFound(err) { l.Info("ClusterDeployment not found, ignoring since object must be deleted") return ctrl.Result{}, nil @@ -98,7 +98,7 @@ func (r *ClusterDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Re if clusterDeployment.Status.ObservedGeneration == 0 { mgmt := &kcm.Management{} mgmtRef := client.ObjectKey{Name: kcm.ManagementName} - if err := r.Get(ctx, mgmtRef, mgmt); err != nil { + if err := r.client.Get(ctx, mgmtRef, mgmt); err != nil { l.Error(err, "Failed to get Management object") return ctrl.Result{}, err } @@ -146,13 +146,13 @@ func (r *ClusterDeploymentReconciler) reconcileUpdate(ctx context.Context, mc *k l := ctrl.LoggerFrom(ctx) if controllerutil.AddFinalizer(mc, kcm.ClusterDeploymentFinalizer) { - if err := r.Client.Update(ctx, mc); err != nil { + if err := r.client.Update(ctx, mc); err != nil { return ctrl.Result{}, fmt.Errorf("failed to update clusterDeployment %s/%s: %w", mc.Namespace, mc.Name, err) } return ctrl.Result{}, nil } - if err := utils.AddKCMComponentLabel(ctx, r.Client, mc); err != nil { + if err := utils.AddKCMComponentLabel(ctx, r.client, mc); err != nil { l.Error(err, "adding component label") return ctrl.Result{}, err } @@ -167,7 +167,7 @@ func (r *ClusterDeploymentReconciler) reconcileUpdate(ctx context.Context, mc *k err = errors.Join(err, r.updateStatus(ctx, mc, clusterTpl)) }() - if err = r.Get(ctx, client.ObjectKey{Name: mc.Spec.Template, Namespace: mc.Namespace}, clusterTpl); err != nil { + if err = r.client.Get(ctx, client.ObjectKey{Name: mc.Spec.Template, Namespace: mc.Namespace}, clusterTpl); err != nil { l.Error(err, "Failed to get Template") errMsg := fmt.Sprintf("failed to get provided template: %s", err) if apierrors.IsNotFound(err) { @@ -272,7 +272,7 @@ func (r *ClusterDeploymentReconciler) updateCluster(ctx context.Context, mc *kcm }) cred := &kcm.Credential{} - err = r.Client.Get(ctx, client.ObjectKey{ + err = r.client.Get(ctx, client.ObjectKey{ Name: mc.Spec.Credential, Namespace: mc.Namespace, }, cred) @@ -333,7 +333,7 @@ func (r *ClusterDeploymentReconciler) updateCluster(ctx context.Context, mc *kcm hrReconcileOpts.ReconcileInterval = &clusterTpl.Spec.Helm.ChartSpec.Interval.Duration } - hr, _, err := helm.ReconcileHelmRelease(ctx, r.Client, mc.Name, mc.Namespace, hrReconcileOpts) + hr, _, err := helm.ReconcileHelmRelease(ctx, r.client, mc.Name, mc.Namespace, hrReconcileOpts) if err != nil { apimeta.SetStatusCondition(mc.GetConditions(), metav1.Condition{ Type: kcm.HelmReleaseReadyCondition, @@ -454,12 +454,12 @@ func (r *ClusterDeploymentReconciler) updateServices(ctx context.Context, mc *kc err = errors.Join(err, servicesErr) }() - opts, err := sveltos.GetHelmChartOpts(ctx, r.Client, mc.Namespace, mc.Spec.ServiceSpec.Services) + opts, err := sveltos.GetHelmChartOpts(ctx, r.client, mc.Namespace, mc.Spec.ServiceSpec.Services) if err != nil { return ctrl.Result{}, err } - if _, err = sveltos.ReconcileProfile(ctx, r.Client, mc.Namespace, mc.Name, + if _, err = sveltos.ReconcileProfile(ctx, r.client, mc.Namespace, mc.Name, sveltos.ReconcileProfileOpts{ OwnerReference: &metav1.OwnerReference{ APIVersion: kcm.GroupVersion.String(), @@ -489,13 +489,13 @@ func (r *ClusterDeploymentReconciler) updateServices(ctx context.Context, mc *kc // will ultimately return the error in servicesErr instead of nil. profile := sveltosv1beta1.Profile{} profileRef := client.ObjectKey{Name: mc.Name, Namespace: mc.Namespace} - if servicesErr = r.Get(ctx, profileRef, &profile); servicesErr != nil { + if servicesErr = r.client.Get(ctx, profileRef, &profile); servicesErr != nil { servicesErr = fmt.Errorf("failed to get Profile %s to fetch status from its associated ClusterSummary: %w", profileRef.String(), servicesErr) return ctrl.Result{}, nil } var servicesStatus []kcm.ServiceStatus - servicesStatus, servicesErr = updateServicesStatus(ctx, r.Client, profileRef, profile.Status.MatchingClusterRefs, mc.Status.Services) + servicesStatus, servicesErr = updateServicesStatus(ctx, r.client, profileRef, profile.Status.MatchingClusterRefs, mc.Status.Services) if servicesErr != nil { return ctrl.Result{}, nil } @@ -514,7 +514,7 @@ func (r *ClusterDeploymentReconciler) updateStatus(ctx context.Context, clusterD return errors.New("failed to set available upgrades") } - if err := r.Status().Update(ctx, clusterDeployment); err != nil { + if err := r.client.Status().Update(ctx, clusterDeployment); err != nil { return fmt.Errorf("failed to update status for clusterDeployment %s/%s: %w", clusterDeployment.Namespace, clusterDeployment.Name, err) } @@ -527,7 +527,7 @@ func (r *ClusterDeploymentReconciler) getSource(ctx context.Context, ref *hcv2.C } chartRef := client.ObjectKey{Namespace: ref.Namespace, Name: ref.Name} hc := sourcev1.HelmChart{} - if err := r.Client.Get(ctx, chartRef, &hc); err != nil { + if err := r.client.Get(ctx, chartRef, &hc); err != nil { return nil, err } return &hc, nil @@ -538,14 +538,14 @@ func (r *ClusterDeploymentReconciler) Delete(ctx context.Context, clusterDeploym hr := &hcv2.HelmRelease{} - if err := r.Get(ctx, client.ObjectKeyFromObject(clusterDeployment), hr); err != nil { + if err := r.client.Get(ctx, client.ObjectKeyFromObject(clusterDeployment), hr); err != nil { if !apierrors.IsNotFound(err) { return ctrl.Result{}, err } l.Info("Removing Finalizer", "finalizer", kcm.ClusterDeploymentFinalizer) if controllerutil.RemoveFinalizer(clusterDeployment, kcm.ClusterDeploymentFinalizer) { - if err := r.Client.Update(ctx, clusterDeployment); err != nil { + if err := r.client.Update(ctx, clusterDeployment); err != nil { return ctrl.Result{}, fmt.Errorf("failed to update clusterDeployment %s/%s: %w", clusterDeployment.Namespace, clusterDeployment.Name, err) } } @@ -553,7 +553,7 @@ func (r *ClusterDeploymentReconciler) Delete(ctx context.Context, clusterDeploym return ctrl.Result{}, nil } - if err := helm.DeleteHelmRelease(ctx, r.Client, clusterDeployment.Name, clusterDeployment.Namespace); err != nil { + if err := helm.DeleteHelmRelease(ctx, r.client, clusterDeployment.Name, clusterDeployment.Namespace); err != nil { return ctrl.Result{}, err } @@ -562,7 +562,7 @@ func (r *ClusterDeploymentReconciler) Delete(ctx context.Context, clusterDeploym // It is detailed in https://github.com/projectsveltos/addon-controller/issues/732. // We may try to remove the explicit call to Delete once a fix for it has been merged. // TODO(https://github.com/K0rdent/kcm/issues/526). - if err := sveltos.DeleteProfile(ctx, r.Client, clusterDeployment.Namespace, clusterDeployment.Name); err != nil { + if err := sveltos.DeleteProfile(ctx, r.client, clusterDeployment.Namespace, clusterDeployment.Name); err != nil { return ctrl.Result{}, err } @@ -637,7 +637,7 @@ func (r *ClusterDeploymentReconciler) releaseCluster(ctx context.Context, namesp func (r *ClusterDeploymentReconciler) getInfraProvidersNames(ctx context.Context, templateNamespace, templateName string) ([]string, error) { template := &kcm.ClusterTemplate{} templateRef := client.ObjectKey{Name: templateName, Namespace: templateNamespace} - if err := r.Get(ctx, templateRef, template); err != nil { + if err := r.client.Get(ctx, templateRef, template); err != nil { ctrl.LoggerFrom(ctx).Error(err, "Failed to get ClusterTemplate", "template namespace", templateNamespace, "template name", templateName) return nil, err } @@ -663,7 +663,7 @@ func (r *ClusterDeploymentReconciler) getCluster(ctx context.Context, namespace, } itemsList := &metav1.PartialObjectMetadataList{} itemsList.SetGroupVersionKind(gvk) - if err := r.Client.List(ctx, itemsList, opts); err != nil { + if err := r.client.List(ctx, itemsList, opts); err != nil { return nil, err } if len(itemsList.Items) == 0 { @@ -677,7 +677,7 @@ func (r *ClusterDeploymentReconciler) removeClusterFinalizer(ctx context.Context originalCluster := *cluster if controllerutil.RemoveFinalizer(cluster, kcm.BlockingFinalizer) { ctrl.LoggerFrom(ctx).Info("Allow to stop cluster", "finalizer", kcm.BlockingFinalizer) - if err := r.Client.Patch(ctx, cluster, client.MergeFrom(&originalCluster)); err != nil { + if err := r.client.Patch(ctx, cluster, client.MergeFrom(&originalCluster)); err != nil { return fmt.Errorf("failed to patch cluster %s/%s: %w", cluster.Namespace, cluster.Name, err) } } @@ -693,7 +693,7 @@ func (r *ClusterDeploymentReconciler) objectsAvailable(ctx context.Context, name } itemsList := &metav1.PartialObjectMetadataList{} itemsList.SetGroupVersionKind(gvk) - if err := r.Client.List(ctx, itemsList, opts); err != nil { + if err := r.client.List(ctx, itemsList, opts); err != nil { return false, err } return len(itemsList.Items) != 0, nil @@ -709,7 +709,7 @@ func (r *ClusterDeploymentReconciler) reconcileCredentialPropagation(ctx context } kubeconfSecret := &corev1.Secret{} - if err := r.Client.Get(ctx, client.ObjectKey{ + if err := r.client.Get(ctx, client.ObjectKey{ Name: clusterDeployment.Name + "-kubeconfig", Namespace: clusterDeployment.Namespace, }, kubeconfSecret); err != nil { @@ -717,7 +717,7 @@ func (r *ClusterDeploymentReconciler) reconcileCredentialPropagation(ctx context } propnCfg := &credspropagation.PropagationCfg{ - Client: r.Client, + Client: r.client, IdentityRef: credential.Spec.IdentityRef, KubeconfSecret: kubeconfSecret, ClusterDeployment: clusterDeployment, @@ -806,7 +806,7 @@ func (r *ClusterDeploymentReconciler) setAvailableUpgrades(ctx context.Context, return nil } chains := &kcm.ClusterTemplateChainList{} - err := r.List(ctx, chains, + err := r.client.List(ctx, chains, client.InNamespace(template.Namespace), client.MatchingFields{kcm.TemplateChainSupportedTemplatesIndexKey: template.GetName()}, ) @@ -835,14 +835,17 @@ func (r *ClusterDeploymentReconciler) setAvailableUpgrades(ctx context.Context, // SetupWithManager sets up the controller with the Manager. func (r *ClusterDeploymentReconciler) SetupWithManager(mgr ctrl.Manager) error { - r.helmActor = helm.NewActor(r.Config, r.RESTMapper()) + r.client = mgr.GetClient() + r.config = mgr.GetConfig() + + r.helmActor = helm.NewActor(r.config, r.client.RESTMapper()) return ctrl.NewControllerManagedBy(mgr). For(&kcm.ClusterDeployment{}). Watches(&hcv2.HelmRelease{}, handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, o client.Object) []ctrl.Request { clusterDeploymentRef := client.ObjectKeyFromObject(o) - if err := r.Client.Get(ctx, clusterDeploymentRef, &kcm.ClusterDeployment{}); err != nil { + if err := r.client.Get(ctx, clusterDeploymentRef, &kcm.ClusterDeployment{}); err != nil { return []ctrl.Request{} } @@ -859,7 +862,7 @@ func (r *ClusterDeploymentReconciler) SetupWithManager(mgr ctrl.Manager) error { var req []ctrl.Request for _, template := range getTemplateNamesManagedByChain(chain) { clusterDeployments := &kcm.ClusterDeploymentList{} - err := r.Client.List(ctx, clusterDeployments, + err := r.client.List(ctx, clusterDeployments, client.InNamespace(chain.Namespace), client.MatchingFields{kcm.ClusterDeploymentTemplateIndexKey: template}) if err != nil { @@ -891,7 +894,7 @@ func (r *ClusterDeploymentReconciler) SetupWithManager(mgr ctrl.Manager) error { Watches(&kcm.Credential{}, handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, o client.Object) []ctrl.Request { clusterDeployments := &kcm.ClusterDeploymentList{} - err := r.Client.List(ctx, clusterDeployments, + err := r.client.List(ctx, clusterDeployments, client.InNamespace(o.GetNamespace()), client.MatchingFields{kcm.ClusterDeploymentCredentialIndexKey: o.GetName()}) if err != nil { diff --git a/internal/controller/clusterdeployment_controller_test.go b/internal/controller/clusterdeployment_controller_test.go index 5dddf7b5..910bdbfc 100644 --- a/internal/controller/clusterdeployment_controller_test.go +++ b/internal/controller/clusterdeployment_controller_test.go @@ -255,9 +255,9 @@ var _ = Describe("ClusterDeployment Controller", func() { It("should reconcile ClusterDeployment in dry-run mode", func() { controllerReconciler := &ClusterDeploymentReconciler{ - Client: mgrClient, + client: mgrClient, helmActor: &fakeHelmActor{}, - Config: &rest.Config{}, + config: &rest.Config{}, } By("creating ClusterDeployment resource", func() { @@ -358,9 +358,9 @@ var _ = Describe("ClusterDeployment Controller", func() { It("should reconcile ClusterDeployment with AWS credentials", func() { controllerReconciler := &ClusterDeploymentReconciler{ - Client: mgrClient, + client: mgrClient, helmActor: &fakeHelmActor{}, - Config: &rest.Config{}, + config: &rest.Config{}, DynamicClient: dynamicClient, } diff --git a/internal/controller/management_controller.go b/internal/controller/management_controller.go index e4b041f9..cac68c0a 100644 --- a/internal/controller/management_controller.go +++ b/internal/controller/management_controller.go @@ -39,6 +39,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/manager" kcm "github.com/K0rdent/kcm/api/v1alpha1" "github.com/K0rdent/kcm/internal/certmanager" @@ -49,12 +50,14 @@ import ( // ManagementReconciler reconciles a Management object type ManagementReconciler struct { - client.Client - Scheme *runtime.Scheme - Config *rest.Config - DynamicClient *dynamic.DynamicClient - SystemNamespace string - CreateAccessManagement bool + client client.Client + manager manager.Manager + scheme *runtime.Scheme + config *rest.Config + DynamicClient *dynamic.DynamicClient + SystemNamespace string + CreateAccessManagement bool + sveltosDependentControllersStarted bool } func (r *ManagementReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { @@ -62,7 +65,7 @@ func (r *ManagementReconciler) Reconcile(ctx context.Context, req ctrl.Request) l.Info("Reconciling Management") management := &kcm.Management{} - if err := r.Get(ctx, req.NamespacedName, management); err != nil { + if err := r.client.Get(ctx, req.NamespacedName, management); err != nil { if apierrors.IsNotFound(err) { l.Info("Management not found, ignoring since object must be deleted") return ctrl.Result{}, nil @@ -84,14 +87,14 @@ func (r *ManagementReconciler) Update(ctx context.Context, management *kcm.Manag l := ctrl.LoggerFrom(ctx) if controllerutil.AddFinalizer(management, kcm.ManagementFinalizer) { - if err := r.Client.Update(ctx, management); err != nil { + if err := r.client.Update(ctx, management); err != nil { l.Error(err, "failed to update Management finalizers") return ctrl.Result{}, err } return ctrl.Result{}, nil } - if err := utils.AddKCMComponentLabel(ctx, r.Client, management); err != nil { + if err := utils.AddKCMComponentLabel(ctx, r.client, management); err != nil { l.Error(err, "adding component label") return ctrl.Result{}, err } @@ -111,7 +114,7 @@ func (r *ManagementReconciler) Update(ctx context.Context, management *kcm.Manag return ctrl.Result{}, err } - components, err := getWrappedComponents(ctx, r.Client, management) + components, err := getWrappedComponents(ctx, r.client, management) if err != nil { l.Error(err, "failed to wrap KCM components") return ctrl.Result{}, err @@ -145,7 +148,7 @@ func (r *ManagementReconciler) Update(ctx context.Context, management *kcm.Manag continue } template := new(kcm.ProviderTemplate) - if err := r.Get(ctx, client.ObjectKey{Name: component.Template}, template); err != nil { + if err := r.client.Get(ctx, client.ObjectKey{Name: component.Template}, template); err != nil { errMsg := fmt.Sprintf("Failed to get ProviderTemplate %s: %s", component.Template, err) updateComponentsStatus(statusAccumulator, component, nil, errMsg) errs = errors.Join(errs, errors.New(errMsg)) @@ -172,7 +175,7 @@ func (r *ManagementReconciler) Update(ctx context.Context, management *kcm.Manag hrReconcileOpts.ReconcileInterval = &template.Spec.Helm.ChartSpec.Interval.Duration } - if _, _, err := helm.ReconcileHelmRelease(ctx, r.Client, component.helmReleaseName, r.SystemNamespace, hrReconcileOpts); err != nil { + if _, _, err := helm.ReconcileHelmRelease(ctx, r.client, component.helmReleaseName, r.SystemNamespace, hrReconcileOpts); err != nil { errMsg := fmt.Sprintf("Failed to reconcile HelmRelease %s/%s: %s", r.SystemNamespace, component.helmReleaseName, err) updateComponentsStatus(statusAccumulator, component, nil, errMsg) errs = errors.Join(errs, errors.New(errMsg)) @@ -196,7 +199,15 @@ func (r *ManagementReconciler) Update(ctx context.Context, management *kcm.Manag management.Status.ObservedGeneration = management.Generation management.Status.Release = management.Spec.Release - if err := r.Status().Update(ctx, management); err != nil { + shouldRequeue, err := r.startDependentControllers(ctx, management) + if err != nil { + return ctrl.Result{}, err + } + if shouldRequeue { + requeue = true + } + + if err := r.client.Status().Update(ctx, management); err != nil { errs = errors.Join(errs, fmt.Errorf("failed to update status for Management %s: %w", management.Name, err)) } @@ -211,6 +222,45 @@ func (r *ManagementReconciler) Update(ctx context.Context, management *kcm.Manag return ctrl.Result{}, nil } +// startDependentControllers starts controllers that cannot be started +// at process startup because of some dependency like CRDs being present. +func (r *ManagementReconciler) startDependentControllers(ctx context.Context, management *kcm.Management) (requue bool, err error) { + l := ctrl.LoggerFrom(ctx) + + if r.sveltosDependentControllersStarted { + // Only need to start controllers once. + return false, nil + } + + if !management.Status.Components[kcm.ProviderSveltosName].Success { + l.Info(fmt.Sprintf("Waiting for %s provider to be ready to setup contollers dependent on it", kcm.ProviderSveltosName)) + return true, nil + } + + currentNamespace := utils.CurrentNamespace() + + l.Info(fmt.Sprintf("Provider %s has been successfully installed, so setting up controller for ClusterDeployment", kcm.ProviderSveltosName)) + if err = (&ClusterDeploymentReconciler{ + DynamicClient: r.DynamicClient, + SystemNamespace: currentNamespace, + }).SetupWithManager(r.manager); err != nil { + return false, fmt.Errorf("failed to setup controller for ClusterDeployment: %w", err) + } + l.Info("Setup for ClusterDeployment controller successful") + + l.Info(fmt.Sprintf("Provider %s has been successfully installed, so setting up controller for MultiClusterService", kcm.ProviderSveltosName)) + if err = (&MultiClusterServiceReconciler{ + SystemNamespace: currentNamespace, + }).SetupWithManager(r.manager); err != nil { + return false, fmt.Errorf("failed to setup controller for MultiClusterService: %w", err) + } + l.Info("Setup for MultiClusterService controller successful") + + r.sveltosDependentControllersStarted = true + + return false, nil +} + func (r *ManagementReconciler) cleanupRemovedComponents(ctx context.Context, management *kcm.Management) error { var ( errs error @@ -218,7 +268,7 @@ func (r *ManagementReconciler) cleanupRemovedComponents(ctx context.Context, man ) managedHelmReleases := new(fluxv2.HelmReleaseList) - if err := r.Client.List(ctx, managedHelmReleases, + if err := r.client.List(ctx, managedHelmReleases, client.MatchingLabels{kcm.KCMManagedLabelKey: kcm.KCMManagedLabelValue}, client.InNamespace(r.SystemNamespace), // all helmreleases are being installed only in the system namespace ); err != nil { @@ -241,7 +291,7 @@ func (r *ManagementReconciler) cleanupRemovedComponents(ctx context.Context, man l.Info("Found component to remove", "component_name", componentName) - if err := r.Client.Delete(ctx, &hr); client.IgnoreNotFound(err) != nil { + if err := r.client.Delete(ctx, &hr); client.IgnoreNotFound(err) != nil { errs = errors.Join(errs, fmt.Errorf("failed to delete %s: %w", client.ObjectKeyFromObject(&hr), err)) continue } @@ -270,7 +320,7 @@ func (r *ManagementReconciler) ensureAccessManagement(ctx context.Context, mgmt }, }, } - err := r.Get(ctx, client.ObjectKey{ + err := r.client.Get(ctx, client.ObjectKey{ Name: kcm.AccessManagementName, }, amObj) if err == nil { @@ -279,7 +329,7 @@ func (r *ManagementReconciler) ensureAccessManagement(ctx context.Context, mgmt if !apierrors.IsNotFound(err) { return fmt.Errorf("failed to get %s AccessManagement object: %w", kcm.AccessManagementName, err) } - err = r.Create(ctx, amObj) + err = r.client.Create(ctx, amObj) if err != nil { return fmt.Errorf("failed to create %s AccessManagement object: %w", kcm.AccessManagementName, err) } @@ -294,7 +344,7 @@ func (r *ManagementReconciler) ensureAccessManagement(ctx context.Context, mgmt func (r *ManagementReconciler) checkProviderStatus(ctx context.Context, component component) error { helmReleaseName := component.helmReleaseName hr := &fluxv2.HelmRelease{} - err := r.Get(ctx, types.NamespacedName{Namespace: r.SystemNamespace, Name: helmReleaseName}, hr) + err := r.client.Get(ctx, types.NamespacedName{Namespace: r.SystemNamespace, Name: helmReleaseName}, hr) if err != nil { return fmt.Errorf("failed to check provider status: %w", err) } @@ -378,7 +428,7 @@ func (r *ManagementReconciler) Delete(ctx context.Context, management *kcm.Manag // Removing finalizer in the end of cleanup l.Info("Removing Management finalizer") if controllerutil.RemoveFinalizer(management, kcm.ManagementFinalizer) { - return ctrl.Result{}, r.Client.Update(ctx, management) + return ctrl.Result{}, r.client.Update(ctx, management) } return ctrl.Result{}, nil } @@ -387,19 +437,19 @@ func (r *ManagementReconciler) removeHelmReleases(ctx context.Context, kcmReleas l := ctrl.LoggerFrom(ctx) l.Info("Suspending KCM Helm Release reconciles") kcmRelease := &fluxv2.HelmRelease{} - err := r.Client.Get(ctx, client.ObjectKey{Namespace: r.SystemNamespace, Name: kcmReleaseName}, kcmRelease) + err := r.client.Get(ctx, client.ObjectKey{Namespace: r.SystemNamespace, Name: kcmReleaseName}, kcmRelease) if err != nil && !apierrors.IsNotFound(err) { return err } if err == nil && !kcmRelease.Spec.Suspend { kcmRelease.Spec.Suspend = true - if err := r.Client.Update(ctx, kcmRelease); err != nil { + if err := r.client.Update(ctx, kcmRelease); err != nil { return err } } l.Info("Ensuring all HelmReleases owned by KCM are removed") gvk := fluxv2.GroupVersion.WithKind(fluxv2.HelmReleaseKind) - if err := utils.EnsureDeleteAllOf(ctx, r.Client, gvk, opts); err != nil { + if err := utils.EnsureDeleteAllOf(ctx, r.client, gvk, opts); err != nil { l.Error(err, "Not all HelmReleases owned by KCM are removed") return err } @@ -410,7 +460,7 @@ func (r *ManagementReconciler) removeHelmCharts(ctx context.Context, opts *clien l := ctrl.LoggerFrom(ctx) l.Info("Ensuring all HelmCharts owned by KCM are removed") gvk := sourcev1.GroupVersion.WithKind(sourcev1.HelmChartKind) - if err := utils.EnsureDeleteAllOf(ctx, r.Client, gvk, opts); err != nil { + if err := utils.EnsureDeleteAllOf(ctx, r.client, gvk, opts); err != nil { l.Error(err, "Not all HelmCharts owned by KCM are removed") return err } @@ -421,7 +471,7 @@ func (r *ManagementReconciler) removeHelmRepositories(ctx context.Context, opts l := ctrl.LoggerFrom(ctx) l.Info("Ensuring all HelmRepositories owned by KCM are removed") gvk := sourcev1.GroupVersion.WithKind(sourcev1.HelmRepositoryKind) - if err := utils.EnsureDeleteAllOf(ctx, r.Client, gvk, opts); err != nil { + if err := utils.EnsureDeleteAllOf(ctx, r.client, gvk, opts); err != nil { l.Error(err, "Not all HelmRepositories owned by KCM are removed") return err } @@ -554,8 +604,8 @@ func (r *ManagementReconciler) enableAdditionalComponents(ctx context.Context, m capiOperatorValues = v } - if r.Config != nil { - if err := certmanager.VerifyAPI(ctx, r.Config, r.SystemNamespace); err != nil { + if r.config != nil { + if err := certmanager.VerifyAPI(ctx, r.config, r.SystemNamespace); err != nil { return fmt.Errorf("failed to check in the cert-manager API is installed: %w", err) } @@ -622,6 +672,11 @@ func updateComponentsStatus( // SetupWithManager sets up the controller with the Manager. func (r *ManagementReconciler) SetupWithManager(mgr ctrl.Manager) error { + r.manager = mgr + r.client = mgr.GetClient() + r.scheme = mgr.GetScheme() + r.config = mgr.GetConfig() + return ctrl.NewControllerManagedBy(mgr). For(&kcm.Management{}). Complete(r) diff --git a/internal/controller/management_controller_test.go b/internal/controller/management_controller_test.go index 2c455014..f06f77da 100644 --- a/internal/controller/management_controller_test.go +++ b/internal/controller/management_controller_test.go @@ -77,8 +77,8 @@ var _ = Describe("Management Controller", func() { // NOTE: this node just checks that the finalizer has been set By("Reconciling the created resource") controllerReconciler := &ManagementReconciler{ - Client: k8sClient, - Scheme: k8sClient.Scheme(), + client: k8sClient, + scheme: k8sClient.Scheme(), } _, err := controllerReconciler.Reconcile(ctx, reconcile.Request{ @@ -275,10 +275,10 @@ var _ = Describe("Management Controller", func() { By("Reconciling the Management object") controllerReconciler := &ManagementReconciler{ - Client: k8sClient, - Scheme: k8sClient.Scheme(), - SystemNamespace: utils.DefaultSystemNamespace, + client: k8sClient, + scheme: k8sClient.Scheme(), DynamicClient: dynamicClient, + SystemNamespace: utils.DefaultSystemNamespace, } _, err := controllerReconciler.Reconcile(ctx, reconcile.Request{ diff --git a/internal/controller/multiclusterservice_controller.go b/internal/controller/multiclusterservice_controller.go index b17d53ed..c9795ee3 100644 --- a/internal/controller/multiclusterservice_controller.go +++ b/internal/controller/multiclusterservice_controller.go @@ -42,7 +42,7 @@ import ( // MultiClusterServiceReconciler reconciles a MultiClusterService object type MultiClusterServiceReconciler struct { - client.Client + client client.Client SystemNamespace string } @@ -52,7 +52,7 @@ func (r *MultiClusterServiceReconciler) Reconcile(ctx context.Context, req ctrl. l.Info("Reconciling MultiClusterService") mcs := &kcm.MultiClusterService{} - err := r.Get(ctx, req.NamespacedName, mcs) + err := r.client.Get(ctx, req.NamespacedName, mcs) if apierrors.IsNotFound(err) { l.Info("MultiClusterService not found, ignoring since object must be deleted") return ctrl.Result{}, nil @@ -72,7 +72,7 @@ func (r *MultiClusterServiceReconciler) Reconcile(ctx context.Context, req ctrl. func (r *MultiClusterServiceReconciler) reconcileUpdate(ctx context.Context, mcs *kcm.MultiClusterService) (_ ctrl.Result, err error) { if utils.AddLabel(mcs, kcm.GenericComponentLabelName, kcm.GenericComponentLabelValueKCM) { - if err := r.Update(ctx, mcs); err != nil { + if err := r.client.Update(ctx, mcs); err != nil { return ctrl.Result{}, fmt.Errorf("failed to update labels: %w", err) } return ctrl.Result{Requeue: true}, nil // generation has not changed, need explicit requeue @@ -112,7 +112,7 @@ func (r *MultiClusterServiceReconciler) reconcileUpdate(ctx context.Context, mcs }() if controllerutil.AddFinalizer(mcs, kcm.MultiClusterServiceFinalizer) { - if err = r.Client.Update(ctx, mcs); err != nil { + if err = r.client.Update(ctx, mcs); err != nil { return ctrl.Result{}, fmt.Errorf("failed to update MultiClusterService %s with finalizer %s: %w", mcs.Name, kcm.MultiClusterServiceFinalizer, err) } // Requeuing to make sure that ClusterProfile is reconciled in subsequent runs. @@ -123,12 +123,12 @@ func (r *MultiClusterServiceReconciler) reconcileUpdate(ctx context.Context, mcs // We are enforcing that MultiClusterService may only use // ServiceTemplates that are present in the system namespace. - opts, err := sveltos.GetHelmChartOpts(ctx, r.Client, r.SystemNamespace, mcs.Spec.ServiceSpec.Services) + opts, err := sveltos.GetHelmChartOpts(ctx, r.client, r.SystemNamespace, mcs.Spec.ServiceSpec.Services) if err != nil { return ctrl.Result{}, err } - if _, err = sveltos.ReconcileClusterProfile(ctx, r.Client, mcs.Name, + if _, err = sveltos.ReconcileClusterProfile(ctx, r.client, mcs.Name, sveltos.ReconcileProfileOpts{ OwnerReference: &metav1.OwnerReference{ APIVersion: kcm.GroupVersion.String(), @@ -153,13 +153,13 @@ func (r *MultiClusterServiceReconciler) reconcileUpdate(ctx context.Context, mcs // will ultimately return the error in servicesErr instead of nil. profile := sveltosv1beta1.ClusterProfile{} profileRef := client.ObjectKey{Name: mcs.Name} - if servicesErr = r.Get(ctx, profileRef, &profile); servicesErr != nil { + if servicesErr = r.client.Get(ctx, profileRef, &profile); servicesErr != nil { servicesErr = fmt.Errorf("failed to get ClusterProfile %s to fetch status from its associated ClusterSummary: %w", profileRef.String(), servicesErr) return ctrl.Result{}, nil } var servicesStatus []kcm.ServiceStatus - servicesStatus, servicesErr = updateServicesStatus(ctx, r.Client, profileRef, profile.Status.MatchingClusterRefs, mcs.Status.Services) + servicesStatus, servicesErr = updateServicesStatus(ctx, r.client, profileRef, profile.Status.MatchingClusterRefs, mcs.Status.Services) if servicesErr != nil { return ctrl.Result{}, nil } @@ -173,7 +173,7 @@ func (r *MultiClusterServiceReconciler) updateStatus(ctx context.Context, mcs *k mcs.Status.ObservedGeneration = mcs.Generation mcs.Status.Conditions = updateStatusConditions(mcs.Status.Conditions, "MultiClusterService is ready") - if err := r.Status().Update(ctx, mcs); err != nil { + if err := r.client.Status().Update(ctx, mcs); err != nil { return fmt.Errorf("failed to update status for MultiClusterService %s/%s: %w", mcs.Namespace, mcs.Name, err) } @@ -265,12 +265,12 @@ func updateServicesStatus(ctx context.Context, c client.Client, profileRef clien } func (r *MultiClusterServiceReconciler) reconcileDelete(ctx context.Context, mcsvc *kcm.MultiClusterService) (ctrl.Result, error) { - if err := sveltos.DeleteClusterProfile(ctx, r.Client, mcsvc.Name); err != nil { + if err := sveltos.DeleteClusterProfile(ctx, r.client, mcsvc.Name); err != nil { return ctrl.Result{}, err } if controllerutil.RemoveFinalizer(mcsvc, kcm.MultiClusterServiceFinalizer) { - if err := r.Client.Update(ctx, mcsvc); err != nil { + if err := r.client.Update(ctx, mcsvc); err != nil { return ctrl.Result{}, fmt.Errorf("failed to remove finalizer %s from MultiClusterService %s: %w", kcm.MultiClusterServiceFinalizer, mcsvc.Name, err) } } @@ -311,6 +311,8 @@ func requeueSveltosProfileForClusterSummary(ctx context.Context, obj client.Obje // SetupWithManager sets up the controller with the Manager. func (r *MultiClusterServiceReconciler) SetupWithManager(mgr ctrl.Manager) error { + r.client = mgr.GetClient() + return ctrl.NewControllerManagedBy(mgr). For(&kcm.MultiClusterService{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})). Watches(&sveltosv1beta1.ClusterSummary{}, diff --git a/internal/controller/multiclusterservice_controller_test.go b/internal/controller/multiclusterservice_controller_test.go index 84120a6d..7cf6a016 100644 --- a/internal/controller/multiclusterservice_controller_test.go +++ b/internal/controller/multiclusterservice_controller_test.go @@ -239,7 +239,7 @@ var _ = Describe("MultiClusterService Controller", func() { multiClusterServiceResource := &kcm.MultiClusterService{} Expect(k8sClient.Get(ctx, multiClusterServiceRef, multiClusterServiceResource)).NotTo(HaveOccurred()) - reconciler := &MultiClusterServiceReconciler{Client: k8sClient, SystemNamespace: testSystemNamespace} + reconciler := &MultiClusterServiceReconciler{client: k8sClient, SystemNamespace: testSystemNamespace} Expect(k8sClient.Delete(ctx, multiClusterService)).To(Succeed()) // Running reconcile to remove the finalizer and delete the MultiClusterService _, err := reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: multiClusterServiceRef}) @@ -266,7 +266,7 @@ var _ = Describe("MultiClusterService Controller", func() { It("should successfully reconcile the resource", func() { By("reconciling MultiClusterService") - multiClusterServiceReconciler := &MultiClusterServiceReconciler{Client: k8sClient, SystemNamespace: testSystemNamespace} + multiClusterServiceReconciler := &MultiClusterServiceReconciler{client: k8sClient, SystemNamespace: testSystemNamespace} _, err := multiClusterServiceReconciler.Reconcile(ctx, reconcile.Request{NamespacedName: multiClusterServiceRef}) Expect(err).NotTo(HaveOccurred())