Merge pull request #4710 from fluxcd/envsubst-cmd

Add `flux envsubst` command
pull/4717/head
Stefan Prodan 9 months ago committed by GitHub
commit f93da6fa76
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,74 @@
/*
Copyright 2024 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"bufio"
"fmt"
"github.com/fluxcd/pkg/envsubst"
"github.com/spf13/cobra"
)
var envsubstCmd = &cobra.Command{
Use: "envsubst",
Args: cobra.NoArgs,
Short: "envsubst substitutes the values of environment variables",
Long: withPreviewNote(`The envsubst command substitutes the values of environment variables
in the string piped as standard input and writes the result to the standard output. This command can be used
to replicate the behavior of the Flux Kustomization post-build substitutions.`),
Example: ` # Run env var substitutions on the kustomization build output
export cluster_region=eu-central-1
kustomize build . | flux envsubst
# Run env var substitutions and error out if a variable is not set
kustomize build . | flux envsubst --strict
`,
RunE: runEnvsubstCmd,
}
type envsubstFlags struct {
strict bool
}
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")
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
}
}
return nil
}

@ -0,0 +1,50 @@
/*
Copyright 2024 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"bytes"
"os"
"testing"
. "github.com/onsi/gomega"
)
func TestEnvsubst(t *testing.T) {
g := NewWithT(t)
input, err := os.ReadFile("testdata/envsubst/file.yaml")
g.Expect(err).NotTo(HaveOccurred())
t.Setenv("REPO_NAME", "test")
output, err := executeCommandWithIn("envsubst", bytes.NewReader(input))
g.Expect(err).NotTo(HaveOccurred())
expected, err := os.ReadFile("testdata/envsubst/file.gold")
g.Expect(err).NotTo(HaveOccurred())
g.Expect(output).To(Equal(string(expected)))
}
func TestEnvsubst_Strinct(t *testing.T) {
g := NewWithT(t)
input, err := os.ReadFile("testdata/envsubst/file.yaml")
g.Expect(err).NotTo(HaveOccurred())
_, err = executeCommandWithIn("envsubst --strict", bytes.NewReader(input))
g.Expect(err).To(HaveOccurred())
g.Expect(err.Error()).To(ContainSubstring("variable not set (strict mode)"))
}

@ -31,7 +31,6 @@ import (
"text/template" "text/template"
"time" "time"
"github.com/fluxcd/flux2/v2/internal/utils"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/mattn/go-shellwords" "github.com/mattn/go-shellwords"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
@ -40,6 +39,8 @@ import (
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest" "sigs.k8s.io/controller-runtime/pkg/envtest"
"github.com/fluxcd/flux2/v2/internal/utils"
) )
var nextNamespaceId int64 var nextNamespaceId int64
@ -393,6 +394,29 @@ func executeCommand(cmd string) (string, error) {
return result, err return result, err
} }
// Run the command while passing the string as input and return the captured output.
func executeCommandWithIn(cmd string, in io.Reader) (string, error) {
defer resetCmdArgs()
args, err := shellwords.Parse(cmd)
if err != nil {
return "", err
}
buf := new(bytes.Buffer)
rootCmd.SetOut(buf)
rootCmd.SetErr(buf)
rootCmd.SetArgs(args)
if in != nil {
rootCmd.SetIn(in)
}
_, err = rootCmd.ExecuteC()
result := buf.String()
return result, err
}
// resetCmdArgs resets the flags for various cmd // resetCmdArgs resets the flags for various cmd
// Note: this will also clear default value of the flags set in init() // Note: this will also clear default value of the flags set in init()
func resetCmdArgs() { func resetCmdArgs() {
@ -441,7 +465,7 @@ func resetCmdArgs() {
versionArgs = versionFlags{ versionArgs = versionFlags{
output: "yaml", output: "yaml",
} }
envsubstArgs = envsubstFlags{}
} }
func isChangeError(err error) bool { func isChangeError(err error) bool {

@ -0,0 +1,10 @@
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: test
namespace: flux-system
spec:
ref:
branch: main
interval: 5m
url: ssh://git@github.com/example/test

@ -0,0 +1,10 @@
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: ${REPO_NAME}
namespace: ${REPO_NAMESPACE:=flux-system}
spec:
ref:
branch: main
interval: 5m
url: ssh://git@github.com/example/${REPO_NAME}

@ -19,6 +19,7 @@ require (
github.com/fluxcd/notification-controller/api v1.2.4 github.com/fluxcd/notification-controller/api v1.2.4
github.com/fluxcd/pkg/apis/event v0.8.0 github.com/fluxcd/pkg/apis/event v0.8.0
github.com/fluxcd/pkg/apis/meta v1.4.0 github.com/fluxcd/pkg/apis/meta v1.4.0
github.com/fluxcd/pkg/envsubst v1.0.0
github.com/fluxcd/pkg/git v0.18.0 github.com/fluxcd/pkg/git v0.18.0
github.com/fluxcd/pkg/git/gogit v0.18.0 github.com/fluxcd/pkg/git/gogit v0.18.0
github.com/fluxcd/pkg/kustomize v1.9.0 github.com/fluxcd/pkg/kustomize v1.9.0
@ -117,7 +118,6 @@ require (
github.com/felixge/httpsnoop v1.0.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fluxcd/pkg/apis/acl v0.2.0 // indirect github.com/fluxcd/pkg/apis/acl v0.2.0 // indirect
github.com/fluxcd/pkg/apis/kustomize v1.4.0 // indirect github.com/fluxcd/pkg/apis/kustomize v1.4.0 // indirect
github.com/fluxcd/pkg/envsubst v1.0.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-errors/errors v1.5.1 // indirect github.com/go-errors/errors v1.5.1 // indirect
github.com/go-fed/httpsig v1.1.0 // indirect github.com/go-fed/httpsig v1.1.0 // indirect

Loading…
Cancel
Save