diff --git a/api/v1beta1/managementclusterclassifier_types.go b/api/v1beta1/managementclusterclassifier_types.go new file mode 100644 index 0000000..626bdcd --- /dev/null +++ b/api/v1beta1/managementclusterclassifier_types.go @@ -0,0 +1,97 @@ +/* +Copyright 2026. projectsveltos.io. All rights reserved. + +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 v1beta1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +const ( + // ManagementClusterClassifierFinalizer allows ManagementClusterClassifierReconciler + // to clean up resources before removing the CR from the apiserver. + ManagementClusterClassifierFinalizer = "managementclusterclassifierfinalizer.projectsveltos.io" + + ManagementClusterClassifierKind = "ManagementClusterClassifier" +) + +// ManagementClusterClassifierSpec defines the desired state of ManagementClusterClassifier. +type ManagementClusterClassifierSpec struct { + // MatchResources lists the management-cluster resource types to watch. + // Reuses the existing ResourceSelector type. Label/name/namespace filters + // and per-resource Lua (ResourceSelector.Evaluate) all apply: only objects + // where Evaluate returns {matching: true} are included in the resources array + // passed to ClassificationLua. Same behavior as the existing Classifier. + MatchResources []ResourceSelector `json:"matchResources"` + + // ClassificationLua is a Lua function called once per reconcile with the full + // set of resources matched by MatchResources. It receives the array as resources + // and must return an array of cluster references. + // Each entry must have fields: namespace (string), name (string), kind (string). + // kind must be "SveltosCluster" or "Cluster". Entries with a missing or unrecognized + // kind are skipped and recorded in status.failureMessage. + // Passing all resources at once allows the function to make decisions that + // depend on the relationship between multiple resources. + ClassificationLua string `json:"classificationLua"` + + // ClassifierLabels is the set of labels to add to every cluster returned by + // ClassificationLua. Same type as Classifier.spec.classifierLabels. + ClassifierLabels []ClassifierLabel `json:"classifierLabels"` +} + +// ManagementClusterClassifierStatus defines the observed state of ManagementClusterClassifier. +type ManagementClusterClassifierStatus struct { + // FailureMessage reports the error from the last reconcile, if any. + // Set when resource collection or Lua evaluation fails; cleared on success. + // +optional + FailureMessage *string `json:"failureMessage,omitempty"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:resource:path=managementclusterclassifiers,scope=Cluster +//+kubebuilder:subresource:status + +// ManagementClusterClassifier evaluates resources on the management cluster and +// labels managed clusters accordingly. Unlike Classifier, no deployment to managed +// clusters is required: the Lua function runs entirely on the management cluster and +// returns the list of clusters to label. +type ManagementClusterClassifier struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ManagementClusterClassifierSpec `json:"spec,omitempty"` + Status ManagementClusterClassifierStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// ManagementClusterClassifierList contains a list of ManagementClusterClassifier. +type ManagementClusterClassifierList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ManagementClusterClassifier `json:"items"` +} + +func init() { + SchemeBuilder.Register(func(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(GroupVersion, + &ManagementClusterClassifier{}, + &ManagementClusterClassifierList{}, + ) + return nil + }) +} diff --git a/api/v1beta1/managementclusterclassifierreport_types.go b/api/v1beta1/managementclusterclassifierreport_types.go new file mode 100644 index 0000000..c012ad4 --- /dev/null +++ b/api/v1beta1/managementclusterclassifierreport_types.go @@ -0,0 +1,121 @@ +/* +Copyright 2026. projectsveltos.io. All rights reserved. + +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 v1beta1 + +import ( + "crypto/sha256" + "fmt" + "strings" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +const ( + // ManagementClusterClassifierNameLabel is added to each ManagementClusterClassifierReport + // to identify the ManagementClusterClassifier that created it. + // `:` is not a valid character in Kubernetes resource names, so this prefix cannot + // collide with any Classifier name when both are registered in the keymanager. + ManagementClusterClassifierNameLabel = "projectsveltos.io/managementclusterclassifier-name" + + ManagementClusterClassifierReportKind = "ManagementClusterClassifierReport" +) + +// GetManagementClusterClassifierReportName returns a deterministic, fixed-length name +// for a ManagementClusterClassifierReport derived from a SHA-256 hash of the three +// identifying components. The name is opaque; labels carry the human-readable context. +func GetManagementClusterClassifierReportName(classifierName, clusterName string, clusterType *ClusterType) string { + h := sha256.New() + fmt.Fprintf(h, "%s:%s:%s", strings.ToLower(string(*clusterType)), classifierName, clusterName) + return fmt.Sprintf("%x", h.Sum(nil))[:32] +} + +// GetManagementClusterClassifierReportLabels returns the labels applied to a +// ManagementClusterClassifierReport. The three labels together allow efficient +// queries in both directions: all reports for a given classifier, and all reports +// targeting a given cluster. +func GetManagementClusterClassifierReportLabels(classifierName, clusterName string, clusterType *ClusterType) map[string]string { + return map[string]string{ + ManagementClusterClassifierNameLabel: classifierName, + ClassifierReportClusterNameLabel: clusterName, + ClassifierReportClusterTypeLabel: strings.ToLower(string(*clusterType)), + } +} + +// ManagementClusterClassifierReportSpec identifies the classifier and cluster this +// report belongs to. +type ManagementClusterClassifierReportSpec struct { + // ClassifierName is the name of the ManagementClusterClassifier this report is for. + ClassifierName string `json:"classifierName"` + + // ClusterNamespace is the namespace of the cluster this report is for. + ClusterNamespace string `json:"clusterNamespace"` + + // ClusterName is the name of the cluster this report is for. + ClusterName string `json:"clusterName"` + + // ClusterType is the type of the cluster this report is for. + ClusterType ClusterType `json:"clusterType"` +} + +// ManagementClusterClassifierReportStatus is written by the controller after processing. +type ManagementClusterClassifierReportStatus struct { + // ManagedLabels lists the label keys this ManagementClusterClassifier is + // actively managing on the cluster. + // +optional + ManagedLabels []string `json:"managedLabels,omitempty"` + + // UnManagedLabels lists label keys this ManagementClusterClassifier would like + // to manage but cannot because another Classifier or ManagementClusterClassifier + // already owns them. + // +optional + UnManagedLabels []UnManagedLabel `json:"unmanagedLabels,omitempty"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:resource:path=managementclusterclassifierreports,scope=Namespaced +//+kubebuilder:subresource:status + +// ManagementClusterClassifierReport is created by the ManagementClusterClassifier +// controller — one per (ManagementClusterClassifier, cluster) pair — to track which +// labels are managed on each cluster and to enable conflict detection via the keymanager. +type ManagementClusterClassifierReport struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ManagementClusterClassifierReportSpec `json:"spec,omitempty"` + Status ManagementClusterClassifierReportStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// ManagementClusterClassifierReportList contains a list of ManagementClusterClassifierReport. +type ManagementClusterClassifierReportList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ManagementClusterClassifierReport `json:"items"` +} + +func init() { + SchemeBuilder.Register(func(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(GroupVersion, + &ManagementClusterClassifierReport{}, + &ManagementClusterClassifierReportList{}, + ) + return nil + }) +} diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 7a6c652..9be406c 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -1801,6 +1801,213 @@ func (in *MachingClusterStatus) DeepCopy() *MachingClusterStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ManagementClusterClassifier) DeepCopyInto(out *ManagementClusterClassifier) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagementClusterClassifier. +func (in *ManagementClusterClassifier) DeepCopy() *ManagementClusterClassifier { + if in == nil { + return nil + } + out := new(ManagementClusterClassifier) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ManagementClusterClassifier) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ManagementClusterClassifierList) DeepCopyInto(out *ManagementClusterClassifierList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ManagementClusterClassifier, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagementClusterClassifierList. +func (in *ManagementClusterClassifierList) DeepCopy() *ManagementClusterClassifierList { + if in == nil { + return nil + } + out := new(ManagementClusterClassifierList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ManagementClusterClassifierList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ManagementClusterClassifierReport) DeepCopyInto(out *ManagementClusterClassifierReport) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagementClusterClassifierReport. +func (in *ManagementClusterClassifierReport) DeepCopy() *ManagementClusterClassifierReport { + if in == nil { + return nil + } + out := new(ManagementClusterClassifierReport) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ManagementClusterClassifierReport) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ManagementClusterClassifierReportList) DeepCopyInto(out *ManagementClusterClassifierReportList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ManagementClusterClassifierReport, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagementClusterClassifierReportList. +func (in *ManagementClusterClassifierReportList) DeepCopy() *ManagementClusterClassifierReportList { + if in == nil { + return nil + } + out := new(ManagementClusterClassifierReportList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ManagementClusterClassifierReportList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ManagementClusterClassifierReportSpec) DeepCopyInto(out *ManagementClusterClassifierReportSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagementClusterClassifierReportSpec. +func (in *ManagementClusterClassifierReportSpec) DeepCopy() *ManagementClusterClassifierReportSpec { + if in == nil { + return nil + } + out := new(ManagementClusterClassifierReportSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ManagementClusterClassifierReportStatus) DeepCopyInto(out *ManagementClusterClassifierReportStatus) { + *out = *in + if in.ManagedLabels != nil { + in, out := &in.ManagedLabels, &out.ManagedLabels + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.UnManagedLabels != nil { + in, out := &in.UnManagedLabels, &out.UnManagedLabels + *out = make([]UnManagedLabel, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagementClusterClassifierReportStatus. +func (in *ManagementClusterClassifierReportStatus) DeepCopy() *ManagementClusterClassifierReportStatus { + if in == nil { + return nil + } + out := new(ManagementClusterClassifierReportStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ManagementClusterClassifierSpec) DeepCopyInto(out *ManagementClusterClassifierSpec) { + *out = *in + if in.MatchResources != nil { + in, out := &in.MatchResources, &out.MatchResources + *out = make([]ResourceSelector, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ClassifierLabels != nil { + in, out := &in.ClassifierLabels, &out.ClassifierLabels + *out = make([]ClassifierLabel, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagementClusterClassifierSpec. +func (in *ManagementClusterClassifierSpec) DeepCopy() *ManagementClusterClassifierSpec { + if in == nil { + return nil + } + out := new(ManagementClusterClassifierSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ManagementClusterClassifierStatus) DeepCopyInto(out *ManagementClusterClassifierStatus) { + *out = *in + if in.FailureMessage != nil { + in, out := &in.FailureMessage, &out.FailureMessage + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagementClusterClassifierStatus. +func (in *ManagementClusterClassifierStatus) DeepCopy() *ManagementClusterClassifierStatus { + if in == nil { + return nil + } + out := new(ManagementClusterClassifierStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MessagingMatchCriteria) DeepCopyInto(out *MessagingMatchCriteria) { *out = *in diff --git a/config/crd/bases/lib.projectsveltos.io_managementclusterclassifierreports.yaml b/config/crd/bases/lib.projectsveltos.io_managementclusterclassifierreports.yaml new file mode 100644 index 0000000..c40afce --- /dev/null +++ b/config/crd/bases/lib.projectsveltos.io_managementclusterclassifierreports.yaml @@ -0,0 +1,106 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.21.0 + name: managementclusterclassifierreports.lib.projectsveltos.io +spec: + group: lib.projectsveltos.io + names: + kind: ManagementClusterClassifierReport + listKind: ManagementClusterClassifierReportList + plural: managementclusterclassifierreports + singular: managementclusterclassifierreport + scope: Namespaced + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + description: |- + ManagementClusterClassifierReport is created by the ManagementClusterClassifier + controller — one per (ManagementClusterClassifier, cluster) pair — to track which + labels are managed on each cluster and to enable conflict detection via the keymanager. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + ManagementClusterClassifierReportSpec identifies the classifier and cluster this + report belongs to. + properties: + classifierName: + description: ClassifierName is the name of the ManagementClusterClassifier + this report is for. + type: string + clusterName: + description: ClusterName is the name of the cluster this report is + for. + type: string + clusterNamespace: + description: ClusterNamespace is the namespace of the cluster this + report is for. + type: string + clusterType: + description: ClusterType is the type of the cluster this report is + for. + type: string + required: + - classifierName + - clusterName + - clusterNamespace + - clusterType + type: object + status: + description: ManagementClusterClassifierReportStatus is written by the + controller after processing. + properties: + managedLabels: + description: |- + ManagedLabels lists the label keys this ManagementClusterClassifier is + actively managing on the cluster. + items: + type: string + type: array + unmanagedLabels: + description: |- + UnManagedLabels lists label keys this ManagementClusterClassifier would like + to manage but cannot because another Classifier or ManagementClusterClassifier + already owns them. + items: + properties: + failureMessage: + description: |- + FailureMessage is a human consumable message explaining the + misconfiguration + type: string + key: + description: |- + Key represents a label Classifier would like to manage + but cannot because currently managed by different instance + type: string + required: + - key + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/lib.projectsveltos.io_managementclusterclassifiers.yaml b/config/crd/bases/lib.projectsveltos.io_managementclusterclassifiers.yaml new file mode 100644 index 0000000..bac65e3 --- /dev/null +++ b/config/crd/bases/lib.projectsveltos.io_managementclusterclassifiers.yaml @@ -0,0 +1,238 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.21.0 + name: managementclusterclassifiers.lib.projectsveltos.io +spec: + group: lib.projectsveltos.io + names: + kind: ManagementClusterClassifier + listKind: ManagementClusterClassifierList + plural: managementclusterclassifiers + singular: managementclusterclassifier + scope: Cluster + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + description: |- + ManagementClusterClassifier evaluates resources on the management cluster and + labels managed clusters accordingly. Unlike Classifier, no deployment to managed + clusters is required: the Lua function runs entirely on the management cluster and + returns the list of clusters to label. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ManagementClusterClassifierSpec defines the desired state + of ManagementClusterClassifier. + properties: + classificationLua: + description: |- + ClassificationLua is a Lua function called once per reconcile with the full + set of resources matched by MatchResources. It receives the array as resources + and must return an array of cluster references. + Each entry must have fields: namespace (string), name (string), kind (string). + kind must be "SveltosCluster" or "Cluster". Entries with a missing or unrecognized + kind are skipped and recorded in status.failureMessage. + Passing all resources at once allows the function to make decisions that + depend on the relationship between multiple resources. + type: string + classifierLabels: + description: |- + ClassifierLabels is the set of labels to add to every cluster returned by + ClassificationLua. Same type as Classifier.spec.classifierLabels. + items: + properties: + key: + description: Key is the label key + type: string + value: + description: Value is the label value + type: string + required: + - key + - value + type: object + type: array + matchResources: + description: |- + MatchResources lists the management-cluster resource types to watch. + Reuses the existing ResourceSelector type. Label/name/namespace filters + and per-resource Lua (ResourceSelector.Evaluate) all apply: only objects + where Evaluate returns {matching: true} are included in the resources array + passed to ClassificationLua. Same behavior as the existing Classifier. + items: + description: ResourceSelector defines what resources are a match + properties: + evaluate: + description: |- + Evaluate contains a function "evaluate" in lua language. + The function will be passed one of the object selected based on + above criteria. + Must return struct with field "matching" representing whether + object is a match and an optional "message" field. + type: string + evaluateCEL: + description: |- + EvaluateCEL contains a list of named CEL (Common Expression Language) rules. + Each rule will be evaluated in order against each object selected based on + the criteria defined above. Each rule's expression must return a boolean value + indicating whether the object is a match. + + Evaluation stops at the first rule that returns true; subsequent + rules will not be evaluated. + items: + description: CELRule defines a named CEL rule used in EvaluateCEL. + properties: + name: + description: Name is a human-readable identifier for the + rule. + type: string + rule: + description: |- + Rule is the CEL (Common Expression Language) expression to evaluate. + It must return a bool + type: string + required: + - name + - rule + type: object + type: array + group: + description: Group of the resource deployed in the Cluster. + type: string + kind: + description: Kind of the resource deployed in the Cluster. + minLength: 1 + type: string + labelFilters: + description: LabelFilters allows to filter resources based on + current labels. + items: + properties: + key: + description: Key is the label key + type: string + operation: + description: Operation is the comparison operation + enum: + - Equal + - Different + - Has + - DoesNotHave + type: string + value: + description: Value is the label value + type: string + required: + - key + - operation + type: object + type: array + name: + description: Name of the resource deployed in the Cluster. + type: string + namespace: + description: |- + Namespace of the resource deployed in the Cluster. + Empty for resources scoped at cluster level. + For namespaced resources, an empty string "" indicates all namespaces. + type: string + selector: + description: |- + Selector is a standard Kubernetes label selector. Resources are selected + if their labels match the selector. This field uses the standard + Kubernetes label matching syntax (e.g., {"environment": "production"}). + If both LabelFilters and Selector are specified, the requirements from + both are logically ANDed. + 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 + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + 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 + version: + description: Version of the resource deployed in the Cluster. + type: string + required: + - group + - kind + - version + type: object + type: array + required: + - classificationLua + - classifierLabels + - matchResources + type: object + status: + description: ManagementClusterClassifierStatus defines the observed state + of ManagementClusterClassifier. + properties: + failureMessage: + description: |- + FailureMessage reports the error from the last reconcile, if any. + Set when resource collection or Lua evaluation fails; cleared on success. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 24c6539..bc21f03 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -22,6 +22,8 @@ resources: - bases/lib.projectsveltos.io_configurationbundles.yaml - bases/lib.projectsveltos.io_configurationgroups.yaml - bases/lib.projectsveltos.io_sveltoslicenses.yaml +- bases/lib.projectsveltos.io_managementclusterclassifiers.yaml +- bases/lib.projectsveltos.io_managementclusterclassifierreports.yaml patches: # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. diff --git a/generator.go b/generator.go index 813fa2f..4859c7a 100644 --- a/generator.go +++ b/generator.go @@ -148,4 +148,10 @@ func main() { sveltosLicenseFile := "../../manifests/apiextensions.k8s.io_v1_customresourcedefinition_sveltoslicenses.lib.projectsveltos.io.yaml" generate(sveltosLicenseFile, "sveltoslicenses", "SveltosLicense") + + managementclusterclassifierFile := "../../manifests/apiextensions.k8s.io_v1_customresourcedefinition_managementclusterclassifiers.lib.projectsveltos.io.yaml" + generate(managementclusterclassifierFile, "managementclusterclassifiers", "ManagementClusterClassifier") + + managementclusterclassifierreportsFile := "../../manifests/apiextensions.k8s.io_v1_customresourcedefinition_managementclusterclassifierreports.lib.projectsveltos.io.yaml" + generate(managementclusterclassifierreportsFile, "managementclusterclassifierreports", "ManagementClusterClassifierReport") } diff --git a/lib/crd/crd.go b/lib/crd/crd.go index 60fe2b8..a989402 100644 --- a/lib/crd/crd.go +++ b/lib/crd/crd.go @@ -97,3 +97,11 @@ func GetConfigurationGroupCRDYAML() []byte { func GetSveltosLicenseCRDYAML() []byte { return SveltosLicenseCRD } + +func GetManagementClusterClassifierCRDYAML() []byte { + return ManagementClusterClassifierCRD +} + +func GetManagementClusterClassifierReportCRDYAML() []byte { + return ManagementClusterClassifierReportCRD +} diff --git a/lib/crd/crd_test.go b/lib/crd/crd_test.go index b2a6e65..bf2421c 100644 --- a/lib/crd/crd_test.go +++ b/lib/crd/crd_test.go @@ -215,4 +215,34 @@ var _ = Describe("CRD", func() { Expect(string(yaml)).To(Equal(string(currentFile))) }) + + It("Gets the SveltosLicense CustomResourceDefinition", func() { + yaml := crd.GetSveltosLicenseCRDYAML() + + filename := "../../manifests/apiextensions.k8s.io_v1_customresourcedefinition_sveltoslicenses.lib.projectsveltos.io.yaml" + currentFile, err := os.ReadFile(filename) + Expect(err).To(BeNil()) + + Expect(string(yaml)).To(Equal(string(currentFile))) + }) + + It("Gets the ManagementClusterClassifier CustomResourceDefinition", func() { + yaml := crd.GetManagementClusterClassifierCRDYAML() + + filename := "../../manifests/apiextensions.k8s.io_v1_customresourcedefinition_managementclusterclassifiers.lib.projectsveltos.io.yaml" + currentFile, err := os.ReadFile(filename) + Expect(err).To(BeNil()) + + Expect(string(yaml)).To(Equal(string(currentFile))) + }) + + It("Gets the ManagementClusterClassifierReport CustomResourceDefinition", func() { + yaml := crd.GetManagementClusterClassifierReportCRDYAML() + + filename := "../../manifests/apiextensions.k8s.io_v1_customresourcedefinition_managementclusterclassifierreports.lib.projectsveltos.io.yaml" + currentFile, err := os.ReadFile(filename) + Expect(err).To(BeNil()) + + Expect(string(yaml)).To(Equal(string(currentFile))) + }) }) diff --git a/lib/crd/managementclusterclassifierreports.go b/lib/crd/managementclusterclassifierreports.go new file mode 100644 index 0000000..4c2be1e --- /dev/null +++ b/lib/crd/managementclusterclassifierreports.go @@ -0,0 +1,125 @@ +// Generated by *go generate* - DO NOT EDIT +/* +Copyright 2022-23. projectsveltos.io. All rights reserved. + +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 crd + +var ManagementClusterClassifierReportFile = "../../manifests/apiextensions.k8s.io_v1_customresourcedefinition_managementclusterclassifierreports.lib.projectsveltos.io.yaml" +var ManagementClusterClassifierReportCRD = []byte(`apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.21.0 + name: managementclusterclassifierreports.lib.projectsveltos.io +spec: + group: lib.projectsveltos.io + names: + kind: ManagementClusterClassifierReport + listKind: ManagementClusterClassifierReportList + plural: managementclusterclassifierreports + singular: managementclusterclassifierreport + scope: Namespaced + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + description: |- + ManagementClusterClassifierReport is created by the ManagementClusterClassifier + controller — one per (ManagementClusterClassifier, cluster) pair — to track which + labels are managed on each cluster and to enable conflict detection via the keymanager. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + ManagementClusterClassifierReportSpec identifies the classifier and cluster this + report belongs to. + properties: + classifierName: + description: ClassifierName is the name of the ManagementClusterClassifier + this report is for. + type: string + clusterName: + description: ClusterName is the name of the cluster this report is + for. + type: string + clusterNamespace: + description: ClusterNamespace is the namespace of the cluster this + report is for. + type: string + clusterType: + description: ClusterType is the type of the cluster this report is + for. + type: string + required: + - classifierName + - clusterName + - clusterNamespace + - clusterType + type: object + status: + description: ManagementClusterClassifierReportStatus is written by the + controller after processing. + properties: + managedLabels: + description: |- + ManagedLabels lists the label keys this ManagementClusterClassifier is + actively managing on the cluster. + items: + type: string + type: array + unmanagedLabels: + description: |- + UnManagedLabels lists label keys this ManagementClusterClassifier would like + to manage but cannot because another Classifier or ManagementClusterClassifier + already owns them. + items: + properties: + failureMessage: + description: |- + FailureMessage is a human consumable message explaining the + misconfiguration + type: string + key: + description: |- + Key represents a label Classifier would like to manage + but cannot because currently managed by different instance + type: string + required: + - key + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} +`) diff --git a/lib/crd/managementclusterclassifiers.go b/lib/crd/managementclusterclassifiers.go new file mode 100644 index 0000000..d2f437d --- /dev/null +++ b/lib/crd/managementclusterclassifiers.go @@ -0,0 +1,257 @@ +// Generated by *go generate* - DO NOT EDIT +/* +Copyright 2022-23. projectsveltos.io. All rights reserved. + +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 crd + +var ManagementClusterClassifierFile = "../../manifests/apiextensions.k8s.io_v1_customresourcedefinition_managementclusterclassifiers.lib.projectsveltos.io.yaml" +var ManagementClusterClassifierCRD = []byte(`apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.21.0 + name: managementclusterclassifiers.lib.projectsveltos.io +spec: + group: lib.projectsveltos.io + names: + kind: ManagementClusterClassifier + listKind: ManagementClusterClassifierList + plural: managementclusterclassifiers + singular: managementclusterclassifier + scope: Cluster + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + description: |- + ManagementClusterClassifier evaluates resources on the management cluster and + labels managed clusters accordingly. Unlike Classifier, no deployment to managed + clusters is required: the Lua function runs entirely on the management cluster and + returns the list of clusters to label. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ManagementClusterClassifierSpec defines the desired state + of ManagementClusterClassifier. + properties: + classificationLua: + description: |- + ClassificationLua is a Lua function called once per reconcile with the full + set of resources matched by MatchResources. It receives the array as resources + and must return an array of cluster references. + Each entry must have fields: namespace (string), name (string), kind (string). + kind must be "SveltosCluster" or "Cluster". Entries with a missing or unrecognized + kind are skipped and recorded in status.failureMessage. + Passing all resources at once allows the function to make decisions that + depend on the relationship between multiple resources. + type: string + classifierLabels: + description: |- + ClassifierLabels is the set of labels to add to every cluster returned by + ClassificationLua. Same type as Classifier.spec.classifierLabels. + items: + properties: + key: + description: Key is the label key + type: string + value: + description: Value is the label value + type: string + required: + - key + - value + type: object + type: array + matchResources: + description: |- + MatchResources lists the management-cluster resource types to watch. + Reuses the existing ResourceSelector type. Label/name/namespace filters + and per-resource Lua (ResourceSelector.Evaluate) all apply: only objects + where Evaluate returns {matching: true} are included in the resources array + passed to ClassificationLua. Same behavior as the existing Classifier. + items: + description: ResourceSelector defines what resources are a match + properties: + evaluate: + description: |- + Evaluate contains a function "evaluate" in lua language. + The function will be passed one of the object selected based on + above criteria. + Must return struct with field "matching" representing whether + object is a match and an optional "message" field. + type: string + evaluateCEL: + description: |- + EvaluateCEL contains a list of named CEL (Common Expression Language) rules. + Each rule will be evaluated in order against each object selected based on + the criteria defined above. Each rule's expression must return a boolean value + indicating whether the object is a match. + + Evaluation stops at the first rule that returns true; subsequent + rules will not be evaluated. + items: + description: CELRule defines a named CEL rule used in EvaluateCEL. + properties: + name: + description: Name is a human-readable identifier for the + rule. + type: string + rule: + description: |- + Rule is the CEL (Common Expression Language) expression to evaluate. + It must return a bool + type: string + required: + - name + - rule + type: object + type: array + group: + description: Group of the resource deployed in the Cluster. + type: string + kind: + description: Kind of the resource deployed in the Cluster. + minLength: 1 + type: string + labelFilters: + description: LabelFilters allows to filter resources based on + current labels. + items: + properties: + key: + description: Key is the label key + type: string + operation: + description: Operation is the comparison operation + enum: + - Equal + - Different + - Has + - DoesNotHave + type: string + value: + description: Value is the label value + type: string + required: + - key + - operation + type: object + type: array + name: + description: Name of the resource deployed in the Cluster. + type: string + namespace: + description: |- + Namespace of the resource deployed in the Cluster. + Empty for resources scoped at cluster level. + For namespaced resources, an empty string "" indicates all namespaces. + type: string + selector: + description: |- + Selector is a standard Kubernetes label selector. Resources are selected + if their labels match the selector. This field uses the standard + Kubernetes label matching syntax (e.g., {"environment": "production"}). + If both LabelFilters and Selector are specified, the requirements from + both are logically ANDed. + 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 + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + 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 + version: + description: Version of the resource deployed in the Cluster. + type: string + required: + - group + - kind + - version + type: object + type: array + required: + - classificationLua + - classifierLabels + - matchResources + type: object + status: + description: ManagementClusterClassifierStatus defines the observed state + of ManagementClusterClassifier. + properties: + failureMessage: + description: |- + FailureMessage reports the error from the last reconcile, if any. + Set when resource collection or Lua evaluation fails; cleared on success. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +`) diff --git a/manifests/apiextensions.k8s.io_v1_customresourcedefinition_managementclusterclassifierreports.lib.projectsveltos.io.yaml b/manifests/apiextensions.k8s.io_v1_customresourcedefinition_managementclusterclassifierreports.lib.projectsveltos.io.yaml new file mode 100644 index 0000000..05d2983 --- /dev/null +++ b/manifests/apiextensions.k8s.io_v1_customresourcedefinition_managementclusterclassifierreports.lib.projectsveltos.io.yaml @@ -0,0 +1,105 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.21.0 + name: managementclusterclassifierreports.lib.projectsveltos.io +spec: + group: lib.projectsveltos.io + names: + kind: ManagementClusterClassifierReport + listKind: ManagementClusterClassifierReportList + plural: managementclusterclassifierreports + singular: managementclusterclassifierreport + scope: Namespaced + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + description: |- + ManagementClusterClassifierReport is created by the ManagementClusterClassifier + controller — one per (ManagementClusterClassifier, cluster) pair — to track which + labels are managed on each cluster and to enable conflict detection via the keymanager. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + ManagementClusterClassifierReportSpec identifies the classifier and cluster this + report belongs to. + properties: + classifierName: + description: ClassifierName is the name of the ManagementClusterClassifier + this report is for. + type: string + clusterName: + description: ClusterName is the name of the cluster this report is + for. + type: string + clusterNamespace: + description: ClusterNamespace is the namespace of the cluster this + report is for. + type: string + clusterType: + description: ClusterType is the type of the cluster this report is + for. + type: string + required: + - classifierName + - clusterName + - clusterNamespace + - clusterType + type: object + status: + description: ManagementClusterClassifierReportStatus is written by the + controller after processing. + properties: + managedLabels: + description: |- + ManagedLabels lists the label keys this ManagementClusterClassifier is + actively managing on the cluster. + items: + type: string + type: array + unmanagedLabels: + description: |- + UnManagedLabels lists label keys this ManagementClusterClassifier would like + to manage but cannot because another Classifier or ManagementClusterClassifier + already owns them. + items: + properties: + failureMessage: + description: |- + FailureMessage is a human consumable message explaining the + misconfiguration + type: string + key: + description: |- + Key represents a label Classifier would like to manage + but cannot because currently managed by different instance + type: string + required: + - key + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/manifests/apiextensions.k8s.io_v1_customresourcedefinition_managementclusterclassifiers.lib.projectsveltos.io.yaml b/manifests/apiextensions.k8s.io_v1_customresourcedefinition_managementclusterclassifiers.lib.projectsveltos.io.yaml new file mode 100644 index 0000000..238a4ed --- /dev/null +++ b/manifests/apiextensions.k8s.io_v1_customresourcedefinition_managementclusterclassifiers.lib.projectsveltos.io.yaml @@ -0,0 +1,237 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.21.0 + name: managementclusterclassifiers.lib.projectsveltos.io +spec: + group: lib.projectsveltos.io + names: + kind: ManagementClusterClassifier + listKind: ManagementClusterClassifierList + plural: managementclusterclassifiers + singular: managementclusterclassifier + scope: Cluster + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + description: |- + ManagementClusterClassifier evaluates resources on the management cluster and + labels managed clusters accordingly. Unlike Classifier, no deployment to managed + clusters is required: the Lua function runs entirely on the management cluster and + returns the list of clusters to label. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ManagementClusterClassifierSpec defines the desired state + of ManagementClusterClassifier. + properties: + classificationLua: + description: |- + ClassificationLua is a Lua function called once per reconcile with the full + set of resources matched by MatchResources. It receives the array as resources + and must return an array of cluster references. + Each entry must have fields: namespace (string), name (string), kind (string). + kind must be "SveltosCluster" or "Cluster". Entries with a missing or unrecognized + kind are skipped and recorded in status.failureMessage. + Passing all resources at once allows the function to make decisions that + depend on the relationship between multiple resources. + type: string + classifierLabels: + description: |- + ClassifierLabels is the set of labels to add to every cluster returned by + ClassificationLua. Same type as Classifier.spec.classifierLabels. + items: + properties: + key: + description: Key is the label key + type: string + value: + description: Value is the label value + type: string + required: + - key + - value + type: object + type: array + matchResources: + description: |- + MatchResources lists the management-cluster resource types to watch. + Reuses the existing ResourceSelector type. Label/name/namespace filters + and per-resource Lua (ResourceSelector.Evaluate) all apply: only objects + where Evaluate returns {matching: true} are included in the resources array + passed to ClassificationLua. Same behavior as the existing Classifier. + items: + description: ResourceSelector defines what resources are a match + properties: + evaluate: + description: |- + Evaluate contains a function "evaluate" in lua language. + The function will be passed one of the object selected based on + above criteria. + Must return struct with field "matching" representing whether + object is a match and an optional "message" field. + type: string + evaluateCEL: + description: |- + EvaluateCEL contains a list of named CEL (Common Expression Language) rules. + Each rule will be evaluated in order against each object selected based on + the criteria defined above. Each rule's expression must return a boolean value + indicating whether the object is a match. + + Evaluation stops at the first rule that returns true; subsequent + rules will not be evaluated. + items: + description: CELRule defines a named CEL rule used in EvaluateCEL. + properties: + name: + description: Name is a human-readable identifier for the + rule. + type: string + rule: + description: |- + Rule is the CEL (Common Expression Language) expression to evaluate. + It must return a bool + type: string + required: + - name + - rule + type: object + type: array + group: + description: Group of the resource deployed in the Cluster. + type: string + kind: + description: Kind of the resource deployed in the Cluster. + minLength: 1 + type: string + labelFilters: + description: LabelFilters allows to filter resources based on + current labels. + items: + properties: + key: + description: Key is the label key + type: string + operation: + description: Operation is the comparison operation + enum: + - Equal + - Different + - Has + - DoesNotHave + type: string + value: + description: Value is the label value + type: string + required: + - key + - operation + type: object + type: array + name: + description: Name of the resource deployed in the Cluster. + type: string + namespace: + description: |- + Namespace of the resource deployed in the Cluster. + Empty for resources scoped at cluster level. + For namespaced resources, an empty string "" indicates all namespaces. + type: string + selector: + description: |- + Selector is a standard Kubernetes label selector. Resources are selected + if their labels match the selector. This field uses the standard + Kubernetes label matching syntax (e.g., {"environment": "production"}). + If both LabelFilters and Selector are specified, the requirements from + both are logically ANDed. + 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 + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + 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 + version: + description: Version of the resource deployed in the Cluster. + type: string + required: + - group + - kind + - version + type: object + type: array + required: + - classificationLua + - classifierLabels + - matchResources + type: object + status: + description: ManagementClusterClassifierStatus defines the observed state + of ManagementClusterClassifier. + properties: + failureMessage: + description: |- + FailureMessage reports the error from the last reconcile, if any. + Set when resource collection or Lua evaluation fails; cleared on success. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {}