From 5299f451dd0c86b90b37ec77f9ec0956a9687de1 Mon Sep 17 00:00:00 2001 From: vimystic <122659254+vimystic@users.noreply.github.com> Date: Fri, 17 Jan 2025 08:00:54 -0700 Subject: [PATCH] Add namespace selector to api,crd and controller.go code --- api/v1/cosmosfullnode_types.go | 12 ++++ api/v1/zz_generated.deepcopy.go | 16 ++++++ .../cosmos.strange.love_cosmosfullnodes.yaml | 57 +++++++++++++++++++ controllers/cosmosfullnode_controller.go | 44 ++++++++++++++ 4 files changed, 129 insertions(+) diff --git a/api/v1/cosmosfullnode_types.go b/api/v1/cosmosfullnode_types.go index 0c7ecab0..acad4b72 100644 --- a/api/v1/cosmosfullnode_types.go +++ b/api/v1/cosmosfullnode_types.go @@ -107,6 +107,18 @@ type FullNodeSpec struct { // complexity of the CosmosFullNodeController. // +optional SelfHeal *SelfHealSpec `json:"selfHeal"` + + // NamespaceSelector allows filtering which namespaces the operator should watch + // +optional + NamespaceSelector *metav1.LabelSelector `json:"namespaceSelector,omitempty"` + + // AllowNamespaces is a list of namespaces to explicitly include for management + // +optional + AllowNamespaces []string `json:"allowNamespaces,omitempty"` + + // DenyNamespaces is a list of namespaces to explicitly exclude from management + // +optional + DenyNamespaces []string `json:"denyNamespaces,omitempty"` } type FullNodeType string diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 1b11a80f..dd7526ef 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -22,6 +22,7 @@ package v1 import ( corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/intstr" ) @@ -311,6 +312,21 @@ func (in *FullNodeSpec) DeepCopyInto(out *FullNodeSpec) { *out = new(SelfHealSpec) (*in).DeepCopyInto(*out) } + if in.NamespaceSelector != nil { + in, out := &in.NamespaceSelector, &out.NamespaceSelector + *out = new(metav1.LabelSelector) + (*in).DeepCopyInto(*out) + } + if in.AllowNamespaces != nil { + in, out := &in.AllowNamespaces, &out.AllowNamespaces + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.DenyNamespaces != nil { + in, out := &in.DenyNamespaces, &out.DenyNamespaces + *out = make([]string, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FullNodeSpec. diff --git a/config/crd/bases/cosmos.strange.love_cosmosfullnodes.yaml b/config/crd/bases/cosmos.strange.love_cosmosfullnodes.yaml index e7b449a6..e294265a 100644 --- a/config/crd/bases/cosmos.strange.love_cosmosfullnodes.yaml +++ b/config/crd/bases/cosmos.strange.love_cosmosfullnodes.yaml @@ -46,6 +46,12 @@ spec: spec: description: FullNodeSpec defines the desired state of CosmosFullNode properties: + allowNamespaces: + description: AllowNamespaces is a list of namespaces to explicitly + include for management + items: + type: string + type: array chain: description: Blockchain-specific configuration. properties: @@ -386,6 +392,12 @@ spec: - chainID - network type: object + denyNamespaces: + description: DenyNamespaces is a list of namespaces to explicitly + exclude from management + items: + type: string + type: array instanceOverrides: additionalProperties: description: InstanceOverridesSpec allows overriding an instance @@ -552,6 +564,51 @@ spec: Example: cosmos-1 Used for debugging. type: object + namespaceSelector: + description: NamespaceSelector allows filtering which namespaces the + operator should watch + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic ordinals: description: |- Ordinals controls the numbering of replica indices in a CosmosFullnode spec. diff --git a/controllers/cosmosfullnode_controller.go b/controllers/cosmosfullnode_controller.go index 005a955f..56e0964e 100644 --- a/controllers/cosmosfullnode_controller.go +++ b/controllers/cosmosfullnode_controller.go @@ -26,6 +26,9 @@ import ( "github.com/strangelove-ventures/cosmos-operator/internal/fullnode" "github.com/strangelove-ventures/cosmos-operator/internal/kube" corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/tools/record" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" @@ -55,6 +58,9 @@ type CosmosFullNodeReconciler struct { serviceAccountControl fullnode.ServiceAccountControl clusterRoleControl fullnode.RoleControl clusterRoleBindingControl fullnode.RoleBindingControl + NamespaceSelector *metav1.LabelSelector + AllowNamespaces []string + DenyNamespaces []string } // NewFullNode returns a valid CosmosFullNode controller. @@ -115,6 +121,12 @@ func (r *CosmosFullNodeReconciler) Reconcile(ctx context.Context, req ctrl.Reque return stopResult, client.IgnoreNotFound(err) } + //Namespace filtering logic + if !r.isNamespaceAllowed(crd.Spec, req.Namespace) { + logger.V(1).Info("Skipping reconciliation for namespace", "namespace", req.Namespace) + return ctrl.Result{}, nil + } + reporter := kube.NewEventReporter(logger, r.recorder, crd) fullnode.ResetStatus(crd) @@ -209,6 +221,38 @@ func (r *CosmosFullNodeReconciler) Reconcile(ctx context.Context, req ctrl.Reque return ctrl.Result{RequeueAfter: 60 * time.Second}, nil } +func (r *CosmosFullNodeReconciler) isNamespaceAllowed(spec cosmosv1.FullNodeSpec, namespace string) bool { + // Check DenyNamespaces + for _, ns := range spec.DenyNamespaces { + if ns == namespace { + return false + } + } + + // Check AllowNamespaces + if len(spec.AllowNamespaces) > 0 { + for _, ns := range spec.AllowNamespaces { + if ns == namespace { + return true + } + } + return false + } + + // Check NamespaceSelector + if spec.NamespaceSelector != nil { + // Implement label selector logic here + // This would require fetching the Namespace object and checking its labels + ns := &corev1.Namespace{} + if err := r.Get(context.TODO(), types.NamespacedName{Name: namespace}, ns); err != nil { + return false + } + return labels.SelectorFromSet(spec.NamespaceSelector.MatchLabels).Matches(labels.Set(ns.Labels)) + } + + return true +} + func (r *CosmosFullNodeReconciler) resultWithErr(crd *cosmosv1.CosmosFullNode, err kube.ReconcileError) (ctrl.Result, kube.ReconcileError) { if err.IsTransient() { r.recorder.Event(crd, kube.EventWarning, "ErrorTransient", fmt.Sprintf("%v; retrying.", err))