Skip to content

Commit 5e363ea

Browse files
committed
ESO-566: Allow overriding operand container args outside the ExternalSecretsConfig API
Signed-off-by: Bharath B <bhb@redhat.com>
1 parent c38c005 commit 5e363ea

8 files changed

Lines changed: 1152 additions & 0 deletions

File tree

‎pkg/controller/external_secrets/constants.go‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,26 @@ const (
8181
webhookContainerName = "webhook"
8282
certControllerContainerName = "cert-controller"
8383
bitwardenContainerName = "bitwarden-sdk-server"
84+
85+
// Operand deployment / container names used by e2e and env-based arg overrides.
86+
OperandCoreControllerDeployment = externalsecretsCommonName
87+
OperandWebhookDeployment = externalsecretsCommonName + "-webhook"
88+
OperandCertControllerDeployment = externalsecretsCommonName + "-cert-controller"
89+
OperandBitwardenSDKServerDeployment = "bitwarden-sdk-server"
90+
91+
OperandCoreControllerContainer = controllerContainerName
92+
OperandWebhookContainer = webhookContainerName
93+
OperandCertControllerContainer = certControllerContainerName
94+
OperandBitwardenContainer = bitwardenContainerName
95+
96+
// OperandExternalSecretsArgsEnvVar is the operator env var for core controller container args overrides.
97+
OperandExternalSecretsArgsEnvVar = "OPERAND_EXTERNAL_SECRETS_ARGS"
98+
// OperandWebhookArgsEnvVar is the operator env var for webhook container args overrides.
99+
OperandWebhookArgsEnvVar = "OPERAND_WEBHOOK_ARGS"
100+
// OperandCertControllerArgsEnvVar is the operator env var for cert-controller container args overrides.
101+
OperandCertControllerArgsEnvVar = "OPERAND_CERT_CONTROLLER_ARGS"
102+
// OperandBitwardenSDKServerArgsEnvVar is the operator env var for bitwarden-sdk-server container args overrides.
103+
OperandBitwardenSDKServerArgsEnvVar = "OPERAND_BITWARDEN_SDK_SERVER_ARGS"
84104
)
85105

