diff --git a/.golangci.yaml b/.golangci.yaml index 900902415..5615edef8 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -208,6 +208,10 @@ linters: - linters: - goconst path: (.+)_test\.go + # Deprecated fields on v1alpha1.PluginOptionValue / PluginValueFromSource are intentionally + # still referenced during the deprecation window (see api/v1alpha1/plugin_types.go). + - linters: [staticcheck] + text: 'SA1019: .*\.(Expression|Ref) is deprecated' paths: - third_party$ - builtin$ diff --git a/api/v1alpha1/plugin_types.go b/api/v1alpha1/plugin_types.go index 0e690c4f4..f0e8c5f32 100644 --- a/api/v1alpha1/plugin_types.go +++ b/api/v1alpha1/plugin_types.go @@ -66,6 +66,9 @@ type PluginOptionValue struct { // ValueFrom references value in another source. ValueFrom *PluginValueFromSource `json:"valueFrom,omitempty"` // Expression is a YAML string with ${...} placeholders that will be evaluated as CEL expressions. + // + // Deprecated: Expression is deprecated on standalone Plugins and will be removed in a future release. + // Consider using a PluginPreset to deploy Plugins utilizing the Expression field. Expression *string `json:"expression,omitempty"` } @@ -77,6 +80,9 @@ type PluginValueFromSource struct { // Secret references the v1.Secret containing the value that needs to be extracted Secret *SecretKeyReference `json:"secret,omitempty"` // Ref references values defined in another resource (Plugin, PluginPreset) + // + // Deprecated: Ref is deprecated on standalone Plugins and will be removed in a future release. + // Consider using a PluginPreset to deploy Plugins utilizing the Ref field. Ref *ExternalValueSource `json:"ref,omitempty"` } diff --git a/api/v1alpha1/pluginpreset_types.go b/api/v1alpha1/pluginpreset_types.go index 80730076b..579072700 100644 --- a/api/v1alpha1/pluginpreset_types.go +++ b/api/v1alpha1/pluginpreset_types.go @@ -6,6 +6,7 @@ package v1alpha1 import ( "slices" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" greenhousemetav1alpha1 "github.com/cloudoperators/greenhouse/api/meta/v1alpha1" @@ -30,7 +31,7 @@ const ( type PluginPresetSpec struct { // PluginSpec is the spec of the plugin to be deployed by the PluginPreset. - Plugin PluginSpec `json:"plugin"` + Plugin PluginPresetPluginSpec `json:"plugin"` // ClusterSelector is a label selector to select the clusters the plugin bundle should be deployed to. ClusterSelector metav1.LabelSelector `json:"clusterSelector"` @@ -50,6 +51,66 @@ type PluginPresetSpec struct { DeletionPolicy string `json:"deletionPolicy,omitempty"` } +// PluginPresetPluginSpec defines the desired state of Plugin +type PluginPresetPluginSpec struct { + // PluginDefinitionRef is the reference to the (Cluster-)PluginDefinition. + PluginDefinitionRef PluginDefinitionReference `json:"pluginDefinitionRef"` + + // DisplayName is an optional name for the Plugin to be displayed in the Greenhouse UI. + // This is especially helpful to distinguish multiple instances of a PluginDefinition in the same context. + // Defaults to a normalized version of metadata.name. + DisplayName string `json:"displayName,omitempty"` + + // Values are the values for a PluginDefinition instance. + OptionValues []PluginOptionValue `json:"optionValues,omitempty"` + + // ReleaseNamespace is the namespace in the remote cluster to which the backend is deployed. + // Defaults to the Greenhouse managed namespace if not set. + ReleaseNamespace string `json:"releaseNamespace,omitempty"` + + // ReleaseName is the name of the helm release in the remote cluster to which the backend is deployed. + // If the Plugin was already deployed, the Plugin's name is used as the release name. + // If this Plugin is newly created, the releaseName is defaulted to the PluginDefinitions HelmChart name. + // +Optional + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="ReleaseName is immutable" + // +kubebuilder:validation:MaxLength=53 + ReleaseName string `json:"releaseName,omitempty"` + + // DeletionPolicy defines how Helm Releases created by a Plugin are handled upon deletion of the Plugin. + // Supported values are "Delete" and "Retain". If not set, defaults to "Delete". + // +Optional + // +kubebuilder:default=Delete + // +kubebuilder:validation:Enum=Delete;Retain + DeletionPolicy string `json:"deletionPolicy,omitempty"` + + // IgnoreDifferences defines paths to ignore when detecting drift between desired and actual state. + // +Optional + IgnoreDifferences []IgnoreDifference `json:"ignoreDifferences,omitempty"` +} + +// PluginPresetPluginOptionValue is the value for a PluginOption. +type PluginPresetPluginOptionValue struct { + // Name of the values. + Name string `json:"name"` + // Value is the actual value in plain text. + Value *apiextensionsv1.JSON `json:"value,omitempty"` + // ValueFrom references value in another source. + ValueFrom *PluginPresetPluginValueFromSource `json:"valueFrom,omitempty"` + // Expression is a YAML string with ${...} placeholders that will be evaluated as CEL expressions. + Expression *string `json:"expression,omitempty"` +} + +// PluginPresetPluginValueFromSource defines how to extract dynamic values +// only one of secret or ref can be set +// +kubebuilder:validation:XValidation:rule="!(has(self.secret) && has(self.ref))",message="both secret and ref cannot be set" +// +kubebuilder:validation:XValidation:rule="has(self.secret) || has(self.ref)",message="one of secret or ref must be set" +type PluginPresetPluginValueFromSource struct { + // Secret references the v1.Secret containing the value that needs to be extracted + Secret *SecretKeyReference `json:"secret,omitempty"` + // Ref references values defined in another resource (Plugin, PluginPreset) + Ref *ExternalValueSource `json:"ref,omitempty"` +} + // ClusterOptionOverride defines which plugin option should be override in which cluster // +Optional type ClusterOptionOverride struct { diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 9a6a8fb42..f7b889c7a 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1288,6 +1288,91 @@ func (in *PluginPresetList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginPresetPluginOptionValue) DeepCopyInto(out *PluginPresetPluginOptionValue) { + *out = *in + if in.Value != nil { + in, out := &in.Value, &out.Value + *out = new(apiextensionsv1.JSON) + (*in).DeepCopyInto(*out) + } + if in.ValueFrom != nil { + in, out := &in.ValueFrom, &out.ValueFrom + *out = new(PluginPresetPluginValueFromSource) + (*in).DeepCopyInto(*out) + } + if in.Expression != nil { + in, out := &in.Expression, &out.Expression + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginPresetPluginOptionValue. +func (in *PluginPresetPluginOptionValue) DeepCopy() *PluginPresetPluginOptionValue { + if in == nil { + return nil + } + out := new(PluginPresetPluginOptionValue) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginPresetPluginSpec) DeepCopyInto(out *PluginPresetPluginSpec) { + *out = *in + out.PluginDefinitionRef = in.PluginDefinitionRef + if in.OptionValues != nil { + in, out := &in.OptionValues, &out.OptionValues + *out = make([]PluginOptionValue, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.IgnoreDifferences != nil { + in, out := &in.IgnoreDifferences, &out.IgnoreDifferences + *out = make([]IgnoreDifference, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginPresetPluginSpec. +func (in *PluginPresetPluginSpec) DeepCopy() *PluginPresetPluginSpec { + if in == nil { + return nil + } + out := new(PluginPresetPluginSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginPresetPluginValueFromSource) DeepCopyInto(out *PluginPresetPluginValueFromSource) { + *out = *in + if in.Secret != nil { + in, out := &in.Secret, &out.Secret + *out = new(SecretKeyReference) + **out = **in + } + if in.Ref != nil { + in, out := &in.Ref, &out.Ref + *out = new(ExternalValueSource) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginPresetPluginValueFromSource. +func (in *PluginPresetPluginValueFromSource) DeepCopy() *PluginPresetPluginValueFromSource { + if in == nil { + return nil + } + out := new(PluginPresetPluginValueFromSource) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PluginPresetSpec) DeepCopyInto(out *PluginPresetSpec) { *out = *in diff --git a/charts/manager/crds/greenhouse.sap_pluginpresets.yaml b/charts/manager/crds/greenhouse.sap_pluginpresets.yaml index 7d2cecd30..fea9ad82d 100644 --- a/charts/manager/crds/greenhouse.sap_pluginpresets.yaml +++ b/charts/manager/crds/greenhouse.sap_pluginpresets.yaml @@ -71,8 +71,11 @@ spec: description: PluginOptionValue is the value for a PluginOption. properties: expression: - description: Expression is a YAML string with ${...} placeholders - that will be evaluated as CEL expressions. + description: |- + Expression is a YAML string with ${...} placeholders that will be evaluated as CEL expressions. + + Deprecated: Expression is deprecated on standalone Plugins and will be removed in a future release. + Consider using a PluginPreset to deploy Plugins utilizing the Expression field. type: string name: description: Name of the values. @@ -84,8 +87,11 @@ spec: description: ValueFrom references value in another source. properties: ref: - description: Ref references values defined in another - resource (Plugin, PluginPreset) + description: |- + Ref references values defined in another resource (Plugin, PluginPreset) + + Deprecated: Ref is deprecated on standalone Plugins and will be removed in a future release. + Consider using a PluginPreset to deploy Plugins utilizing the Ref field. properties: expression: description: Expression is a CEL expression to @@ -252,11 +258,6 @@ spec: description: PluginSpec is the spec of the plugin to be deployed by the PluginPreset. properties: - clusterName: - description: ClusterName is the name of the cluster the plugin - is deployed to. If not set, the plugin is deployed to the greenhouse - cluster. - type: string deletionPolicy: default: Delete description: |- @@ -309,8 +310,11 @@ spec: description: PluginOptionValue is the value for a PluginOption. properties: expression: - description: Expression is a YAML string with ${...} placeholders - that will be evaluated as CEL expressions. + description: |- + Expression is a YAML string with ${...} placeholders that will be evaluated as CEL expressions. + + Deprecated: Expression is deprecated on standalone Plugins and will be removed in a future release. + Consider using a PluginPreset to deploy Plugins utilizing the Expression field. type: string name: description: Name of the values. @@ -322,8 +326,11 @@ spec: description: ValueFrom references value in another source. properties: ref: - description: Ref references values defined in another - resource (Plugin, PluginPreset) + description: |- + Ref references values defined in another resource (Plugin, PluginPreset) + + Deprecated: Ref is deprecated on standalone Plugins and will be removed in a future release. + Consider using a PluginPreset to deploy Plugins utilizing the Ref field. properties: expression: description: Expression is a CEL expression to extract @@ -455,28 +462,6 @@ spec: ReleaseNamespace is the namespace in the remote cluster to which the backend is deployed. Defaults to the Greenhouse managed namespace if not set. type: string - waitFor: - description: WaitFor defines other Plugins to wait for before - installing this Plugin. - items: - description: WaitForItem is a wrapper around PluginRef to add - context for every WaitFor list item. - properties: - pluginRef: - description: PluginRef defines a reference to the Plugin. - properties: - name: - description: Name of the Plugin. - type: string - pluginPreset: - description: PluginPreset is the name of the PluginPreset - which creates the Plugin. - type: string - type: object - required: - - pluginRef - type: object - type: array required: - pluginDefinitionRef type: object diff --git a/charts/manager/crds/greenhouse.sap_plugins.yaml b/charts/manager/crds/greenhouse.sap_plugins.yaml index e016b0476..65676d7d1 100644 --- a/charts/manager/crds/greenhouse.sap_plugins.yaml +++ b/charts/manager/crds/greenhouse.sap_plugins.yaml @@ -124,8 +124,11 @@ spec: description: PluginOptionValue is the value for a PluginOption. properties: expression: - description: Expression is a YAML string with ${...} placeholders - that will be evaluated as CEL expressions. + description: |- + Expression is a YAML string with ${...} placeholders that will be evaluated as CEL expressions. + + Deprecated: Expression is deprecated on standalone Plugins and will be removed in a future release. + Consider using a PluginPreset to deploy Plugins utilizing the Expression field. type: string name: description: Name of the values. @@ -137,8 +140,11 @@ spec: description: ValueFrom references value in another source. properties: ref: - description: Ref references values defined in another resource - (Plugin, PluginPreset) + description: |- + Ref references values defined in another resource (Plugin, PluginPreset) + + Deprecated: Ref is deprecated on standalone Plugins and will be removed in a future release. + Consider using a PluginPreset to deploy Plugins utilizing the Ref field. properties: expression: description: Expression is a CEL expression to extract diff --git a/docs/reference/api/index.html b/docs/reference/api/index.html index c0d619379..67f0c179c 100644 --- a/docs/reference/api/index.html +++ b/docs/reference/api/index.html @@ -1445,6 +1445,7 @@
(Appears on: +PluginPresetPluginValueFromSource, PluginValueFromSource)
ExternalValueSource defines how to extract values from external resources
@@ -1700,6 +1701,7 @@(Appears on: +PluginPresetPluginSpec, PluginSpec)
IgnoreDifference defines a set of paths to ignore for matching resources.
@@ -2719,6 +2721,7 @@(Appears on: +PluginPresetPluginSpec, PluginSpec)
PluginDefinitionReference defines the reference to the PluginDefinition or ClusterPluginDefinition.
@@ -3064,6 +3067,7 @@(Appears on: ClusterOptionOverride, +PluginPresetPluginSpec, PluginSpec)
PluginOptionValue is the value for a PluginOption.
@@ -3123,6 +3127,8 @@Expression is a YAML string with ${…} placeholders that will be evaluated as CEL expressions.
+Deprecated: Expression is deprecated on standalone Plugins and will be removed in a future release. +Consider using a PluginPreset to deploy Plugins utilizing the Expression field.
pluginPluginPresetPluginOptionValue is the value for a PluginOption.
+| Field | +Description | +
|---|---|
+name+ +string + + |
+
+ Name of the values. + |
+
+value+ + +Kubernetes apiextensions/v1.JSON + + + |
+
+ Value is the actual value in plain text. + |
+
+valueFrom+ + +PluginPresetPluginValueFromSource + + + |
+
+ ValueFrom references value in another source. + |
+
+expression+ +string + + |
+
+ Expression is a YAML string with ${…} placeholders that will be evaluated as CEL expressions. + |
+
+(Appears on: +PluginPresetSpec) +
+PluginPresetPluginSpec defines the desired state of Plugin
+| Field | +Description | +
|---|---|
+pluginDefinitionRef+ + +PluginDefinitionReference + + + |
+
+ PluginDefinitionRef is the reference to the (Cluster-)PluginDefinition. + |
+
+displayName+ +string + + |
+
+ DisplayName is an optional name for the Plugin to be displayed in the Greenhouse UI. +This is especially helpful to distinguish multiple instances of a PluginDefinition in the same context. +Defaults to a normalized version of metadata.name. + |
+
+optionValues+ + +[]PluginOptionValue + + + |
+
+ Values are the values for a PluginDefinition instance. + |
+
+releaseNamespace+ +string + + |
+
+ ReleaseNamespace is the namespace in the remote cluster to which the backend is deployed. +Defaults to the Greenhouse managed namespace if not set. + |
+
+releaseName+ +string + + |
+
+ ReleaseName is the name of the helm release in the remote cluster to which the backend is deployed. +If the Plugin was already deployed, the Plugin’s name is used as the release name. +If this Plugin is newly created, the releaseName is defaulted to the PluginDefinitions HelmChart name. + |
+
+deletionPolicy+ +string + + |
+
+ DeletionPolicy defines how Helm Releases created by a Plugin are handled upon deletion of the Plugin. +Supported values are “Delete” and “Retain”. If not set, defaults to “Delete”. + |
+
+ignoreDifferences+ + +[]IgnoreDifference + + + |
+
+ IgnoreDifferences defines paths to ignore when detecting drift between desired and actual state. + |
+
+(Appears on: +PluginPresetPluginOptionValue) +
+PluginPresetPluginValueFromSource defines how to extract dynamic values +only one of secret or ref can be set
+| Field | +Description | +
|---|---|
+secret+ + +SecretKeyReference + + + |
+
+ Secret references the v1.Secret containing the value that needs to be extracted + |
+
+ref+ + +ExternalValueSource + + + |
+
+ Ref references values defined in another resource (Plugin, PluginPreset) + |
+
@@ -3273,8 +3502,8 @@
plugin(Appears on: -Plugin, -PluginPresetSpec) +Plugin)
PluginSpec defines the desired state of Plugin
Ref references values defined in another resource (Plugin, PluginPreset)
+Deprecated: Ref is deprecated on standalone Plugins and will be removed in a future release. +Consider using a PluginPreset to deploy Plugins utilizing the Ref field.
(Appears on: OIDCConfig, +PluginPresetPluginValueFromSource, PluginValueFromSource, ValueFromSource)
diff --git a/docs/reference/api/openapi.yaml b/docs/reference/api/openapi.yaml index 6fe406f38..95a099a30 100755 --- a/docs/reference/api/openapi.yaml +++ b/docs/reference/api/openapi.yaml @@ -1108,7 +1108,11 @@ components: description: PluginOptionValue is the value for a PluginOption. properties: expression: - description: Expression is a YAML string with ${...} placeholders that will be evaluated as CEL expressions. + description: |- + Expression is a YAML string with ${...} placeholders that will be evaluated as CEL expressions. + + Deprecated: Expression is deprecated on standalone Plugins and will be removed in a future release. + Consider using a PluginPreset to deploy Plugins utilizing the Expression field. type: string name: description: Name of the values. @@ -1120,7 +1124,11 @@ components: description: ValueFrom references value in another source. properties: ref: - description: Ref references values defined in another resource (Plugin, PluginPreset) + description: |- + Ref references values defined in another resource (Plugin, PluginPreset) + + Deprecated: Ref is deprecated on standalone Plugins and will be removed in a future release. + Consider using a PluginPreset to deploy Plugins utilizing the Ref field. properties: expression: description: Expression is a CEL expression to extract the value from the referenced resource @@ -1275,9 +1283,6 @@ components: plugin: description: PluginSpec is the spec of the plugin to be deployed by the PluginPreset. properties: - clusterName: - description: ClusterName is the name of the cluster the plugin is deployed to. If not set, the plugin is deployed to the greenhouse cluster. - type: string deletionPolicy: default: Delete description: |- @@ -1325,7 +1330,11 @@ components: description: PluginOptionValue is the value for a PluginOption. properties: expression: - description: Expression is a YAML string with ${...} placeholders that will be evaluated as CEL expressions. + description: |- + Expression is a YAML string with ${...} placeholders that will be evaluated as CEL expressions. + + Deprecated: Expression is deprecated on standalone Plugins and will be removed in a future release. + Consider using a PluginPreset to deploy Plugins utilizing the Expression field. type: string name: description: Name of the values. @@ -1337,7 +1346,11 @@ components: description: ValueFrom references value in another source. properties: ref: - description: Ref references values defined in another resource (Plugin, PluginPreset) + description: |- + Ref references values defined in another resource (Plugin, PluginPreset) + + Deprecated: Ref is deprecated on standalone Plugins and will be removed in a future release. + Consider using a PluginPreset to deploy Plugins utilizing the Ref field. properties: expression: description: Expression is a CEL expression to extract the value from the referenced resource @@ -1459,25 +1472,6 @@ components: ReleaseNamespace is the namespace in the remote cluster to which the backend is deployed. Defaults to the Greenhouse managed namespace if not set. type: string - waitFor: - description: WaitFor defines other Plugins to wait for before installing this Plugin. - items: - description: WaitForItem is a wrapper around PluginRef to add context for every WaitFor list item. - properties: - pluginRef: - description: PluginRef defines a reference to the Plugin. - properties: - name: - description: Name of the Plugin. - type: string - pluginPreset: - description: PluginPreset is the name of the PluginPreset which creates the Plugin. - type: string - type: object - required: - - pluginRef - type: object - type: array required: - pluginDefinitionRef type: object @@ -1661,7 +1655,11 @@ components: description: PluginOptionValue is the value for a PluginOption. properties: expression: - description: Expression is a YAML string with ${...} placeholders that will be evaluated as CEL expressions. + description: |- + Expression is a YAML string with ${...} placeholders that will be evaluated as CEL expressions. + + Deprecated: Expression is deprecated on standalone Plugins and will be removed in a future release. + Consider using a PluginPreset to deploy Plugins utilizing the Expression field. type: string name: description: Name of the values. @@ -1673,7 +1671,11 @@ components: description: ValueFrom references value in another source. properties: ref: - description: Ref references values defined in another resource (Plugin, PluginPreset) + description: |- + Ref references values defined in another resource (Plugin, PluginPreset) + + Deprecated: Ref is deprecated on standalone Plugins and will be removed in a future release. + Consider using a PluginPreset to deploy Plugins utilizing the Ref field. properties: expression: description: Expression is a CEL expression to extract the value from the referenced resource diff --git a/internal/cmd/plugin_template_test.go b/internal/cmd/plugin_template_test.go index 353428b9b..5ae43d9c0 100644 --- a/internal/cmd/plugin_template_test.go +++ b/internal/cmd/plugin_template_test.go @@ -25,7 +25,7 @@ var _ = Describe("validateCompatibility", func() { pluginPreset: &greenhousev1alpha1.PluginPreset{ TypeMeta: metav1.TypeMeta{Kind: PluginPresetKind}, Spec: greenhousev1alpha1.PluginPresetSpec{ - Plugin: greenhousev1alpha1.PluginSpec{ + Plugin: greenhousev1alpha1.PluginPresetPluginSpec{ PluginDefinitionRef: greenhousev1alpha1.PluginDefinitionReference{ Name: "apache", Kind: greenhousev1alpha1.ClusterPluginDefinitionKind, @@ -56,7 +56,7 @@ var _ = Describe("validateCompatibility", func() { pluginPreset: &greenhousev1alpha1.PluginPreset{ TypeMeta: metav1.TypeMeta{Kind: PluginPresetKind}, Spec: greenhousev1alpha1.PluginPresetSpec{ - Plugin: greenhousev1alpha1.PluginSpec{ + Plugin: greenhousev1alpha1.PluginPresetPluginSpec{ PluginDefinitionRef: greenhousev1alpha1.PluginDefinitionReference{ Name: "nginx", Kind: greenhousev1alpha1.ClusterPluginDefinitionKind, @@ -92,7 +92,7 @@ var _ = Describe("validateCompatibility", func() { pluginPreset: &greenhousev1alpha1.PluginPreset{ TypeMeta: metav1.TypeMeta{Kind: PluginPresetKind}, Spec: greenhousev1alpha1.PluginPresetSpec{ - Plugin: greenhousev1alpha1.PluginSpec{ + Plugin: greenhousev1alpha1.PluginPresetPluginSpec{ PluginDefinitionRef: greenhousev1alpha1.PluginDefinitionReference{ Name: "nginx", Kind: greenhousev1alpha1.ClusterPluginDefinitionKind, @@ -142,7 +142,7 @@ var _ = Describe("prepareValues", func() { Namespace: "test-org", }, Spec: greenhousev1alpha1.PluginPresetSpec{ - Plugin: greenhousev1alpha1.PluginSpec{ + Plugin: greenhousev1alpha1.PluginPresetPluginSpec{ PluginDefinitionRef: greenhousev1alpha1.PluginDefinitionReference{ Name: "nginx", Kind: greenhousev1alpha1.ClusterPluginDefinitionKind, diff --git a/internal/controller/plugin/pluginpreset_controller.go b/internal/controller/plugin/pluginpreset_controller.go index b78058582..aab4f0406 100644 --- a/internal/controller/plugin/pluginpreset_controller.go +++ b/internal/controller/plugin/pluginpreset_controller.go @@ -238,12 +238,8 @@ func (r *PluginPresetReconciler) reconcilePluginPreset(ctx context.Context, pres releaseName := getReleaseName(plugin, preset) - plugin.Spec = preset.Spec.Plugin + plugin.Spec = pluginSpecFromPluginPreset(preset, cluster.GetName()) plugin.Spec.ReleaseName = releaseName - // Set the cluster name to the name of the cluster. The PluginSpec contained in the PluginPreset does not have a cluster name. - plugin.Spec.ClusterName = cluster.GetName() - // Copy over the plugin dependencies - plugin.Spec.WaitFor = preset.Spec.WaitFor // transport plugin preset labels to plugin plugin = (lifecycle.NewPropagator(preset, plugin).Apply()).(*greenhousev1alpha1.Plugin) // overrides options based on preset definition @@ -512,3 +508,20 @@ func isPluginDefinitionNotFoundError(err error) bool { } return false } + +// pluginSpecFromPluginPreset returns a PluginSpec based on the given PluginPreset.Spec.Plugin. +// This maps all fields that can be copied 1:1 from the PluginPreset's PluginSpec, the given cluster name and the PluginPreset's WaitFor +func pluginSpecFromPluginPreset(preset *greenhousev1alpha1.PluginPreset, cluster string) greenhousev1alpha1.PluginSpec { + return greenhousev1alpha1.PluginSpec{ + PluginDefinitionRef: preset.Spec.Plugin.PluginDefinitionRef, + DisplayName: preset.Spec.Plugin.DisplayName, + OptionValues: preset.Spec.Plugin.OptionValues, + ReleaseNamespace: preset.Spec.Plugin.ReleaseNamespace, + DeletionPolicy: preset.Spec.Plugin.DeletionPolicy, + IgnoreDifferences: preset.Spec.Plugin.IgnoreDifferences, + // Set the cluster name to the name of the cluster. The PluginSpec contained in the PluginPreset does not have a cluster name. + ClusterName: cluster, + // Copy over the plugin dependencies + WaitFor: preset.Spec.WaitFor, + } +} diff --git a/internal/controller/plugin/pluginpreset_controller_test.go b/internal/controller/plugin/pluginpreset_controller_test.go index 6091c108f..1cbaf0874 100644 --- a/internal/controller/plugin/pluginpreset_controller_test.go +++ b/internal/controller/plugin/pluginpreset_controller_test.go @@ -1041,7 +1041,7 @@ var _ = Describe("overridesPluginOptionValues", Ordered, func() { var _ = Describe("getReleaseName", func() { It("returns plugin.Spec.ReleaseName if set", func() { plugin := &greenhousev1alpha1.Plugin{Spec: greenhousev1alpha1.PluginSpec{ReleaseName: "explicit-release"}} - preset := &greenhousev1alpha1.PluginPreset{Spec: greenhousev1alpha1.PluginPresetSpec{Plugin: greenhousev1alpha1.PluginSpec{ReleaseName: "preset-release"}}} + preset := &greenhousev1alpha1.PluginPreset{Spec: greenhousev1alpha1.PluginPresetSpec{Plugin: greenhousev1alpha1.PluginPresetPluginSpec{ReleaseName: "preset-release"}}} Expect(getReleaseName(plugin, preset)).To(Equal("explicit-release")) }) @@ -1051,13 +1051,13 @@ var _ = Describe("getReleaseName", func() { Spec: greenhousev1alpha1.PluginSpec{ReleaseName: ""}, Status: greenhousev1alpha1.PluginStatus{HelmReleaseStatus: &greenhousev1alpha1.HelmReleaseStatus{}}, } - preset := &greenhousev1alpha1.PluginPreset{Spec: greenhousev1alpha1.PluginPresetSpec{Plugin: greenhousev1alpha1.PluginSpec{ReleaseName: "preset-release"}}} + preset := &greenhousev1alpha1.PluginPreset{Spec: greenhousev1alpha1.PluginPresetSpec{Plugin: greenhousev1alpha1.PluginPresetPluginSpec{ReleaseName: "preset-release"}}} Expect(getReleaseName(plugin, preset)).To(Equal("plugin-name")) }) It("returns preset.Spec.Plugin.ReleaseName if plugin.Spec.ReleaseName is empty and no HelmReleaseStatus", func() { plugin := &greenhousev1alpha1.Plugin{Spec: greenhousev1alpha1.PluginSpec{ReleaseName: ""}} - preset := &greenhousev1alpha1.PluginPreset{Spec: greenhousev1alpha1.PluginPresetSpec{Plugin: greenhousev1alpha1.PluginSpec{ReleaseName: "preset-release"}}} + preset := &greenhousev1alpha1.PluginPreset{Spec: greenhousev1alpha1.PluginPresetSpec{Plugin: greenhousev1alpha1.PluginPresetPluginSpec{ReleaseName: "preset-release"}}} Expect(getReleaseName(plugin, preset)).To(Equal("preset-release")) }) }) diff --git a/internal/test/resources.go b/internal/test/resources.go index 07b62c663..190eedd4b 100644 --- a/internal/test/resources.go +++ b/internal/test/resources.go @@ -479,7 +479,13 @@ func WithPluginPresetClusterSelector(clusterSelector metav1.LabelSelector) func( // WithPluginPresetPluginSpec sets the PluginSpec on a PluginPreset. func WithPluginPresetPluginSpec(pluginSpec greenhousev1alpha1.PluginSpec) func(*greenhousev1alpha1.PluginPreset) { return func(pp *greenhousev1alpha1.PluginPreset) { - pp.Spec.Plugin = pluginSpec + pp.Spec.Plugin.PluginDefinitionRef = pluginSpec.PluginDefinitionRef + pp.Spec.Plugin.DisplayName = pluginSpec.DisplayName + pp.Spec.Plugin.OptionValues = pluginSpec.OptionValues + pp.Spec.Plugin.ReleaseNamespace = pluginSpec.ReleaseNamespace + pp.Spec.Plugin.ReleaseName = pluginSpec.ReleaseName + pp.Spec.Plugin.DeletionPolicy = pluginSpec.DeletionPolicy + pp.Spec.Plugin.IgnoreDifferences = pluginSpec.IgnoreDifferences } } diff --git a/internal/webhook/v1alpha1/pluginpreset_webhook.go b/internal/webhook/v1alpha1/pluginpreset_webhook.go index bf6c97438..4d1ddc4ee 100644 --- a/internal/webhook/v1alpha1/pluginpreset_webhook.go +++ b/internal/webhook/v1alpha1/pluginpreset_webhook.go @@ -88,11 +88,6 @@ func ValidateCreatePluginPreset(ctx context.Context, c client.Client, pluginPres allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("clusterSelector"), pluginPreset.Spec.ClusterSelector, "ClusterSelector must be set")) } - // ensure ClusterName is not set - if pluginPreset.Spec.Plugin.ClusterName != "" { - allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("plugin").Child("clusterName"), pluginPreset.Spec.Plugin.ClusterName, "ClusterName must not be set")) - } - if err := validateReleaseName(pluginPreset.Spec.Plugin.ReleaseName); err != nil { allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("plugin").Child("releaseName"), pluginPreset.Spec.Plugin.ReleaseName, err.Error())) } @@ -117,10 +112,6 @@ func ValidateUpdatePluginPreset(ctx context.Context, c client.Client, oldPluginP allWarns = append(allWarns, "PluginPreset should have a support-group Team set as its owner", warn) } - if err := webhook.ValidateImmutableField(oldPluginPreset.Spec.Plugin.ClusterName, pluginPreset.Spec.Plugin.ClusterName, field.NewPath("spec", "plugin", "clusterName")); err != nil { - allErrs = append(allErrs, err) - } - // validate WaitFor items are unique and that PluginRef's fields are mutually exclusive if errList := validateWaitForPluginRefs(pluginPreset.Spec.WaitFor, false); len(errList) > 0 { allErrs = append(allErrs, errList...) diff --git a/internal/webhook/v1alpha1/pluginpreset_webhook_test.go b/internal/webhook/v1alpha1/pluginpreset_webhook_test.go index c18bcdc75..024169028 100644 --- a/internal/webhook/v1alpha1/pluginpreset_webhook_test.go +++ b/internal/webhook/v1alpha1/pluginpreset_webhook_test.go @@ -67,25 +67,6 @@ var _ = Describe("PluginPreset Admission Tests", Ordered, func() { Expect(err.Error()).To(ContainSubstring("PluginDefinition name must be set")) }) - It("should reject PluginPreset with a PluginSpec containing a ClusterName", func() { - cut := &greenhousev1alpha1.PluginPreset{ - ObjectMeta: metav1.ObjectMeta{ - Name: pluginPresetCreate, - Namespace: test.TestNamespace, - }, - Spec: greenhousev1alpha1.PluginPresetSpec{ - ClusterSelector: metav1.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}}, - Plugin: greenhousev1alpha1.PluginSpec{ - ClusterName: "cluster", - }, - }, - } - - err := test.K8sClient.Create(test.Ctx, cut) - Expect(err).To(HaveOccurred(), "there should be an error creating the PluginPreset with invalid fields") - Expect(err.Error()).To(ContainSubstring("ClusterName must not be set"), "the error message should reflect that plugin.clusterName should not be set") - }) - It("should reject PluginPreset without ClusterSelector", func() { cut := &greenhousev1alpha1.PluginPreset{ ObjectMeta: metav1.ObjectMeta{ @@ -93,7 +74,7 @@ var _ = Describe("PluginPreset Admission Tests", Ordered, func() { Namespace: test.TestNamespace, }, Spec: greenhousev1alpha1.PluginPresetSpec{ - Plugin: greenhousev1alpha1.PluginSpec{ + Plugin: greenhousev1alpha1.PluginPresetPluginSpec{ PluginDefinitionRef: greenhousev1alpha1.PluginDefinitionReference{ Name: pluginPresetClusterDefinition, Kind: greenhousev1alpha1.ClusterPluginDefinitionKind, @@ -116,7 +97,7 @@ var _ = Describe("PluginPreset Admission Tests", Ordered, func() { Labels: map[string]string{greenhouseapis.LabelKeyOwnedBy: teamWithSupportGroupName}, }, Spec: greenhousev1alpha1.PluginPresetSpec{ - Plugin: greenhousev1alpha1.PluginSpec{ + Plugin: greenhousev1alpha1.PluginPresetPluginSpec{ PluginDefinitionRef: greenhousev1alpha1.PluginDefinitionReference{ Name: "non-existing", Kind: greenhousev1alpha1.ClusterPluginDefinitionKind, @@ -140,7 +121,7 @@ var _ = Describe("PluginPreset Admission Tests", Ordered, func() { Labels: map[string]string{greenhouseapis.LabelKeyOwnedBy: teamWithSupportGroupName}, }, Spec: greenhousev1alpha1.PluginPresetSpec{ - Plugin: greenhousev1alpha1.PluginSpec{ + Plugin: greenhousev1alpha1.PluginPresetPluginSpec{ PluginDefinitionRef: greenhousev1alpha1.PluginDefinitionReference{ Name: "non-existing", Kind: greenhousev1alpha1.PluginDefinitionKind, @@ -247,15 +228,6 @@ var _ = Describe("PluginPreset Admission Tests", Ordered, func() { Expect(err). NotTo(HaveOccurred(), "there must be no error updating the PluginPreset pluginDefinition kind") - _, err = clientutil.CreateOrPatch(test.Ctx, test.K8sClient, cut, func() error { - cut.Spec.Plugin.ClusterName = "foo" - return nil - }) - Expect(err). - To(HaveOccurred(), "there must be an error updating the PluginPreset clusterName") - Expect(err.Error()). - To(ContainSubstring("field is immutable"), "the error must reflect the field is immutable") - test.EventuallyDeleted(test.Ctx, test.K8sClient, cut) }) @@ -270,7 +242,7 @@ var _ = Describe("PluginPreset Admission Tests", Ordered, func() { }, }, Spec: greenhousev1alpha1.PluginPresetSpec{ - Plugin: greenhousev1alpha1.PluginSpec{ + Plugin: greenhousev1alpha1.PluginPresetPluginSpec{ PluginDefinitionRef: greenhousev1alpha1.PluginDefinitionReference{ Name: pluginPresetClusterDefinition, Kind: greenhousev1alpha1.ClusterPluginDefinitionKind, @@ -307,7 +279,7 @@ var _ = Describe("Validate Plugin OptionValues for PluginPreset", func() { Namespace: test.TestNamespace, }, Spec: greenhousev1alpha1.PluginPresetSpec{ - Plugin: greenhousev1alpha1.PluginSpec{ + Plugin: greenhousev1alpha1.PluginPresetPluginSpec{ PluginDefinitionRef: greenhousev1alpha1.PluginDefinitionReference{ Name: "test", Kind: greenhousev1alpha1.ClusterPluginDefinitionKind, @@ -375,7 +347,7 @@ var _ = Describe("Validate Plugin OptionValues for PluginPreset", func() { Namespace: test.TestNamespace, }, Spec: greenhousev1alpha1.PluginPresetSpec{ - Plugin: greenhousev1alpha1.PluginSpec{ + Plugin: greenhousev1alpha1.PluginPresetPluginSpec{ PluginDefinitionRef: greenhousev1alpha1.PluginDefinitionReference{ Name: "test", Kind: greenhousev1alpha1.ClusterPluginDefinitionKind,