diff --git a/cli/cmd/auto.go b/cli/cmd/auto.go index db33b20f..9ffef057 100644 --- a/cli/cmd/auto.go +++ b/cli/cmd/auto.go @@ -48,12 +48,14 @@ func init() { func runAuto(cmd *cobra.Command, args []string) error { output.Header("Kates Auto-Deploy") - executor := detect.NewOSExecutor() + executor := defaultExecutor collector := detect.NewCollector(executor) + // Introspection creates a namespace, a Secret and prober pods. A dry run + // collects without them, as kates deploy --dry-run does. + collector.ReadOnly = autoDryRun if err := collector.Preflight(); err != nil { - output.Error(fmt.Sprintf("Preflight failed: %v", err)) - os.Exit(1) + return cmdErr(fmt.Sprintf("Preflight failed: %v", err)) } // 1. Detect Phase @@ -62,6 +64,7 @@ func runAuto(cmd *cobra.Command, args []string) error { report, collectErr := collector.Collect(context.Background()) if collectErr != nil { output.Error(fmt.Sprintf("Cluster introspection failed: %v", collectErr)) + // The CLI reference documents exit 2 here; an error from RunE exits 1. os.Exit(2) } diff --git a/cli/cmd/auto_test.go b/cli/cmd/auto_test.go new file mode 100644 index 00000000..13a7d5e3 --- /dev/null +++ b/cli/cmd/auto_test.go @@ -0,0 +1,40 @@ +package cmd + +import ( + "path/filepath" + "strings" + "testing" +) + +// kates auto --dry-run introspected the cluster with every write probe on: a +// namespace, a Secret and prober pods, where kates deploy --dry-run writes +// nothing. The run without --dry-run is the control: the same introspection +// does write. +func TestAutoDryRunCollectsReadOnly(t *testing.T) { + origExecutor, origDryRun, origChart := defaultExecutor, autoDryRun, autoChartDir + t.Cleanup(func() { defaultExecutor, autoDryRun, autoChartDir = origExecutor, origDryRun, origChart }) + // No chart there, so the run stops before helm, right after introspection. + autoChartDir = filepath.Join(t.TempDir(), "no-chart") + + writes := func(dryRun bool) []string { + rec := &recordingExecutor{} + defaultExecutor, autoDryRun = rec, dryRun + if err := runAuto(autoCmd, nil); err == nil || !strings.Contains(err.Error(), "Helm chart not found") { + t.Fatalf("dry run %v: err = %v, want the missing chart", dryRun, err) + } + var out []string + for _, c := range rec.commands() { + if clusterWrite.MatchString(c) { + out = append(out, c) + } + } + return out + } + + if len(writes(false)) == 0 { + t.Fatal("control: introspection without --dry-run wrote nothing, so the dry run proves nothing") + } + if got := writes(true); len(got) != 0 { + t.Errorf("auto --dry-run wrote to the cluster:\n %s", strings.Join(got, "\n ")) + } +}