diff --git a/api/v1alpha1/external_secrets_config_types.go b/api/v1alpha1/external_secrets_config_types.go index ccac0512f..1904d3938 100644 --- a/api/v1alpha1/external_secrets_config_types.go +++ b/api/v1alpha1/external_secrets_config_types.go @@ -4,6 +4,7 @@ import ( corev1 "k8s.io/api/core/v1" networkingv1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" ) func init() { @@ -191,6 +192,16 @@ type ComponentConfig struct { // +listMapKey=name // +optional OverrideEnv []corev1.EnvVar `json:"overrideEnv,omitempty"` + + // advancedOverrides applies raw patches on top of the final operator generated Deployment spec. + // WARNING: DO NOT USE UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING. + // This field can overwrite your own first-class CRD settings. You must NOT use this + // field to add or modify containers, initContainers, or ports, as doing so breaks + // the structural integrity of the operand and will fail deployment reconciliation. + // Only the allowlisted paths are applied. + // +kubebuilder:validation:Optional + // +kubebuilder:pruning:PreserveUnknownFields + AdvancedOverrides *runtime.RawExtension `json:"advancedOverrides,omitempty"` } // DeploymentConfig defines configuration overrides for a Kubernetes Deployment resource. @@ -204,6 +215,14 @@ type DeploymentConfig struct { // +kubebuilder:validation:Maximum=50 // +optional RevisionHistoryLimit *int32 `json:"revisionHistoryLimit,omitempty"` + + // replicas sets the desired replica count for this component's Deployment. + // When omitted, defaults to 1. For ExternalSecretsCoreController, replicas > 1 enables --enable-leader-election. + // +kubebuilder:default:=1 + // +kubebuilder:validation:Minimum:=1 + // +kubebuilder:validation:Maximum:=10 + // +optional + Replicas *int32 `json:"replicas,omitempty"` } // BitwardenSecretManagerProvider is for enabling the bitwarden secrets manager provider and for setting up the additional service required for connecting with the bitwarden server. diff --git a/api/v1alpha1/tests/externalsecretsconfig.operator.openshift.io/externalsecretsconfig.testsuite.yaml b/api/v1alpha1/tests/externalsecretsconfig.operator.openshift.io/externalsecretsconfig.testsuite.yaml index b922d6a07..99764234e 100644 --- a/api/v1alpha1/tests/externalsecretsconfig.operator.openshift.io/externalsecretsconfig.testsuite.yaml +++ b/api/v1alpha1/tests/externalsecretsconfig.operator.openshift.io/externalsecretsconfig.testsuite.yaml @@ -1385,6 +1385,90 @@ tests: overrideEnv: - name: SHARED_VAR value: "webhook-value" + - name: Should allow replicas within valid bounds + resourceName: cluster + initial: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ExternalSecretsConfig + spec: + controllerConfig: + replicas: 2 + expected: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ExternalSecretsConfig + spec: + controllerConfig: + replicas: 2 + - name: Should allow replicas at maximum of 10 + resourceName: cluster + initial: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ExternalSecretsConfig + spec: + controllerConfig: + replicas: 10 + expected: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ExternalSecretsConfig + spec: + controllerConfig: + replicas: 10 + - name: Should fail with replicas less than 1 + resourceName: cluster + initial: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ExternalSecretsConfig + spec: + controllerConfig: + replicas: 0 + expectedError: "ExternalSecretsConfig.operator.openshift.io \"cluster\" is invalid: spec.controllerConfig.replicas: Invalid value: 0: spec.controllerConfig.replicas in body should be greater than or equal to 1" + - name: Should fail with replicas exceeding maximum of 10 + resourceName: cluster + initial: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ExternalSecretsConfig + spec: + controllerConfig: + replicas: 11 + expectedError: "ExternalSecretsConfig.operator.openshift.io \"cluster\" is invalid: spec.controllerConfig.replicas: Invalid value: 11: spec.controllerConfig.replicas in body should be less than or equal to 10" + - name: Should allow advancedOverrides on a componentConfig + resourceName: cluster + initial: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ExternalSecretsConfig + spec: + controllerConfig: + replicas: 2 + componentConfigs: + - componentName: ExternalSecretsCoreController + advancedOverrides: + template: + spec: + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: + app.kubernetes.io/name: external-secrets + topologyKey: kubernetes.io/hostname + expected: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ExternalSecretsConfig + spec: + controllerConfig: + replicas: 2 + componentConfigs: + - componentName: ExternalSecretsCoreController + advancedOverrides: + template: + spec: + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: + app.kubernetes.io/name: external-secrets + topologyKey: kubernetes.io/hostname - name: Should allow networkPolicy with valid componentName ExternalSecretsCoreController resourceName: cluster initial: | diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 3743fc256..1c7e10fb9 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -24,7 +24,7 @@ import ( "k8s.io/api/core/v1" networkingv1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. @@ -177,6 +177,11 @@ func (in *ComponentConfig) DeepCopyInto(out *ComponentConfig) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.AdvancedOverrides != nil { + in, out := &in.AdvancedOverrides, &out.AdvancedOverrides + *out = new(runtime.RawExtension) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ComponentConfig. @@ -322,6 +327,11 @@ func (in *DeploymentConfig) DeepCopyInto(out *DeploymentConfig) { *out = new(int32) **out = **in } + if in.Replicas != nil { + in, out := &in.Replicas, &out.Replicas + *out = new(int32) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentConfig. diff --git a/bundle/manifests/operator.openshift.io_externalsecretsconfigs.yaml b/bundle/manifests/operator.openshift.io_externalsecretsconfigs.yaml index 699f85bfc..5969ad7fc 100644 --- a/bundle/manifests/operator.openshift.io_externalsecretsconfigs.yaml +++ b/bundle/manifests/operator.openshift.io_externalsecretsconfigs.yaml @@ -1304,6 +1304,16 @@ spec: description: ComponentConfig defines configuration overrides for a specific external-secrets component. properties: + advancedOverrides: + description: |- + advancedOverrides applies raw patches on top of the final operator generated Deployment spec. + WARNING: DO NOT USE UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING. + This field can overwrite your own first-class CRD settings. You must NOT use this + field to add or modify containers, initContainers, or ports, as doing so breaks + the structural integrity of the operand and will fail deployment reconciliation. + Only the allowlisted paths are applied. + type: object + x-kubernetes-preserve-unknown-fields: true componentName: description: |- componentName identifies which external-secrets component this configuration applies to. @@ -1318,6 +1328,15 @@ spec: description: deploymentConfigs specifies overrides for the Kubernetes Deployment resource of this component. properties: + replicas: + default: 1 + description: |- + replicas sets the desired replica count for this component's Deployment. + When omitted, defaults to 1. For ExternalSecretsCoreController, replicas > 1 enables --enable-leader-election. + format: int32 + maximum: 10 + minimum: 1 + type: integer revisionHistoryLimit: default: 10 description: |- diff --git a/config/crd/bases/operator.openshift.io_externalsecretsconfigs.yaml b/config/crd/bases/operator.openshift.io_externalsecretsconfigs.yaml index 4dcfb2135..2c0657ea7 100644 --- a/config/crd/bases/operator.openshift.io_externalsecretsconfigs.yaml +++ b/config/crd/bases/operator.openshift.io_externalsecretsconfigs.yaml @@ -1304,6 +1304,16 @@ spec: description: ComponentConfig defines configuration overrides for a specific external-secrets component. properties: + advancedOverrides: + description: |- + advancedOverrides applies raw patches on top of the final operator generated Deployment spec. + WARNING: DO NOT USE UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING. + This field can overwrite your own first-class CRD settings. You must NOT use this + field to add or modify containers, initContainers, or ports, as doing so breaks + the structural integrity of the operand and will fail deployment reconciliation. + Only the allowlisted paths are applied. + type: object + x-kubernetes-preserve-unknown-fields: true componentName: description: |- componentName identifies which external-secrets component this configuration applies to. @@ -1318,6 +1328,15 @@ spec: description: deploymentConfigs specifies overrides for the Kubernetes Deployment resource of this component. properties: + replicas: + default: 1 + description: |- + replicas sets the desired replica count for this component's Deployment. + When omitted, defaults to 1. For ExternalSecretsCoreController, replicas > 1 enables --enable-leader-election. + format: int32 + maximum: 10 + minimum: 1 + type: integer revisionHistoryLimit: default: 10 description: |- diff --git a/docs/api_reference.md b/docs/api_reference.md index a9851a1b6..684d7a788 100644 --- a/docs/api_reference.md +++ b/docs/api_reference.md @@ -130,6 +130,7 @@ _Appears in:_ | `componentName` _[ComponentName](#componentname)_ | componentName identifies which external-secrets component this configuration applies to.
Valid component names: ExternalSecretsCoreController, Webhook, CertController, BitwardenSDKServer. | | Enum: [ExternalSecretsCoreController Webhook CertController BitwardenSDKServer]
| | `deploymentConfigs` _[DeploymentConfig](#deploymentconfig)_ | deploymentConfigs specifies overrides for the Kubernetes Deployment resource of this component. | | | | `overrideEnv` _[EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#envvar-v1-core) array_ | overrideEnv specifies custom environment variables for this component's container. These are merged with operator-managed environment variables, with user-defined values taking precedence.
Names starting with 'KUBERNETES_' or 'EXTERNAL_SECRETS_' are reserved prefixes and will be rejected.
The exact names 'HOSTNAME', 'SSL_CERT_DIR', and 'SSL_CERT_FILE' are also reserved. | | MaxItems: 50
| +| `advancedOverrides` _[RawExtension](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#rawextension-runtime-pkg)_ | advancedOverrides applies raw patches on top of the final operator generated Deployment spec.
WARNING: DO NOT USE UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING.
This field can overwrite your own first-class CRD settings. You must NOT use this
field to add or modify containers, initContainers, or ports, as doing so breaks
the structural integrity of the operand and will fail deployment reconciliation.
Only the allowlisted paths are applied. | | Optional: \{\}
| #### ComponentName @@ -256,6 +257,7 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | | `revisionHistoryLimit` _integer_ | revisionHistoryLimit specifies the number of old ReplicaSets to retain for rollback purposes.
This allows rolling back to previous deployment versions using 'kubectl rollout undo'.
Must be at least 1 to ensure rollback capability. Maximum value is 50 to limit resource usage.
If not specified, defaults to 10. | 10 | Maximum: 50
Minimum: 1
| +| `replicas` _integer_ | replicas sets the desired replica count for this component's Deployment.
When omitted, defaults to 1. For ExternalSecretsCoreController, replicas > 1 enables --enable-leader-election. | 1 | Maximum: 10
Minimum: 1
| #### ExternalSecretsConfig