diff --git a/doc/parameter.md b/doc/parameter.md index c5954c57b..44bbb32bb 100644 --- a/doc/parameter.md +++ b/doc/parameter.md @@ -40,6 +40,7 @@ Environment variables, are conventionally ALL_CAPS, and for our purposes | Helmfile Merge | LOVELY_HELMFILE_MERGE | Set to some yaml you'd like [strategic merged](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/patchesstrategicmerge/) into any helmfile.yaml used by helmfile. | | | Helmfile Patch | LOVELY_HELMFILE_PATCH | to some yaml or json you'd like [json6902](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/patchesjson6902/) patched into any helmfile.yaml used by Helmfile. | | | Helmfile Template Parameters | LOVELY_HELMFILE_TEMPLATE_PARAMS | Space separated extra parameters to `Helmfile template` as you might use on the command line. You're on your own here if you pass rubbish parameters. | | +| Environment variables propagation | LOVELY_ENV_PROPAGATION | Whether to propagate and map ARGOCD_ENV_{VARIABLE} environment variables as {VARIABLE} to the downstream processor (Helm, Kustomize or Helmfile). | false | ## Plugin Name You can set `PLUGIN_NAME` in the environment of the sidecar to override the default name of the plugin. This allows you to supply multiple pre-configured plugins (with different environment, but the same variation). diff --git a/pkg/features/features.go b/pkg/features/features.go index 8869dceea..430897687 100644 --- a/pkg/features/features.go +++ b/pkg/features/features.go @@ -36,8 +36,9 @@ const ( HelmfileMerge HelmfilePatch HelmfileTemplateParams + EnvPropagation FirstFeature = Plugins - LastFeature = HelmfileTemplateParams + LastFeature = EnvPropagation ) // Feature is an individual configurable element of the plugin @@ -179,5 +180,11 @@ func Features() map[FeatureID]Feature { Name: `lovely_helmfile_template_params`, Description: "Space separated extra parameters to `Helmfile template` as you might use on the command line. You're on your own here if you pass rubbish parameters.", }, + EnvPropagation: { + Title: `Environment variables propagation`, + Name: `lovely_env_propagation`, + DefaultVal: `false`, + Description: "Whether to propagate and map ARGOCD_ENV_{VARIABLE} environment variables as {VARIABLE} to the downstream processor (Helm, Kustomize or Helmfile).", + }, } } diff --git a/pkg/features/getters.go b/pkg/features/getters.go index 1cf9add20..a6dfb69f4 100644 --- a/pkg/features/getters.go +++ b/pkg/features/getters.go @@ -172,3 +172,10 @@ func GetHelmfileTemplateParams() ([]string, error) { f := Features()[HelmfileTemplateParams] return config.GetStringListParam(f.EnvName(), f.DefaultVal, ' ') } + +// GetEnvPropagation returns extra parameters to pass to processor stage +// Set LOVELY_ENV_PROPAGATION to activate env propagation +func GetEnvPropagation() bool { + f := Features()[EnvPropagation] + return config.GetBoolParam(f.EnvName(), f.DefaultVal) +} diff --git a/pkg/processor/execute.go b/pkg/processor/execute.go index 6c7e78ea6..bc6d5d498 100644 --- a/pkg/processor/execute.go +++ b/pkg/processor/execute.go @@ -3,12 +3,24 @@ package processor import ( "bytes" "fmt" + "github.com/crumbhole/argocd-lovely-plugin/pkg/features" + "os" "os/exec" + "regexp" +) + +const ( + envPrefixArgoCD = "ARGOCD_ENV_" ) func execute(path string, command string, params ...string) (string, error) { cmd := exec.Command(command, params...) cmd.Dir = path + + if features.GetEnvPropagation() { + cmd.Env = filterEnvironment(os.Environ()) + } + var stderr bytes.Buffer cmd.Stderr = &stderr out, err := cmd.Output() @@ -18,3 +30,15 @@ func execute(path string, command string, params ...string) (string, error) { } return string(out), nil } + +func filterEnvironment(env []string) []string { + filtered := make([]string, 0, len(env)) + argoRegex := regexp.MustCompile(`^` + regexp.QuoteMeta(envPrefixArgoCD)) + for _, e := range env { + if argoRegex.MatchString(e) { + e = argoRegex.ReplaceAllString(e, "") + } + filtered = append(filtered, e) + } + return filtered +} diff --git a/test/helmfile_env_propagation/README.md b/test/helmfile_env_propagation/README.md new file mode 100644 index 000000000..5e0bac1a1 --- /dev/null +++ b/test/helmfile_env_propagation/README.md @@ -0,0 +1,2 @@ +This example: +- Installs the helm chart defined in `helmfile.yaml` using helmfile using env propagation to substitute the replicaCount from a provided env var. diff --git a/test/helmfile_env_propagation/env.txt b/test/helmfile_env_propagation/env.txt new file mode 100644 index 000000000..0db487ecc --- /dev/null +++ b/test/helmfile_env_propagation/env.txt @@ -0,0 +1,2 @@ +LOVELY_ENV_PROPAGATION: true +ARGOCD_ENV_REPLICA_COUNT: 2 \ No newline at end of file diff --git a/test/helmfile_env_propagation/expected.txt b/test/helmfile_env_propagation/expected.txt new file mode 100644 index 000000000..1151b8753 --- /dev/null +++ b/test/helmfile_env_propagation/expected.txt @@ -0,0 +1,76 @@ +--- +# Source: hello-world/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: test-hello-world + labels: + helm.sh/chart: hello-world-0.1.0 + app.kubernetes.io/name: hello-world + app.kubernetes.io/instance: test + app.kubernetes.io/version: "1.16.0" + app.kubernetes.io/managed-by: Helm +--- +# Source: hello-world/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: test-hello-world + labels: + helm.sh/chart: hello-world-0.1.0 + app.kubernetes.io/name: hello-world + app.kubernetes.io/instance: test + app.kubernetes.io/version: "1.16.0" + app.kubernetes.io/managed-by: Helm +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app.kubernetes.io/name: hello-world + app.kubernetes.io/instance: test +--- +# Source: hello-world/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: test-hello-world + labels: + helm.sh/chart: hello-world-0.1.0 + app.kubernetes.io/name: hello-world + app.kubernetes.io/instance: test + app.kubernetes.io/version: "1.16.0" + app.kubernetes.io/managed-by: Helm +spec: + replicas: 2 + selector: + matchLabels: + app.kubernetes.io/name: hello-world + app.kubernetes.io/instance: test + template: + metadata: + labels: + app.kubernetes.io/name: hello-world + app.kubernetes.io/instance: test + spec: + serviceAccountName: test-hello-world + containers: + - name: hello-world + image: "nginx:1.16.0" + imagePullPolicy: IfNotPresent + ports: + - name: http + containerPort: 80 + protocol: TCP + livenessProbe: + httpGet: + path: / + port: http + readinessProbe: + httpGet: + path: / + port: http + diff --git a/test/helmfile_env_propagation/helmfile.yaml b/test/helmfile_env_propagation/helmfile.yaml new file mode 100644 index 000000000..d015fc3b7 --- /dev/null +++ b/test/helmfile_env_propagation/helmfile.yaml @@ -0,0 +1,11 @@ +repositories: + - name: examples + url: https://helm.github.io/examples + +releases: + - name: test + namespace: default + chart: examples/hello-world + set: + - name: replicaCount + value: {{ requiredEnv "REPLICA_COUNT" }}