From 0b08a2bf43aaa6118997f272f5f2c9c234ee0263 Mon Sep 17 00:00:00 2001 From: Stefan Bueringer Date: Mon, 25 Mar 2024 12:15:46 +0100 Subject: [PATCH] Add ClusterClass variables metadata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stefan Büringer buringerst@vmware.com --- api/v1beta1/clusterclass_types.go | 21 ++++++++++ .../cluster.x-k8s.io_clusterclasses.yaml | 22 +++++++++++ .../clusterclass_variable_validation.go | 18 +++++++++ .../clusterclass_variable_validation_test.go | 38 +++++++++++++++++++ .../main/clusterclass-quick-start.yaml | 6 +++ 5 files changed, 105 insertions(+) diff --git a/api/v1beta1/clusterclass_types.go b/api/v1beta1/clusterclass_types.go index 19cdad710c2f..e2733d287c1d 100644 --- a/api/v1beta1/clusterclass_types.go +++ b/api/v1beta1/clusterclass_types.go @@ -382,10 +382,31 @@ type ClusterClassVariable struct { // required, this will be specified inside the schema. Required bool `json:"required"` + // Metadata is the metadata of a variable. + // It can be used to add additional data for higher level tools to + // a ClusterClassVariable. + Metadata ClusterClassVariableMetadata `json:"metadata,omitempty"` + // Schema defines the schema of the variable. Schema VariableSchema `json:"schema"` } +// ClusterClassVariableMetadata is the metadata of a variable. +// It can be used to add additional data for higher level tools to +// a ClusterClassVariable. +type ClusterClassVariableMetadata struct { + // Map of string keys and values that can be used to organize and categorize + // (scope and select) variables. + // +optional + Labels map[string]string `json:"labels,omitempty"` + + // Annotations is an unstructured key value map that can be used to store and + // retrieve arbitrary metadata. + // They are not queryable. + // +optional + Annotations map[string]string `json:"annotations,omitempty"` +} + // VariableSchema defines the schema of a variable. type VariableSchema struct { // OpenAPIV3Schema defines the schema of a variable via OpenAPI v3 diff --git a/config/crd/bases/cluster.x-k8s.io_clusterclasses.yaml b/config/crd/bases/cluster.x-k8s.io_clusterclasses.yaml index 4c0533672220..c996e47dc1bb 100644 --- a/config/crd/bases/cluster.x-k8s.io_clusterclasses.yaml +++ b/config/crd/bases/cluster.x-k8s.io_clusterclasses.yaml @@ -979,6 +979,28 @@ spec: ClusterClassVariable defines a variable which can be configured in the Cluster topology and used in patches. properties: + metadata: + description: |- + Metadata is the metadata of a variable. + It can be used to add additional data for higher level tools to + a ClusterClassVariable. + properties: + annotations: + additionalProperties: + type: string + description: |- + Annotations is an unstructured key value map that can be used to store and + retrieve arbitrary metadata. + They are not queryable. + type: object + labels: + additionalProperties: + type: string + description: |- + Map of string keys and values that can be used to organize and categorize + (scope and select) variables. + type: object + type: object name: description: Name of the variable. type: string diff --git a/internal/topology/variables/clusterclass_variable_validation.go b/internal/topology/variables/clusterclass_variable_validation.go index d6b47bce973d..d498441e3afb 100644 --- a/internal/topology/variables/clusterclass_variable_validation.go +++ b/internal/topology/variables/clusterclass_variable_validation.go @@ -25,6 +25,8 @@ import ( structuralschema "k8s.io/apiextensions-apiserver/pkg/apiserver/schema" structuraldefaulting "k8s.io/apiextensions-apiserver/pkg/apiserver/schema/defaulting" "k8s.io/apiextensions-apiserver/pkg/apiserver/validation" + apivalidation "k8s.io/apimachinery/pkg/api/validation" + metav1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/validation/field" @@ -77,6 +79,9 @@ func validateClusterClassVariable(ctx context.Context, variable *clusterv1.Clust // Validate variable name. allErrs = append(allErrs, validateClusterClassVariableName(variable.Name, fldPath.Child("name"))...) + // Validate variable metadata. + allErrs = append(allErrs, validateClusterClassVariableMetadata(variable.Metadata, fldPath.Child("metadata"))...) + // Validate schema. allErrs = append(allErrs, validateRootSchema(ctx, variable, fldPath.Child("schema", "openAPIV3Schema"))...) @@ -101,6 +106,19 @@ func validateClusterClassVariableName(variableName string, fldPath *field.Path) return allErrs } +// validateClusterClassVariableMetadata validates a variable metadata. +func validateClusterClassVariableMetadata(metadata clusterv1.ClusterClassVariableMetadata, fldPath *field.Path) field.ErrorList { + allErrs := metav1validation.ValidateLabels( + metadata.Labels, + fldPath.Child("labels"), + ) + allErrs = append(allErrs, apivalidation.ValidateAnnotations( + metadata.Annotations, + fldPath.Child("annotations"), + )...) + return allErrs +} + var validVariableTypes = sets.Set[string]{}.Insert("object", "array", "string", "number", "integer", "boolean") // validateRootSchema validates the schema. diff --git a/internal/topology/variables/clusterclass_variable_validation_test.go b/internal/topology/variables/clusterclass_variable_validation_test.go index 040005389899..47526de07a50 100644 --- a/internal/topology/variables/clusterclass_variable_validation_test.go +++ b/internal/topology/variables/clusterclass_variable_validation_test.go @@ -200,6 +200,44 @@ func Test_ValidateClusterClassVariable(t *testing.T) { }, wantErr: true, }, + { + name: "Valid variable metadata", + clusterClassVariable: &clusterv1.ClusterClassVariable{ + Name: "validVariable", + Metadata: clusterv1.ClusterClassVariableMetadata{ + Labels: map[string]string{ + "label-key": "label-value", + }, + Annotations: map[string]string{ + "annotation-key": "annotation-value", + }, + }, + }, + }, + { + name: "fail on invalid variable label: key does not start with alphanumeric character", + clusterClassVariable: &clusterv1.ClusterClassVariable{ + Name: "path.tovariable", + Metadata: clusterv1.ClusterClassVariableMetadata{ + Labels: map[string]string{ + ".label-key": "label-value", + }, + }, + }, + wantErr: true, + }, + { + name: "fail on invalid variable annotation: key does not start with alphanumeric character", + clusterClassVariable: &clusterv1.ClusterClassVariable{ + Name: "path.tovariable", + Metadata: clusterv1.ClusterClassVariableMetadata{ + Annotations: map[string]string{ + ".annotation-key": "annotation-value", + }, + }, + }, + wantErr: true, + }, { name: "Valid default value regular string", clusterClassVariable: &clusterv1.ClusterClassVariable{ diff --git a/test/e2e/data/infrastructure-docker/main/clusterclass-quick-start.yaml b/test/e2e/data/infrastructure-docker/main/clusterclass-quick-start.yaml index a8c059f98ce9..50d9c2865e1b 100644 --- a/test/e2e/data/infrastructure-docker/main/clusterclass-quick-start.yaml +++ b/test/e2e/data/infrastructure-docker/main/clusterclass-quick-start.yaml @@ -81,6 +81,12 @@ spec: default: kindest - name: etcdImageTag required: true + # This metadata has just been added to verify that we can set metadata. + metadata: + labels: + testLabelKey: testLabelValue + annotations: + testAnnotationKey: testAnnotationValue schema: openAPIV3Schema: type: string