mirror of
https://github.com/fluxcd/flux2.git
synced 2026-05-23 01:45:53 +00:00
feat: add --k8s-aware support to envsubst
This routes the envsubst changes to go through to a new `kustomize.SubstituteEnvVariables` to the pkgs `kustomize` module which supports the `kustomize.toolkit.fluxcd.io/substitute` annotation. Requires https://github.com/fluxcd/pkg/pull/1176 Fixes https://github.com/fluxcd/flux2/issues/5108 Signed-off-by: Jaakko Sirén <jaakko@craci.com>
This commit is contained in:
parent
7d27a26665
commit
61ce5edde5
8 changed files with 235 additions and 18 deletions
|
|
@ -17,10 +17,12 @@ limitations under the License.
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/fluxcd/pkg/envsubst"
|
||||
"github.com/fluxcd/pkg/kustomize"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
|
@ -37,12 +39,16 @@ to replicate the behavior of the Flux Kustomization post-build substitutions.`),
|
|||
|
||||
# Run env var substitutions and error out if a variable is not set
|
||||
kustomize build . | flux envsubst --strict
|
||||
|
||||
# Run env var substitutions, skipping resources with substitute disabled
|
||||
kustomize build . | flux envsubst --strict --k8s-aware
|
||||
`,
|
||||
RunE: runEnvsubstCmd,
|
||||
}
|
||||
|
||||
type envsubstFlags struct {
|
||||
strict bool
|
||||
strict bool
|
||||
k8sAware bool
|
||||
}
|
||||
|
||||
var envsubstArgs envsubstFlags
|
||||
|
|
@ -50,25 +56,33 @@ var envsubstArgs envsubstFlags
|
|||
func init() {
|
||||
envsubstCmd.Flags().BoolVar(&envsubstArgs.strict, "strict", false,
|
||||
"fail if a variable without a default value is declared in the input but is missing from the environment")
|
||||
envsubstCmd.Flags().BoolVar(&envsubstArgs.k8sAware, "k8s-aware", false,
|
||||
"treat the input as multi-doc Kubernetes YAML and skip substitution for resources "+
|
||||
"annotated or labeled with kustomize.toolkit.fluxcd.io/substitute: disabled")
|
||||
rootCmd.AddCommand(envsubstCmd)
|
||||
}
|
||||
|
||||
func runEnvsubstCmd(cmd *cobra.Command, args []string) error {
|
||||
stdin := bufio.NewScanner(rootCmd.InOrStdin())
|
||||
stdout := bufio.NewWriter(rootCmd.OutOrStdout())
|
||||
for stdin.Scan() {
|
||||
line, err := envsubst.EvalEnv(stdin.Text(), envsubstArgs.strict)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = fmt.Fprintln(stdout, line)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = stdout.Flush()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := io.ReadAll(rootCmd.InOrStdin())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
mapping := envsubst.Getenv
|
||||
if envsubstArgs.strict {
|
||||
mapping = os.LookupEnv
|
||||
}
|
||||
|
||||
var result string
|
||||
if envsubstArgs.k8sAware {
|
||||
result, err = kustomize.SubstituteEnvVariables(string(data), mapping)
|
||||
} else {
|
||||
result, err = envsubst.Eval(string(data), mapping)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = fmt.Fprint(rootCmd.OutOrStdout(), result)
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,3 +48,80 @@ func TestEnvsubst_Strinct(t *testing.T) {
|
|||
g.Expect(err).To(HaveOccurred())
|
||||
g.Expect(err.Error()).To(ContainSubstring("variable not set (strict mode)"))
|
||||
}
|
||||
|
||||
func TestEnvsubst_K8sAware(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args string
|
||||
env map[string]string
|
||||
input string
|
||||
gold string
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "annotation disabled",
|
||||
args: "envsubst --k8s-aware",
|
||||
env: map[string]string{"REPO_NAME": "test"},
|
||||
input: "testdata/envsubst/k8s-aware.yaml",
|
||||
gold: "testdata/envsubst/k8s-aware.gold",
|
||||
},
|
||||
{
|
||||
name: "label disabled",
|
||||
args: "envsubst --k8s-aware",
|
||||
input: "testdata/envsubst/k8s-aware-label.yaml",
|
||||
gold: "testdata/envsubst/k8s-aware-label.gold",
|
||||
},
|
||||
{
|
||||
name: "strict skips disabled resources",
|
||||
args: "envsubst --strict --k8s-aware",
|
||||
env: map[string]string{"REPO_NAME": "test"},
|
||||
input: "testdata/envsubst/k8s-aware.yaml",
|
||||
gold: "testdata/envsubst/k8s-aware.gold",
|
||||
},
|
||||
{
|
||||
name: "strict errors on enabled resource with missing var",
|
||||
args: "envsubst --strict --k8s-aware",
|
||||
input: "testdata/envsubst/k8s-aware.yaml",
|
||||
wantErr: "variable not set (strict mode)",
|
||||
},
|
||||
{
|
||||
name: "bash script in disabled resource",
|
||||
args: "envsubst --k8s-aware",
|
||||
env: map[string]string{"APP_NAME": "myapp"},
|
||||
input: "testdata/envsubst/k8s-aware-bash.yaml",
|
||||
gold: "testdata/envsubst/k8s-aware-bash.gold",
|
||||
},
|
||||
{
|
||||
name: "strict with bash script in disabled resource",
|
||||
args: "envsubst --strict --k8s-aware",
|
||||
env: map[string]string{"APP_NAME": "myapp"},
|
||||
input: "testdata/envsubst/k8s-aware-bash.yaml",
|
||||
gold: "testdata/envsubst/k8s-aware-bash.gold",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
for k, v := range tt.env {
|
||||
t.Setenv(k, v)
|
||||
}
|
||||
|
||||
input, err := os.ReadFile(tt.input)
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
output, err := executeCommandWithIn(tt.args, bytes.NewReader(input))
|
||||
if tt.wantErr != "" {
|
||||
g.Expect(err).To(HaveOccurred())
|
||||
g.Expect(err.Error()).To(ContainSubstring(tt.wantErr))
|
||||
return
|
||||
}
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
expected, err := os.ReadFile(tt.gold)
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
g.Expect(output).To(Equal(string(expected)))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
29
cmd/flux/testdata/envsubst/k8s-aware-bash.gold
vendored
Normal file
29
cmd/flux/testdata/envsubst/k8s-aware-bash.gold
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: myapp
|
||||
namespace: default
|
||||
data:
|
||||
key: value
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: init-scripts
|
||||
namespace: default
|
||||
annotations:
|
||||
kustomize.toolkit.fluxcd.io/substitute: disabled
|
||||
data:
|
||||
setup.sh: |
|
||||
#!/bin/bash
|
||||
process_args() {
|
||||
echo "First arg: $1"
|
||||
echo "Second arg: $2"
|
||||
echo "All args: $@"
|
||||
local name=${1:-default}
|
||||
local count=${2:-0}
|
||||
for i in $(seq 1 $count); do
|
||||
echo "$i: processing $name"
|
||||
done
|
||||
}
|
||||
process_args "$@"
|
||||
29
cmd/flux/testdata/envsubst/k8s-aware-bash.yaml
vendored
Normal file
29
cmd/flux/testdata/envsubst/k8s-aware-bash.yaml
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: ${APP_NAME}
|
||||
namespace: ${APP_NAMESPACE:=default}
|
||||
data:
|
||||
key: value
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: init-scripts
|
||||
namespace: default
|
||||
annotations:
|
||||
kustomize.toolkit.fluxcd.io/substitute: disabled
|
||||
data:
|
||||
setup.sh: |
|
||||
#!/bin/bash
|
||||
process_args() {
|
||||
echo "First arg: $1"
|
||||
echo "Second arg: $2"
|
||||
echo "All args: $@"
|
||||
local name=${1:-default}
|
||||
local count=${2:-0}
|
||||
for i in $(seq 1 $count); do
|
||||
echo "$i: processing $name"
|
||||
done
|
||||
}
|
||||
process_args "$@"
|
||||
9
cmd/flux/testdata/envsubst/k8s-aware-label.gold
vendored
Normal file
9
cmd/flux/testdata/envsubst/k8s-aware-label.gold
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: grafana-dashboard
|
||||
namespace: monitoring
|
||||
labels:
|
||||
kustomize.toolkit.fluxcd.io/substitute: disabled
|
||||
data:
|
||||
dashboard.json: '{"panels": [{"datasource": "${DataSource}"}]}'
|
||||
9
cmd/flux/testdata/envsubst/k8s-aware-label.yaml
vendored
Normal file
9
cmd/flux/testdata/envsubst/k8s-aware-label.yaml
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: grafana-dashboard
|
||||
namespace: monitoring
|
||||
labels:
|
||||
kustomize.toolkit.fluxcd.io/substitute: disabled
|
||||
data:
|
||||
dashboard.json: '{"panels": [{"datasource": "${DataSource}"}]}'
|
||||
25
cmd/flux/testdata/envsubst/k8s-aware.gold
vendored
Normal file
25
cmd/flux/testdata/envsubst/k8s-aware.gold
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: test
|
||||
namespace: flux-system
|
||||
data:
|
||||
key: value
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: grafana-dashboard
|
||||
namespace: monitoring
|
||||
annotations:
|
||||
kustomize.toolkit.fluxcd.io/substitute: disabled
|
||||
data:
|
||||
dashboard.json: '{"panels": [{"datasource": "${DataSource}"}]}'
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: test-config
|
||||
namespace: flux-system
|
||||
data:
|
||||
region: eu-central-1
|
||||
25
cmd/flux/testdata/envsubst/k8s-aware.yaml
vendored
Normal file
25
cmd/flux/testdata/envsubst/k8s-aware.yaml
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: ${REPO_NAME}
|
||||
namespace: ${REPO_NAMESPACE:=flux-system}
|
||||
data:
|
||||
key: value
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: grafana-dashboard
|
||||
namespace: monitoring
|
||||
annotations:
|
||||
kustomize.toolkit.fluxcd.io/substitute: disabled
|
||||
data:
|
||||
dashboard.json: '{"panels": [{"datasource": "${DataSource}"}]}'
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: ${REPO_NAME}-config
|
||||
namespace: ${REPO_NAMESPACE:=flux-system}
|
||||
data:
|
||||
region: ${CLUSTER_REGION:=eu-central-1}
|
||||
Loading…
Add table
Add a link
Reference in a new issue