From 41c0bc69cee5f886c283b9618c015dc92faa56c4 Mon Sep 17 00:00:00 2001 From: Jan-Hendrik Boll Date: Mon, 25 Nov 2024 11:16:09 +0100 Subject: [PATCH 1/5] Add Dry Run for Shell Steps Add the capability to run dry runs on shell script steps. Did some slight refactorings to add tests. Also moved AKS Kubeconfig creation into Resource group to only call it once, as it is not required to run it for every stip since it can be reused --- tooling/templatize/pkg/config/types_test.go | 45 +++++ tooling/templatize/pkg/ev2/pipeline_test.go | 6 +- tooling/templatize/pkg/pipeline/inspect.go | 2 +- tooling/templatize/pkg/pipeline/run.go | 41 ++++- tooling/templatize/pkg/pipeline/shell.go | 88 ++++----- tooling/templatize/pkg/pipeline/shell_test.go | 168 ++++++++++++++++++ tooling/templatize/pkg/pipeline/types.go | 10 ++ tooling/templatize/pkg/utils/env.go | 8 +- tooling/templatize/pkg/utils/typing.go | 16 ++ tooling/templatize/testdata/Makefile | 4 + tooling/templatize/testdata/pipeline.yaml | 5 + ...re_TestPreprocessFileForEV2SystemVars.yaml | 5 + .../testdata/zz_fixture_TestRawOptions.yaml | 5 + 13 files changed, 353 insertions(+), 50 deletions(-) create mode 100644 tooling/templatize/pkg/config/types_test.go create mode 100644 tooling/templatize/pkg/pipeline/shell_test.go create mode 100644 tooling/templatize/pkg/utils/typing.go create mode 100644 tooling/templatize/testdata/Makefile diff --git a/tooling/templatize/pkg/config/types_test.go b/tooling/templatize/pkg/config/types_test.go new file mode 100644 index 000000000..8285e3734 --- /dev/null +++ b/tooling/templatize/pkg/config/types_test.go @@ -0,0 +1,45 @@ +package config + +import "testing" + +func TestGetByPath(t *testing.T) { + tests := []struct { + name string + vars Variables + path string + want any + found bool + }{ + { + name: "simple", + vars: Variables{ + "key": "value", + }, + path: "key", + want: "value", + found: true, + }, + { + name: "nested", + vars: Variables{ + "key": Variables{ + "key": "value", + }, + }, + path: "key.key", + want: "value", + found: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, found := tt.vars.GetByPath(tt.path) + if got != tt.want { + t.Errorf("Variables.GetByPath() got = %v, want %v", got, tt.want) + } + if found != tt.found { + t.Errorf("Variables.GetByPath() found = %v, want %v", found, tt.found) + } + }) + } +} diff --git a/tooling/templatize/pkg/ev2/pipeline_test.go b/tooling/templatize/pkg/ev2/pipeline_test.go index 4a0c0f983..540476335 100644 --- a/tooling/templatize/pkg/ev2/pipeline_test.go +++ b/tooling/templatize/pkg/ev2/pipeline_test.go @@ -31,8 +31,10 @@ func TestPrecompilePipelineForEV2(t *testing.T) { } fmt.Println(p) expectedParamsPath := "ev2-precompiled-test.bicepparam" - if p.ResourceGroups[0].Steps[1].Parameters != expectedParamsPath { - t.Errorf("expected parameters path %v, but got %v", expectedParamsPath, p.ResourceGroups[0].Steps[1].Parameters) + + armStep := p.ResourceGroups[0].Steps[2] + if armStep.Parameters != expectedParamsPath { + t.Errorf("expected parameters path %v, but got %v", expectedParamsPath, armStep.Parameters) } // TODO improve test, check against fixture } diff --git a/tooling/templatize/pkg/pipeline/inspect.go b/tooling/templatize/pkg/pipeline/inspect.go index aaadcae5a..739b7c50b 100644 --- a/tooling/templatize/pkg/pipeline/inspect.go +++ b/tooling/templatize/pkg/pipeline/inspect.go @@ -49,7 +49,7 @@ func inspectVars(s *step, options *PipelineInspectOptions, writer io.Writer) err var err error switch s.Action { case "Shell": - envVars, err = s.getEnvVars(options.Vars, false) + envVars, err = s.mapStepVariables(options.Vars) default: return fmt.Errorf("inspecting step variables not implemented for action type %s", s.Action) } diff --git a/tooling/templatize/pkg/pipeline/run.go b/tooling/templatize/pkg/pipeline/run.go index 783e1eae1..c8fb29fac 100644 --- a/tooling/templatize/pkg/pipeline/run.go +++ b/tooling/templatize/pkg/pipeline/run.go @@ -93,6 +93,19 @@ func (rg *resourceGroup) run(ctx context.Context, options *PipelineRunOptions) e } logger := logr.FromContextOrDiscard(ctx) + + kubeconfigFile, err := prepareKubeConfig(ctx, executionTarget) + if kubeconfigFile != "" { + defer func() { + if err := os.Remove(kubeconfigFile); err != nil { + logger.V(5).Error(err, "failed to delete kubeconfig file", "kubeconfig", kubeconfigFile) + } + }() + } + if err != nil { + return fmt.Errorf("failed to prepare kubeconfig: %w", err) + } + for _, step := range rg.Steps { if options.Step != "" && step.Name != options.Step { // skip steps that don't match the specified step name @@ -109,6 +122,7 @@ func (rg *resourceGroup) run(ctx context.Context, options *PipelineRunOptions) e "aksCluster", executionTarget.AKSClusterName, ), ), + kubeconfigFile, executionTarget, options, ) if err != nil { @@ -118,13 +132,17 @@ func (rg *resourceGroup) run(ctx context.Context, options *PipelineRunOptions) e return nil } -func (s *step) run(ctx context.Context, executionTarget *ExecutionTarget, options *PipelineRunOptions) error { +func (s *step) run(ctx context.Context, kubeconfigFile string, executionTarget *ExecutionTarget, options *PipelineRunOptions) error { fmt.Println("\n---------------------") + if options.DryRun { + fmt.Println("This is a dry run!") + } fmt.Println(s.description()) fmt.Print("\n") + switch s.Action { case "Shell": - return s.runShellStep(ctx, executionTarget, options) + return s.runShellStep(ctx, kubeconfigFile, options) case "ARM": return s.runArmStep(ctx, executionTarget, options) default: @@ -132,6 +150,25 @@ func (s *step) run(ctx context.Context, executionTarget *ExecutionTarget, option } } +func prepareKubeConfig(ctx context.Context, executionTarget *ExecutionTarget) (string, error) { + logger := logr.FromContextOrDiscard(ctx) + kubeconfigFile := "" + if executionTarget.AKSClusterName != "" { + logger.V(5).Info("Building kubeconfig for AKS cluster") + kubeconfigFile, err := executionTarget.KubeConfig(ctx) + if err != nil { + return "", fmt.Errorf("failed to build kubeconfig for %s: %w", executionTarget.aksID(), err) + } + defer func() { + if err := os.Remove(kubeconfigFile); err != nil { + logger.V(5).Error(err, "failed to delete kubeconfig file", "kubeconfig", kubeconfigFile) + } + }() + logger.V(5).Info("kubeconfig set to shell execution environment", "kubeconfig", kubeconfigFile) + } + return kubeconfigFile, nil +} + func (s *step) description() string { var details []string switch s.Action { diff --git a/tooling/templatize/pkg/pipeline/shell.go b/tooling/templatize/pkg/pipeline/shell.go index bac670e7f..23754a119 100644 --- a/tooling/templatize/pkg/pipeline/shell.go +++ b/tooling/templatize/pkg/pipeline/shell.go @@ -3,7 +3,7 @@ package pipeline import ( "context" "fmt" - "os" + "maps" "os/exec" "github.com/go-logr/logr" @@ -12,75 +12,75 @@ import ( "github.com/Azure/ARO-HCP/tooling/templatize/pkg/utils" ) -func (s *step) runShellStep(ctx context.Context, executionTarget *ExecutionTarget, options *PipelineRunOptions) error { +func (s *step) createCommand(ctx context.Context, dryRun bool, envVars map[string]string) (*exec.Cmd, bool) { + var cmd *exec.Cmd + if dryRun { + if s.DryRun.Command == nil && s.DryRun.EnvVars == nil { + return nil, true + } + for _, e := range s.DryRun.EnvVars { + envVars[e.Name] = e.Value + } + if s.DryRun.Command != nil { + cmd = exec.CommandContext(ctx, s.DryRun.Command[0], s.DryRun.Command[1:]...) + } + } + if cmd == nil { + // if dry-run is not enabled, use the actual command or also if no dry-run command is defined + cmd = exec.CommandContext(ctx, s.Command[0], s.Command[1:]...) + } + cmd.Env = append(cmd.Env, utils.MapToEnvVarArray(envVars)...) + return cmd, false +} + +func (s *step) runShellStep(ctx context.Context, kubeconfigFile string, options *PipelineRunOptions) error { + if s.outputFunc == nil { + s.outputFunc = func(output string) { + fmt.Println(output) + } + } + logger := logr.FromContextOrDiscard(ctx) // build ENV vars - envVars, err := s.getEnvVars(options.Vars, true) + stepVars, err := s.mapStepVariables(options.Vars) if err != nil { return fmt.Errorf("failed to build env vars: %w", err) } - // prepare kubeconfig - if executionTarget.AKSClusterName != "" { - logger.V(5).Info("Building kubeconfig for AKS cluster") - kubeconfigFile, err := executionTarget.KubeConfig(ctx) - if err != nil { - return fmt.Errorf("failed to build kubeconfig for %s: %w", executionTarget.aksID(), err) - } - defer func() { - if err := os.Remove(kubeconfigFile); err != nil { - logger.V(5).Error(err, "failed to delete kubeconfig file", "kubeconfig", kubeconfigFile) - } - }() - envVars["KUBECONFIG"] = kubeconfigFile - logger.V(5).Info("kubeconfig set to shell execution environment", "kubeconfig", kubeconfigFile) + envVars := utils.GetOsVariable() + + maps.Copy(envVars, stepVars) + // execute the command + cmd, skipCommand := s.createCommand(ctx, options.DryRun, envVars) + if skipCommand { + logger.V(5).Info("Skipping step '%s' due to missing dry-run configuiration", s.Name) + return nil } - // TODO handle dry-run + if kubeconfigFile != "" { + cmd.Env = append(cmd.Env, fmt.Sprintf("KUBECONFIG=%s", kubeconfigFile)) + } - // execute the command logger.V(5).Info(fmt.Sprintf("Executing shell command: %s\n", s.Command), "command", s.Command) - cmd := exec.CommandContext(ctx, s.Command[0], s.Command[1:]...) - cmd.Env = append(cmd.Env, utils.MapToEnvVarArray(envVars)...) output, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("failed to execute shell command: %s %w", string(output), err) } - // print the output of the command - fmt.Println(string(output)) + s.outputFunc(string(output)) return nil } -func (s *step) getEnvVars(vars config.Variables, includeOSEnvVars bool) (map[string]string, error) { +func (s *step) mapStepVariables(vars config.Variables) (map[string]string, error) { envVars := make(map[string]string) - envVars["RUNS_IN_TEMPLATIZE"] = "1" - if includeOSEnvVars { - for k, v := range utils.GetOSEnvVarsAsMap() { - envVars[k] = v - } - } for _, e := range s.Env { value, found := vars.GetByPath(e.ConfigRef) if !found { return nil, fmt.Errorf("failed to lookup config reference %s for %s", e.ConfigRef, e.Name) } - envVars[e.Name] = anyToString(value) + envVars[e.Name] = utils.AnyToString(value) } return envVars, nil } - -func anyToString(value any) string { - switch v := value.(type) { - case string: - return v - case int: - return fmt.Sprintf("%d", v) - case bool: - return fmt.Sprintf("%t", v) - default: - return fmt.Sprintf("%v", v) - } -} diff --git a/tooling/templatize/pkg/pipeline/shell_test.go b/tooling/templatize/pkg/pipeline/shell_test.go new file mode 100644 index 000000000..4ac7f6a6e --- /dev/null +++ b/tooling/templatize/pkg/pipeline/shell_test.go @@ -0,0 +1,168 @@ +package pipeline + +import ( + "context" + "testing" + + "gotest.tools/v3/assert" + + "github.com/Azure/ARO-HCP/tooling/templatize/pkg/config" +) + +func TestCreateCommand(t *testing.T) { + ctx := context.Background() + testCases := []struct { + name string + step *step + dryRun bool + envVars map[string]string + expectedCommand string + expectedArgs []string + expectedEnv []string + skipCommand bool + }{ + { + name: "basic", + step: &step{ + Command: []string{"/usr/bin/echo", "hello"}, + }, + expectedCommand: "/usr/bin/echo", + expectedArgs: []string{"hello"}, + }, + { + name: "dry-run", + step: &step{ + Command: []string{"/usr/bin/echo", "hello"}, + DryRun: dryRun{ + Command: []string{"/usr/bin/echo", "dry-run"}, + }, + }, + dryRun: true, + expectedCommand: "/usr/bin/echo", + expectedArgs: []string{"dry-run"}, + }, + { + name: "dry-run-env", + step: &step{ + Command: []string{"/usr/bin/echo"}, + DryRun: dryRun{ + EnvVars: []EnvVar{ + { + Name: "DRY_RUN", + Value: "true", + }, + }, + }, + }, + dryRun: true, + expectedCommand: "/usr/bin/echo", + envVars: map[string]string{}, + expectedEnv: []string{"DRY_RUN=true"}, + }, + { + name: "dry-run fail", + step: &step{ + Command: []string{"/usr/bin/echo"}, + }, + dryRun: true, + skipCommand: true, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + cmd, skipCommand := tc.step.createCommand(ctx, tc.dryRun, tc.envVars) + assert.Equal(t, skipCommand, tc.skipCommand) + if !tc.skipCommand { + assert.Equal(t, cmd.Path, tc.expectedCommand) + } + if tc.expectedArgs != nil { + assert.DeepEqual(t, cmd.Args[1:], tc.expectedArgs) + } + if tc.expectedEnv != nil { + assert.DeepEqual(t, cmd.Env, tc.expectedEnv) + } + }) + } + +} + +func TestMapStepVariables(t *testing.T) { + testCases := []struct { + name string + vars config.Variables + step step + expected map[string]string + err string + }{ + { + name: "basic", + vars: config.Variables{ + "FOO": "bar", + }, + step: step{ + Env: []EnvVar{ + { + Name: "BAZ", + ConfigRef: "FOO", + }, + }, + }, + expected: map[string]string{ + "BAZ": "bar", + }, + }, + { + name: "missing", + vars: config.Variables{}, + step: step{ + Env: []EnvVar{ + { + ConfigRef: "FOO", + }, + }, + }, + err: "failed to lookup config reference FOO for ", + }, + { + name: "type conversion", + vars: config.Variables{ + "FOO": 42, + }, + step: step{ + Env: []EnvVar{ + { + Name: "BAZ", + ConfigRef: "FOO", + }, + }, + }, + expected: map[string]string{ + "BAZ": "42", + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + envVars, err := tc.step.mapStepVariables(tc.vars) + t.Log(envVars) + if tc.err != "" { + assert.Error(t, err, tc.err) + } else { + assert.NilError(t, err) + assert.DeepEqual(t, envVars, tc.expected) + } + }) + } +} + +func TestRunShellStep(t *testing.T) { + expectedOutput := "hello\n" + s := &step{ + Command: []string{"echo", "hello"}, + outputFunc: func(output string) { + assert.Equal(t, output, expectedOutput) + }, + } + err := s.runShellStep(context.Background(), "", &PipelineRunOptions{}) + assert.NilError(t, err) +} diff --git a/tooling/templatize/pkg/pipeline/types.go b/tooling/templatize/pkg/pipeline/types.go index 58db883f5..4dc9fb3df 100644 --- a/tooling/templatize/pkg/pipeline/types.go +++ b/tooling/templatize/pkg/pipeline/types.go @@ -14,6 +14,8 @@ type resourceGroup struct { Steps []*step `yaml:"steps"` } +type outPutHandler func(string) + type step struct { Name string `yaml:"name"` Action string `yaml:"action"` @@ -22,9 +24,17 @@ type step struct { Template string `yaml:"template"` Parameters string `yaml:"parameters"` DependsOn []string `yaml:"dependsOn"` + DryRun dryRun `yaml:"dryRun"` + outputFunc outPutHandler +} + +type dryRun struct { + EnvVars []EnvVar `yaml:"envVars"` + Command []string `yaml:"command"` } type EnvVar struct { Name string `yaml:"name"` ConfigRef string `yaml:"configRef"` + Value string `yaml:"value"` } diff --git a/tooling/templatize/pkg/utils/env.go b/tooling/templatize/pkg/utils/env.go index 84c51b537..fff04e5f1 100644 --- a/tooling/templatize/pkg/utils/env.go +++ b/tooling/templatize/pkg/utils/env.go @@ -2,18 +2,24 @@ package utils import ( "fmt" + "maps" "os" "strings" ) -func GetOSEnvVarsAsMap() map[string]string { +func GetOsVariable() map[string]string { envVars := make(map[string]string) + envVars["RUNS_IN_TEMPLATIZE"] = "1" + + osVars := make(map[string]string) for _, env := range os.Environ() { parts := strings.SplitN(env, "=", 2) if len(parts) == 2 { envVars[parts[0]] = parts[1] } } + maps.Copy(envVars, osVars) + return envVars } diff --git a/tooling/templatize/pkg/utils/typing.go b/tooling/templatize/pkg/utils/typing.go new file mode 100644 index 000000000..954c360c5 --- /dev/null +++ b/tooling/templatize/pkg/utils/typing.go @@ -0,0 +1,16 @@ +package utils + +import "fmt" + +func AnyToString(value any) string { + switch v := value.(type) { + case string: + return v + case int: + return fmt.Sprintf("%d", v) + case bool: + return fmt.Sprintf("%t", v) + default: + return fmt.Sprintf("%v", v) + } +} diff --git a/tooling/templatize/testdata/Makefile b/tooling/templatize/testdata/Makefile new file mode 100644 index 000000000..9eed15a1e --- /dev/null +++ b/tooling/templatize/testdata/Makefile @@ -0,0 +1,4 @@ +deploy: + echo ${DRY_RUN} + +.PHONE: deploy \ No newline at end of file diff --git a/tooling/templatize/testdata/pipeline.yaml b/tooling/templatize/testdata/pipeline.yaml index 702bb39d5..77e6e1c4d 100644 --- a/tooling/templatize/testdata/pipeline.yaml +++ b/tooling/templatize/testdata/pipeline.yaml @@ -11,6 +11,11 @@ resourceGroups: env: - name: MAESTRO_IMAGE configRef: maestro_image + - name: dry-run + action: Shell + command: ["make", "dry-run"] + dryRun: + command: ["make", "-n", "dry-run"] - name: svc action: ARM template: templates/svc-cluster.bicep diff --git a/tooling/templatize/testdata/zz_fixture_TestPreprocessFileForEV2SystemVars.yaml b/tooling/templatize/testdata/zz_fixture_TestPreprocessFileForEV2SystemVars.yaml index 9540159a7..b9202d5bb 100644 --- a/tooling/templatize/testdata/zz_fixture_TestPreprocessFileForEV2SystemVars.yaml +++ b/tooling/templatize/testdata/zz_fixture_TestPreprocessFileForEV2SystemVars.yaml @@ -11,6 +11,11 @@ resourceGroups: env: - name: MAESTRO_IMAGE configRef: maestro_image + - name: dry-run + action: Shell + command: ["make", "dry-run"] + dryRun: + command: ["make", "-n", "dry-run"] - name: svc action: ARM template: templates/svc-cluster.bicep diff --git a/tooling/templatize/testdata/zz_fixture_TestRawOptions.yaml b/tooling/templatize/testdata/zz_fixture_TestRawOptions.yaml index fc58ba012..846a0f5c8 100644 --- a/tooling/templatize/testdata/zz_fixture_TestRawOptions.yaml +++ b/tooling/templatize/testdata/zz_fixture_TestRawOptions.yaml @@ -11,6 +11,11 @@ resourceGroups: env: - name: MAESTRO_IMAGE configRef: maestro_image + - name: dry-run + action: Shell + command: ["make", "dry-run"] + dryRun: + command: ["make", "-n", "dry-run"] - name: svc action: ARM template: templates/svc-cluster.bicep From 3f571eaabeac7cd043be84912af3e09ed702690a Mon Sep 17 00:00:00 2001 From: Jan-Hendrik Boll Date: Mon, 25 Nov 2024 11:18:10 +0100 Subject: [PATCH 2/5] Fix lint --- tooling/templatize/testdata/Makefile | 2 +- tooling/templatize/testdata/pipeline.yaml | 2 +- .../testdata/zz_fixture_TestPreprocessFileForEV2SystemVars.yaml | 2 +- tooling/templatize/testdata/zz_fixture_TestRawOptions.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tooling/templatize/testdata/Makefile b/tooling/templatize/testdata/Makefile index 9eed15a1e..71375ec54 100644 --- a/tooling/templatize/testdata/Makefile +++ b/tooling/templatize/testdata/Makefile @@ -1,4 +1,4 @@ deploy: echo ${DRY_RUN} -.PHONE: deploy \ No newline at end of file +.PHONE: deploy diff --git a/tooling/templatize/testdata/pipeline.yaml b/tooling/templatize/testdata/pipeline.yaml index 77e6e1c4d..baa14191a 100644 --- a/tooling/templatize/testdata/pipeline.yaml +++ b/tooling/templatize/testdata/pipeline.yaml @@ -14,7 +14,7 @@ resourceGroups: - name: dry-run action: Shell command: ["make", "dry-run"] - dryRun: + dryRun: command: ["make", "-n", "dry-run"] - name: svc action: ARM diff --git a/tooling/templatize/testdata/zz_fixture_TestPreprocessFileForEV2SystemVars.yaml b/tooling/templatize/testdata/zz_fixture_TestPreprocessFileForEV2SystemVars.yaml index b9202d5bb..5d00de465 100644 --- a/tooling/templatize/testdata/zz_fixture_TestPreprocessFileForEV2SystemVars.yaml +++ b/tooling/templatize/testdata/zz_fixture_TestPreprocessFileForEV2SystemVars.yaml @@ -14,7 +14,7 @@ resourceGroups: - name: dry-run action: Shell command: ["make", "dry-run"] - dryRun: + dryRun: command: ["make", "-n", "dry-run"] - name: svc action: ARM diff --git a/tooling/templatize/testdata/zz_fixture_TestRawOptions.yaml b/tooling/templatize/testdata/zz_fixture_TestRawOptions.yaml index 846a0f5c8..200b06cc1 100644 --- a/tooling/templatize/testdata/zz_fixture_TestRawOptions.yaml +++ b/tooling/templatize/testdata/zz_fixture_TestRawOptions.yaml @@ -14,7 +14,7 @@ resourceGroups: - name: dry-run action: Shell command: ["make", "dry-run"] - dryRun: + dryRun: command: ["make", "-n", "dry-run"] - name: svc action: ARM From 4cb8f935a5a5aa0dbd588fa2d8bd3e21f535d569 Mon Sep 17 00:00:00 2001 From: Jan-Hendrik Boll Date: Mon, 25 Nov 2024 11:24:02 +0100 Subject: [PATCH 3/5] Pipeline test fixes --- tooling/templatize/testdata/pipeline.yaml | 6 ++++-- .../zz_fixture_TestPreprocessFileForEV2SystemVars.yaml | 6 ++++-- tooling/templatize/testdata/zz_fixture_TestRawOptions.yaml | 6 ++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/tooling/templatize/testdata/pipeline.yaml b/tooling/templatize/testdata/pipeline.yaml index baa14191a..bd61629dc 100644 --- a/tooling/templatize/testdata/pipeline.yaml +++ b/tooling/templatize/testdata/pipeline.yaml @@ -13,9 +13,11 @@ resourceGroups: configRef: maestro_image - name: dry-run action: Shell - command: ["make", "dry-run"] + command: ["make", "deploy"] dryRun: - command: ["make", "-n", "dry-run"] + envVars: + - name: DRY_RUN + value: "A very dry one" - name: svc action: ARM template: templates/svc-cluster.bicep diff --git a/tooling/templatize/testdata/zz_fixture_TestPreprocessFileForEV2SystemVars.yaml b/tooling/templatize/testdata/zz_fixture_TestPreprocessFileForEV2SystemVars.yaml index 5d00de465..b243c236c 100644 --- a/tooling/templatize/testdata/zz_fixture_TestPreprocessFileForEV2SystemVars.yaml +++ b/tooling/templatize/testdata/zz_fixture_TestPreprocessFileForEV2SystemVars.yaml @@ -13,9 +13,11 @@ resourceGroups: configRef: maestro_image - name: dry-run action: Shell - command: ["make", "dry-run"] + command: ["make", "deploy"] dryRun: - command: ["make", "-n", "dry-run"] + envVars: + - name: DRY_RUN + value: "A very dry one" - name: svc action: ARM template: templates/svc-cluster.bicep diff --git a/tooling/templatize/testdata/zz_fixture_TestRawOptions.yaml b/tooling/templatize/testdata/zz_fixture_TestRawOptions.yaml index 200b06cc1..4b8ed8ef3 100644 --- a/tooling/templatize/testdata/zz_fixture_TestRawOptions.yaml +++ b/tooling/templatize/testdata/zz_fixture_TestRawOptions.yaml @@ -13,9 +13,11 @@ resourceGroups: configRef: maestro_image - name: dry-run action: Shell - command: ["make", "dry-run"] + command: ["make", "deploy"] dryRun: - command: ["make", "-n", "dry-run"] + envVars: + - name: DRY_RUN + value: "A very dry one" - name: svc action: ARM template: templates/svc-cluster.bicep From 2c6b1ba8f710578945bf7bab48c8a5bc0aa3cecc Mon Sep 17 00:00:00 2001 From: Jan-Hendrik Boll Date: Mon, 25 Nov 2024 11:30:04 +0100 Subject: [PATCH 4/5] Tests and comments for utils functions --- tooling/templatize/pkg/utils/env.go | 3 +++ tooling/templatize/pkg/utils/env_test.go | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 tooling/templatize/pkg/utils/env_test.go diff --git a/tooling/templatize/pkg/utils/env.go b/tooling/templatize/pkg/utils/env.go index fff04e5f1..2798a3746 100644 --- a/tooling/templatize/pkg/utils/env.go +++ b/tooling/templatize/pkg/utils/env.go @@ -7,6 +7,8 @@ import ( "strings" ) +// GetOsVariable looks up OS environment variables and returns them as a map. +// It also sets a special environment variable RUNS_IN_TEMPLATIZE to 1. func GetOsVariable() map[string]string { envVars := make(map[string]string) envVars["RUNS_IN_TEMPLATIZE"] = "1" @@ -23,6 +25,7 @@ func GetOsVariable() map[string]string { return envVars } +// MapToEnvVarArray converts a map of environment variables to an array of strings. func MapToEnvVarArray(envVars map[string]string) []string { envVarArray := make([]string, 0, len(envVars)) for k, v := range envVars { diff --git a/tooling/templatize/pkg/utils/env_test.go b/tooling/templatize/pkg/utils/env_test.go new file mode 100644 index 000000000..2d15ac8c0 --- /dev/null +++ b/tooling/templatize/pkg/utils/env_test.go @@ -0,0 +1,22 @@ +package utils + +import ( + "testing" + + "gotest.tools/assert" +) + +func TestGetOsVariable(t *testing.T) { + t.Setenv("FOO", "BAR") + envVars := GetOsVariable() + assert.Equal(t, "1", envVars["RUNS_IN_TEMPLATIZE"]) + assert.Equal(t, "BAR", envVars["FOO"]) +} + +func TestMapToEnvVarArray(t *testing.T) { + envVars := map[string]string{ + "FOO": "BAR", + } + envVarArray := MapToEnvVarArray(envVars) + assert.DeepEqual(t, []string{"FOO=BAR"}, envVarArray) +} From abe34fb0d920be554471d61cb4546b1227c610b2 Mon Sep 17 00:00:00 2001 From: Jan-Hendrik Boll Date: Mon, 25 Nov 2024 11:35:09 +0100 Subject: [PATCH 5/5] Adding simple test to AnyToString as well --- tooling/templatize/pkg/utils/typing.go | 5 ++++- tooling/templatize/pkg/utils/typing_test.go | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 tooling/templatize/pkg/utils/typing_test.go diff --git a/tooling/templatize/pkg/utils/typing.go b/tooling/templatize/pkg/utils/typing.go index 954c360c5..dba9a4f49 100644 --- a/tooling/templatize/pkg/utils/typing.go +++ b/tooling/templatize/pkg/utils/typing.go @@ -1,7 +1,10 @@ package utils -import "fmt" +import ( + "fmt" +) +// AnyToString maps some types to strings, as they are used in OS Env. func AnyToString(value any) string { switch v := value.(type) { case string: diff --git a/tooling/templatize/pkg/utils/typing_test.go b/tooling/templatize/pkg/utils/typing_test.go new file mode 100644 index 000000000..9797c1455 --- /dev/null +++ b/tooling/templatize/pkg/utils/typing_test.go @@ -0,0 +1,14 @@ +package utils + +import ( + "testing" + + "gotest.tools/assert" +) + +func TestAnyToString(t *testing.T) { + assert.Equal(t, "foo", AnyToString("foo")) + assert.Equal(t, "42", AnyToString(42)) + assert.Equal(t, "true", AnyToString(true)) + assert.Equal(t, "3.14", AnyToString(3.14)) +}