From 12cfd57af9f59ca399dbb510823e716d6577a166 Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Tue, 18 Jun 2024 09:39:15 -0700 Subject: [PATCH 1/5] feat: Use flag to configure namespacesync target namespace label key Sets the default label key as an empty string. Labels cannot have an empty key, which means that, by default, no namespaces are target namespaces. --- api/v1alpha1/constants.go | 6 ------ cmd/main.go | 3 +-- pkg/controllers/namespacesync/flags.go | 15 ++++++++++++--- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/api/v1alpha1/constants.go b/api/v1alpha1/constants.go index 1efbcecd9..2a37e2f68 100644 --- a/api/v1alpha1/constants.go +++ b/api/v1alpha1/constants.go @@ -32,10 +32,4 @@ const ( GlobalMirrorVariableName = "globalImageRegistryMirror" // ImageRegistriesVariableName is the image registries patch variable name. ImageRegistriesVariableName = "imageRegistries" - - // NamespaceSyncLabelKey is a label that can be applied to a namespace. - // - // When a namespace has a label with this key, ClusterClasses and their Templates are - // copied to the namespace from a source namespace. The copies are not updated or deleted. - NamespaceSyncLabelKey = "caren.nutanix.com/namespace-sync" ) diff --git a/cmd/main.go b/cmd/main.go index 8e4c2f6d0..451418c43 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -27,7 +27,6 @@ import ( metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" caaphv1 "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/external/sigs.k8s.io/cluster-api-addon-provider-helm/api/v1alpha1" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/v1alpha1" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/server" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/controllers/namespacesync" @@ -164,7 +163,7 @@ func main() { Client: mgr.GetClient(), UnstructuredCachingClient: unstructuredCachingClient, SourceClusterClassNamespace: namespacesyncOptions.SourceNamespace, - TargetNamespaceFilter: namespacesync.NamespaceHasLabelKey(v1alpha1.NamespaceSyncLabelKey), + TargetNamespaceFilter: namespacesync.NamespaceHasLabelKey(namespacesyncOptions.TargetNamespaceLabelKey), }).SetupWithManager( signalCtx, mgr, diff --git a/pkg/controllers/namespacesync/flags.go b/pkg/controllers/namespacesync/flags.go index d560add2e..4177002e0 100644 --- a/pkg/controllers/namespacesync/flags.go +++ b/pkg/controllers/namespacesync/flags.go @@ -9,8 +9,9 @@ import ( ) type Options struct { - Concurrency int - SourceNamespace string + Concurrency int + SourceNamespace string + TargetNamespaceLabelKey string } func (o *Options) AddFlags(flags *pflag.FlagSet) { @@ -24,6 +25,14 @@ func (o *Options) AddFlags(flags *pflag.FlagSet) { pflag.CommandLine.StringVar( &o.SourceNamespace, "namespacesync-source-namespace", - corev1.NamespaceDefault, "Namespace from which ClusterClasses and Templates are copied.", + corev1.NamespaceDefault, + "Namespace from which ClusterClasses and Templates are copied.", + ) + + pflag.CommandLine.StringVar( + &o.TargetNamespaceLabelKey, + "namespacesync-target-namespace-label-key", + "", + "Label key to determine if a namespace is a target. If a namespace has a label with this key, copy ClusterClasses and Templates to it from the source namespace.", //nolint:lll // Output will be wrapped. ) } From 3aceabef5f8dca08c141a8980d3dc9f9d4637016 Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Thu, 20 Jun 2024 09:55:22 -0700 Subject: [PATCH 2/5] feat: Enable namespacesync using a flag --- cmd/main.go | 59 +++++++++++++++----------- pkg/controllers/namespacesync/flags.go | 9 +++- 2 files changed, 43 insertions(+), 25 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 451418c43..d55c6d077 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -147,30 +147,41 @@ func main() { os.Exit(1) } - unstructuredCachingClient, err := client.New(mgr.GetConfig(), client.Options{ - HTTPClient: mgr.GetHTTPClient(), - Cache: &client.CacheOptions{ - Reader: mgr.GetCache(), - Unstructured: true, - }, - }) - if err != nil { - setupLog.Error(err, "unable to create unstructured caching client") - os.Exit(1) - } - - if err := (&namespacesync.Reconciler{ - Client: mgr.GetClient(), - UnstructuredCachingClient: unstructuredCachingClient, - SourceClusterClassNamespace: namespacesyncOptions.SourceNamespace, - TargetNamespaceFilter: namespacesync.NamespaceHasLabelKey(namespacesyncOptions.TargetNamespaceLabelKey), - }).SetupWithManager( - signalCtx, - mgr, - controller.Options{MaxConcurrentReconciles: namespacesyncOptions.Concurrency}, - ); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "namespacesync.Reconciler") - os.Exit(1) + if namespacesyncOptions.Enabled { + if namespacesyncOptions.SourceNamespace == "" || + namespacesyncOptions.TargetNamespaceLabelKey == "" { + setupLog.Error( + nil, + "Namespace Sync is enabled, but source namespace and/or target namespace label key are not configured.", + ) + os.Exit(1) + } + + unstructuredCachingClient, err := client.New(mgr.GetConfig(), client.Options{ + HTTPClient: mgr.GetHTTPClient(), + Cache: &client.CacheOptions{ + Reader: mgr.GetCache(), + Unstructured: true, + }, + }) + if err != nil { + setupLog.Error(err, "unable to create unstructured caching client") + os.Exit(1) + } + + if err := (&namespacesync.Reconciler{ + Client: mgr.GetClient(), + UnstructuredCachingClient: unstructuredCachingClient, + SourceClusterClassNamespace: namespacesyncOptions.SourceNamespace, + TargetNamespaceFilter: namespacesync.NamespaceHasLabelKey(namespacesyncOptions.TargetNamespaceLabelKey), + }).SetupWithManager( + signalCtx, + mgr, + controller.Options{MaxConcurrentReconciles: namespacesyncOptions.Concurrency}, + ); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "namespacesync.Reconciler") + os.Exit(1) + } } if err := mgr.Start(signalCtx); err != nil { diff --git a/pkg/controllers/namespacesync/flags.go b/pkg/controllers/namespacesync/flags.go index 4177002e0..2d2399177 100644 --- a/pkg/controllers/namespacesync/flags.go +++ b/pkg/controllers/namespacesync/flags.go @@ -5,16 +5,23 @@ package namespacesync import ( "github.com/spf13/pflag" - corev1 "k8s.io/api/core/v1" ) type Options struct { + Enabled bool Concurrency int SourceNamespace string TargetNamespaceLabelKey string } func (o *Options) AddFlags(flags *pflag.FlagSet) { + pflag.CommandLine.BoolVar( + &o.Enabled, + "namespacesync-enabled", + false, + "Enable copying of ClusterClasses and Templates from a source namespace to one or more target namespaces.", + ) + pflag.CommandLine.IntVar( &o.Concurrency, "namespacesync-concurrency", From 3f4f89ff09ca3d59fef6c640532477644153cbf6 Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Thu, 20 Jun 2024 09:56:09 -0700 Subject: [PATCH 3/5] refactor: Remove namespace sync default source namespace --- pkg/controllers/namespacesync/flags.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/controllers/namespacesync/flags.go b/pkg/controllers/namespacesync/flags.go index 2d2399177..1b2bd8e00 100644 --- a/pkg/controllers/namespacesync/flags.go +++ b/pkg/controllers/namespacesync/flags.go @@ -32,7 +32,7 @@ func (o *Options) AddFlags(flags *pflag.FlagSet) { pflag.CommandLine.StringVar( &o.SourceNamespace, "namespacesync-source-namespace", - corev1.NamespaceDefault, + "", "Namespace from which ClusterClasses and Templates are copied.", ) From 9616a90919ed404c03875f20c88ab6bb1a3a0e75 Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Thu, 20 Jun 2024 10:36:19 -0700 Subject: [PATCH 4/5] refactor: Formatting --- cmd/main.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cmd/main.go b/cmd/main.go index d55c6d077..331d0611a 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -179,7 +179,12 @@ func main() { mgr, controller.Options{MaxConcurrentReconciles: namespacesyncOptions.Concurrency}, ); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "namespacesync.Reconciler") + setupLog.Error( + err, + "unable to create controller", + "controller", + "namespacesync.Reconciler", + ) os.Exit(1) } } From 3c5abeb069f1f7170f82e8f61bc6fbac77877343 Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Tue, 18 Jun 2024 10:00:00 -0700 Subject: [PATCH 5/5] feat: Configure namespace sync in helm chart - Adds configuration fields and passes them to manager as flags. - Documents configuration fields and their default values. --- .../README.md | 3 +++ .../templates/deployment.yaml | 3 +++ .../values.schema.json | 14 ++++++++++++++ .../values.yaml | 10 ++++++++++ 4 files changed, 30 insertions(+) diff --git a/charts/cluster-api-runtime-extensions-nutanix/README.md b/charts/cluster-api-runtime-extensions-nutanix/README.md index 510f0e5e1..c70d691d8 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/README.md +++ b/charts/cluster-api-runtime-extensions-nutanix/README.md @@ -73,6 +73,9 @@ A Helm chart for cluster-api-runtime-extensions-nutanix | image.repository | string | `"ghcr.io/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix"` | | | image.tag | string | `""` | | | imagePullSecrets | list | `[]` | Optional secrets used for pulling the container image | +| namespaceSync.enabled | bool | `true` | | +| namespaceSync.sourceNamespace | string | `""` | | +| namespaceSync.targetNamespaceLabelKey | string | `"caren.nutanix.com/namespace-sync"` | | | nodeSelector | object | `{}` | | | priorityClassName | string | `"system-cluster-critical"` | Priority class to be used for the pod. | | resources.limits.cpu | string | `"100m"` | | diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/deployment.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/deployment.yaml index bee2322df..bbf6ba6e8 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/deployment.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/deployment.yaml @@ -30,6 +30,9 @@ spec: args: - --webhook-cert-dir=/runtimehooks-certs/ - --defaults-namespace=$(POD_NAMESPACE) + - --namespacesync-enabled={{ .Values.namespaceSync.enabled }} + - --namespacesync-source-namespace={{ .Values.namespaceSync.sourceNamespace | default .Release.Namespace }} + - --namespacesync-target-namespace-label-key={{ .Values.namespaceSync.targetNamespaceLabelKey }} - --helm-addons-configmap={{ .Values.helmAddonsConfigMap }} - --cni.cilium.helm-addon.default-values-template-configmap-name={{ .Values.hooks.cni.cilium.helmAddonStrategy.defaultValueTemplateConfigMap.name }} - --nfd.helm-addon.default-values-template-configmap-name={{ .Values.hooks.nfd.helmAddonStrategy.defaultValueTemplateConfigMap.name }} diff --git a/charts/cluster-api-runtime-extensions-nutanix/values.schema.json b/charts/cluster-api-runtime-extensions-nutanix/values.schema.json index 5cc9b2610..99b6ea8af 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/values.schema.json +++ b/charts/cluster-api-runtime-extensions-nutanix/values.schema.json @@ -401,6 +401,20 @@ "imagePullSecrets": { "type": "array" }, + "namespaceSync": { + "properties": { + "enabled": { + "type": "boolean" + }, + "sourceNamespace": { + "type": "string" + }, + "targetNamespaceLabelKey": { + "type": "string" + } + }, + "type": "object" + }, "nodeSelector": { "properties": {}, "type": "object" diff --git a/charts/cluster-api-runtime-extensions-nutanix/values.yaml b/charts/cluster-api-runtime-extensions-nutanix/values.yaml index 33062ba13..f79d0943e 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/values.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/values.yaml @@ -89,6 +89,16 @@ selfHostedRegistry: true deployDefaultClusterClasses: true +# The ClusterClass and the Templates it references must be in the same namespace +# as the Cluster. To enable cluster creation in user-defined namespaces, CAREN +# will copy all ClusterClasses and Templates from the source namespace to every +# target namespace, i.e., every namespace that has a label with a matching key. +namespaceSync: + enabled: true + targetNamespaceLabelKey: caren.nutanix.com/namespace-sync + # By default, sourceNamespace is the helm release namespace. + sourceNamespace: "" + deployment: replicas: 1