86106
var (

‎pkg/controller/external_secrets/deployments.go‎

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"fmt"
55
"maps"
66
"os"
7+
"slices"
8+
"strings"
79
"unsafe"
810

911
appsv1 "k8s.io/api/apps/v1"
@@ -119,19 +121,31 @@ func (r *Reconciler) getDeploymentObject(assetName string, esc *operatorv1alpha1
119121
switch assetName {
120122
case controllerDeploymentAssetName:
121123
updateContainerSpec(deployment, esc, image, logLevel)
124+
if err := applyOperandArgsFromEnv(deployment, OperandCoreControllerContainer, OperandExternalSecretsArgsEnvVar); err != nil {
125+
return nil, fmt.Errorf("failed to apply operand args from env: %w", err)
126+
}
122127
case webhookDeploymentAssetName:
123128
checkInterval := "5m"
124129
if esc.Spec.ApplicationConfig.WebhookConfig != nil &&
125130
esc.Spec.ApplicationConfig.WebhookConfig.CertificateCheckInterval != nil {
126131
checkInterval = esc.Spec.ApplicationConfig.WebhookConfig.CertificateCheckInterval.Duration.String()
127132
}
128133
updateWebhookContainerSpec(deployment, image, logLevel, checkInterval)
134+
if err := applyOperandArgsFromEnv(deployment, OperandWebhookContainer, OperandWebhookArgsEnvVar); err != nil {
135+
return nil, fmt.Errorf("failed to apply operand args from env: %w", err)
136+
}
129137
updateWebhookVolumeConfig(deployment, esc)
130138
case certControllerDeploymentAssetName:
131139
updateCertControllerContainerSpec(deployment, image, logLevel)
140+
if err := applyOperandArgsFromEnv(deployment, OperandCertControllerContainer, OperandCertControllerArgsEnvVar); err != nil {
141+
return nil, fmt.Errorf("failed to apply operand args from env: %w", err)
142+
}
132143
case bitwardenDeploymentAssetName:
133144
deployment.Labels["app.kubernetes.io/version"] = os.Getenv(bitwardenImageVersionEnvVarName)
134145
updateBitwardenServerContainerSpec(deployment, bitwardenImage)
146+
if err := applyOperandArgsFromEnv(deployment, OperandBitwardenContainer, OperandBitwardenSDKServerArgsEnvVar); err != nil {
147+
return nil, fmt.Errorf("failed to apply operand args from env: %w", err)
148+
}
135149
updateBitwardenVolumeConfig(deployment, esc)
136150
}
137151

@@ -749,3 +763,93 @@ func getComponentNameFromAsset(assetName string) (operatorv1alpha1.ComponentName
749763
return "", "", fmt.Errorf("unknown deployment asset name: %s", assetName)
750764
}
751765
}
766+
767+
// argFlagKey returns the flag key for a container arg (everything before the first '='),
768+
// or the whole token when there is no '='. Positional args without a leading "--" return "".
769+
func argFlagKey(arg string) string {
770+
if !strings.HasPrefix(arg, "--") {
771+
return ""
772+
}
773+
if i := strings.IndexByte(arg, '='); i >= 0 {
774+
return arg[:i]
775+
}
776+
return arg
777+
}
778+
779+
// parseOperandArgsEnv parses a comma-separated list of full CLI flags
780+
// (e.g. "--concurrent=5,--loglevel=debug"). Empty segments (from trailing or
781+
// repeated commas) are skipped. Callers should treat a fully empty/whitespace
782+
// env value as a no-op before calling this helper.
783+
func parseOperandArgsEnv(raw string) ([]string, error) {
784+
parts := strings.Split(raw, ",")
785+
args := make([]string, 0, len(parts))
786+
for _, part := range parts {
787+
part = strings.TrimSpace(part)
788+
if part == "" {
789+
continue
790+
}
791+
if !strings.HasPrefix(part, "--") {
792+
return nil, common.NewIrrecoverableError(
793+
fmt.Errorf("argument %q must start with --", part),
794+
"invalid custom arg override",
795+
)
796+
}
797+
args = append(args, part)
798+
}
799+
return args, nil
800+
}
801+
802+
// mergeContainerArgs overrides matching --flag keys in base with overrides and appends
803+
// unknown keys. Positional args (no leading "--") in base are preserved in place;
804+
// non-flag overrides are skipped (parseOperandArgsEnv already rejects them for the env path).
805+
func mergeContainerArgs(base []string, overrides []string) []string {
806+
if len(overrides) == 0 {
807+
return base
808+
}
809+
810+
keyIndex := make(map[string]int, len(base))
811+
for i, arg := range base {
812+
if key := argFlagKey(arg); key != "" {
813+
keyIndex[key] = i
814+
}
815+
}
816+
817+
result := slices.Clone(base)
818+
for _, override := range overrides {
819+
key := argFlagKey(override)
820+
if key == "" {
821+
continue
822+
}
823+
if idx, ok := keyIndex[key]; ok {
824+
result[idx] = override
825+
continue
826+
}
827+
result = append(result, override)
828+
keyIndex[key] = len(result) - 1
829+
}
830+
return result
831+
}
832+
833+
// applyOperandArgsFromEnv reads envVarName and merges its comma-separated --key=value
834+
// flags into the named container's Args. Unset or empty env is a no-op.
835+
func applyOperandArgsFromEnv(deployment *appsv1.Deployment, containerName, envVarName string) error {
836+
raw := strings.TrimSpace(os.Getenv(envVarName))
837+
if raw == "" {
838+
return nil
839+
}
840+
841+
overrides, err := parseOperandArgsEnv(raw)
842+
if err != nil {
843+
return fmt.Errorf("%s: %w", envVarName, err)
844+
}
845+
846+
for i := range deployment.Spec.Template.Spec.Containers {
847+
if deployment.Spec.Template.Spec.Containers[i].Name != containerName {
848+
continue
849+
}
850+
deployment.Spec.Template.Spec.Containers[i].Args = mergeContainerArgs(
851+
deployment.Spec.Template.Spec.Containers[i].Args, overrides)
852+
return nil
853+
}
854+
return fmt.Errorf("container %s not found in deployment %s", containerName, deployment.GetName())
855+
}

0 commit comments

Comments
 (0)