From 588794f29ff37852ec1ec47ea82707d14addad90 Mon Sep 17 00:00:00 2001 From: Darren Shepherd Date: Sun, 11 Jun 2023 17:33:44 -0700 Subject: [PATCH] Add env values "acorn run -e ARG" style to a secret Signed-off-by: Darren Shepherd --- pkg/cli/dev.go | 2 +- pkg/cli/run.go | 10 +++++-- pkg/cli/run_test.go | 18 ------------ pkg/env/parse.go | 53 ++++++++++++++++++++++++++++++++++++ pkg/secrets/interpolation.go | 13 ++++++++- 5 files changed, 73 insertions(+), 23 deletions(-) create mode 100644 pkg/env/parse.go diff --git a/pkg/cli/dev.go b/pkg/cli/dev.go index 3bfb943fa..4d85d98ca 100644 --- a/pkg/cli/dev.go +++ b/pkg/cli/dev.go @@ -53,7 +53,7 @@ func (s *Dev) Run(cmd *cobra.Command, args []string) error { imageSource := imagesource.NewImageSource(s.File, args, s.Profile, nil) - opts, err := s.ToOpts() + opts, err := s.ToOpts(cmd.Context(), c) if err != nil { return err } diff --git a/pkg/cli/run.go b/pkg/cli/run.go index 3a3e1b73f..468f12178 100644 --- a/pkg/cli/run.go +++ b/pkg/cli/run.go @@ -13,6 +13,7 @@ import ( cli "github.com/acorn-io/acorn/pkg/cli/builder" "github.com/acorn-io/acorn/pkg/client" "github.com/acorn-io/acorn/pkg/dev" + "github.com/acorn-io/acorn/pkg/env" "github.com/acorn-io/acorn/pkg/imagesource" "github.com/acorn-io/acorn/pkg/rulerequest" "github.com/acorn-io/acorn/pkg/wait" @@ -147,7 +148,7 @@ type RunArgs struct { Name string `usage:"Name of app to create" short:"n"` } -func (s RunArgs) ToOpts() (client.AppRunOptions, error) { +func (s RunArgs) ToOpts(ctx context.Context, c client.Client) (client.AppRunOptions, error) { var ( opts client.AppRunOptions err error @@ -186,7 +187,10 @@ func (s RunArgs) ToOpts() (client.AppRunOptions, error) { return opts, err } - opts.Env = v1.ParseNameValues(true, s.Env...) + opts.Env, err = env.ParseEnvForCLIAndCreateSecret(ctx, c, s.Env...) + if err != nil { + return opts, err + } opts.Labels, err = v1.ParseScopedLabels(s.Label...) if err != nil { @@ -234,7 +238,7 @@ func (s *Run) Run(cmd *cobra.Command, args []string) (err error) { updated bool ) - opts, err := s.ToOpts() + opts, err := s.ToOpts(cmd.Context(), c) if err != nil { return err } diff --git a/pkg/cli/run_test.go b/pkg/cli/run_test.go index 267340b2b..b8af97a7d 100644 --- a/pkg/cli/run_test.go +++ b/pkg/cli/run_test.go @@ -22,24 +22,6 @@ import ( "github.com/stretchr/testify/assert" ) -func TestRunArgs_Env(t *testing.T) { - os.Setenv("x222", "y333") - runArgs := RunArgs{ - UpdateArgs: UpdateArgs{ - Env: []string{"x222", "y=1"}, - }, - } - opts, err := runArgs.ToOpts() - if err != nil { - t.Fatal(err) - } - - assert.Equal(t, "x222", opts.Env[0].Name) - assert.Equal(t, "y333", opts.Env[0].Value) - assert.Equal(t, "y", opts.Env[1].Name) - assert.Equal(t, "1", opts.Env[1].Value) -} - func TestRun(t *testing.T) { baseMock := func(f *mocks.MockClient) { f.EXPECT().AppGet(gomock.Any(), gomock.Any()).DoAndReturn( diff --git a/pkg/env/parse.go b/pkg/env/parse.go new file mode 100644 index 000000000..315d9c06f --- /dev/null +++ b/pkg/env/parse.go @@ -0,0 +1,53 @@ +package env + +import ( + "context" + "fmt" + "os" + "strings" + + v1 "github.com/acorn-io/acorn/pkg/apis/internal.acorn.io/v1" + "github.com/acorn-io/acorn/pkg/client" + "github.com/acorn-io/baaah/pkg/randomtoken" +) + +func ParseEnvForCLIAndCreateSecret(ctx context.Context, client client.Client, s ...string) (result []v1.NameValue, _ error) { + random, err := randomtoken.Generate() + if err != nil { + return nil, err + } + secretName := "shell-env-" + random[:8] + secretValues := map[string][]byte{} + for _, s := range s { + k, v, ok := strings.Cut(s, "=") + if ok { + result = append(result, v1.NameValue{ + Name: k, + Value: v, + }) + } else { + v = os.Getenv(k) + if v == "" { + result = append(result, v1.NameValue{ + Name: k, + Value: v, + }) + } else { + result = append(result, v1.NameValue{ + Name: k, + Value: fmt.Sprintf("@{secrets.external:%s.%s}", secretName, k), + }) + secretValues[k] = []byte(v) + } + } + } + + if len(secretValues) > 0 { + _, err := client.SecretCreate(ctx, secretName, "", secretValues) + if err != nil { + return nil, err + } + } + + return result, nil +} diff --git a/pkg/secrets/interpolation.go b/pkg/secrets/interpolation.go index 858ded2d6..839296826 100644 --- a/pkg/secrets/interpolation.go +++ b/pkg/secrets/interpolation.go @@ -179,7 +179,18 @@ func (i *Interpolator) resolveApp(keyName string) (string, bool, error) { func (i *Interpolator) resolveSecrets(secretName []string, keyName string) (string, bool, error) { secret := &corev1.Secret{} - err := ref.Lookup(i.ctx, i.client, secret, i.namespace, secretName...) + ns := i.namespace + secretNames := secretName + + // support interpolation of external secrets + if len(secretName) > 0 && strings.HasPrefix(secretName[0], "external:") { + secretNames = append([]string{ + strings.TrimPrefix(secretName[0], "external:"), + }, secretName[1:]...) + ns = i.app.Namespace + } + + err := ref.Lookup(i.ctx, i.client, secret, ns, secretNames...) if apierrors.IsNotFound(err) { return "", false, &ErrInterpolation{ ExpressionError: v1.ExpressionError{