|
4 | 4 | "fmt" |
5 | 5 | "maps" |
6 | 6 | "os" |
| 7 | + "slices" |
| 8 | + "strings" |
7 | 9 | "unsafe" |
8 | 10 |
|
9 | 11 | appsv1 "k8s.io/api/apps/v1" |
@@ -119,19 +121,31 @@ func (r *Reconciler) getDeploymentObject(assetName string, esc *operatorv1alpha1 |
119 | 121 | switch assetName { |
120 | 122 | case controllerDeploymentAssetName: |
121 | 123 | 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 | + } |
122 | 127 | case webhookDeploymentAssetName: |
123 | 128 | checkInterval := "5m" |
124 | 129 | if esc.Spec.ApplicationConfig.WebhookConfig != nil && |
125 | 130 | esc.Spec.ApplicationConfig.WebhookConfig.CertificateCheckInterval != nil { |
126 | 131 | checkInterval = esc.Spec.ApplicationConfig.WebhookConfig.CertificateCheckInterval.Duration.String() |
127 | 132 | } |
128 | 133 | 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 | + } |
129 | 137 | updateWebhookVolumeConfig(deployment, esc) |
130 | 138 | case certControllerDeploymentAssetName: |
131 | 139 | 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 | + } |
132 | 143 | case bitwardenDeploymentAssetName: |
133 | 144 | deployment.Labels["app.kubernetes.io/version"] = os.Getenv(bitwardenImageVersionEnvVarName) |
134 | 145 | 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 | + } |
135 | 149 | updateBitwardenVolumeConfig(deployment, esc) |
136 | 150 | } |
137 | 151 |
|
@@ -749,3 +763,93 @@ func getComponentNameFromAsset(assetName string) (operatorv1alpha1.ComponentName |
749 | 763 | return "", "", fmt.Errorf("unknown deployment asset name: %s", assetName) |
750 | 764 | } |
751 | 765 | } |
| 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