diff --git a/internal/cli/dryrun_test.go b/internal/cli/dryrun_test.go index dbd886a..4573278 100644 --- a/internal/cli/dryrun_test.go +++ b/internal/cli/dryrun_test.go @@ -581,8 +581,8 @@ func TestInstallCommand_DryRun(t *testing.T) { } }) - if !strings.Contains(output, "CustomResourceDefinition") { - t.Errorf("expected CRD manifest in dry-run output, got:\n%s", output[:min(len(output), 500)]) + if strings.Contains(output, "CustomResourceDefinition") { + t.Errorf("expected no CRD manifest in default dry-run output, got:\n%s", output[:min(len(output), 500)]) } if !strings.Contains(output, "Deployment") { t.Errorf("expected Deployment manifest in dry-run output, got:\n%s", output[:min(len(output), 500)]) diff --git a/internal/cli/install.go b/internal/cli/install.go index 16b0f9e..0f9e5c2 100644 --- a/internal/cli/install.go +++ b/internal/cli/install.go @@ -31,10 +31,11 @@ func newInstallCommand(cfg *ClientConfig) *cobra.Command { var dryRun bool var flagVersion string var imagePullPolicy string + var crd bool cmd := &cobra.Command{ Use: "install", - Short: "Install kelos CRDs and controller into the cluster", + Short: "Install kelos controller into the cluster", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { if flagVersion != "" { @@ -46,10 +47,12 @@ func newInstallCommand(cfg *ClientConfig) *cobra.Command { } if dryRun { - if _, err := os.Stdout.Write(manifests.InstallCRD); err != nil { - return err + if crd { + if _, err := os.Stdout.Write(manifests.InstallCRD); err != nil { + return err + } + fmt.Fprintln(os.Stdout, "---") } - fmt.Fprintln(os.Stdout, "---") _, err := os.Stdout.Write(controllerManifest) return err } @@ -70,9 +73,11 @@ func newInstallCommand(cfg *ClientConfig) *cobra.Command { ctx := cmd.Context() - fmt.Fprintf(os.Stdout, "Installing kelos CRDs\n") - if err := applyManifests(ctx, dc, dyn, manifests.InstallCRD); err != nil { - return fmt.Errorf("installing CRDs: %w", err) + if crd { + fmt.Fprintf(os.Stdout, "Installing kelos CRDs\n") + if err := applyManifests(ctx, dc, dyn, manifests.InstallCRD); err != nil { + return fmt.Errorf("installing CRDs: %w", err) + } } fmt.Fprintf(os.Stdout, "Installing kelos controller (version: %s)\n", version.Version) @@ -88,6 +93,7 @@ func newInstallCommand(cfg *ClientConfig) *cobra.Command { cmd.Flags().BoolVar(&dryRun, "dry-run", false, "print the manifests that would be applied without installing") cmd.Flags().StringVar(&flagVersion, "version", "", "override the version used for image tags (defaults to the binary version)") cmd.Flags().StringVar(&imagePullPolicy, "image-pull-policy", "", "set imagePullPolicy on controller containers (e.g. Always, IfNotPresent, Never)") + cmd.Flags().BoolVar(&crd, "crd", false, "install CRDs along with the controller") return cmd } @@ -134,9 +140,11 @@ func withImagePullPolicy(data []byte, policy string) []byte { } func newUninstallCommand(cfg *ClientConfig) *cobra.Command { + var crd bool + cmd := &cobra.Command{ Use: "uninstall", - Short: "Uninstall kelos controller and CRDs from the cluster", + Short: "Uninstall kelos controller from the cluster", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { restConfig, _, err := cfg.resolveConfig() @@ -160,9 +168,11 @@ func newUninstallCommand(cfg *ClientConfig) *cobra.Command { return fmt.Errorf("removing controller: %w", err) } - fmt.Fprintf(os.Stdout, "Removing kelos CRDs\n") - if err := deleteManifests(ctx, dc, dyn, manifests.InstallCRD); err != nil { - return fmt.Errorf("removing CRDs: %w", err) + if crd { + fmt.Fprintf(os.Stdout, "Removing kelos CRDs\n") + if err := deleteManifests(ctx, dc, dyn, manifests.InstallCRD); err != nil { + return fmt.Errorf("removing CRDs: %w", err) + } } fmt.Fprintf(os.Stdout, "Kelos uninstalled successfully\n") @@ -170,6 +180,8 @@ func newUninstallCommand(cfg *ClientConfig) *cobra.Command { }, } + cmd.Flags().BoolVar(&crd, "crd", false, "remove CRDs along with the controller") + return cmd } diff --git a/internal/cli/install_test.go b/internal/cli/install_test.go index 1cab96d..2496ab0 100644 --- a/internal/cli/install_test.go +++ b/internal/cli/install_test.go @@ -315,6 +315,59 @@ func TestWithImagePullPolicy(t *testing.T) { } } +func TestInstallCommand_CRDFlagDefault(t *testing.T) { + cmd := NewRootCommand() + cmd.SetArgs([]string{"install", "--dry-run"}) + + output := captureStdout(t, func() { + if err := cmd.Execute(); err != nil { + t.Fatalf("unexpected error: %v", err) + } + }) + + if strings.Contains(output, "CustomResourceDefinition") { + t.Errorf("expected no CRD manifest in default output, got:\n%s", output[:min(len(output), 500)]) + } + if !strings.Contains(output, "Deployment") { + t.Errorf("expected controller manifest in output, got:\n%s", output[:min(len(output), 500)]) + } +} + +func TestInstallCommand_CRDFlagTrue(t *testing.T) { + cmd := NewRootCommand() + cmd.SetArgs([]string{"install", "--dry-run", "--crd"}) + + output := captureStdout(t, func() { + if err := cmd.Execute(); err != nil { + t.Fatalf("unexpected error: %v", err) + } + }) + + if !strings.Contains(output, "CustomResourceDefinition") { + t.Errorf("expected CRD manifest when --crd is set, got:\n%s", output[:min(len(output), 500)]) + } + if !strings.Contains(output, "Deployment") { + t.Errorf("expected controller manifest in output, got:\n%s", output[:min(len(output), 500)]) + } +} + +func TestUninstallCommand_CRDFlagAccepted(t *testing.T) { + cmd := NewRootCommand() + cmd.SetArgs([]string{ + "uninstall", + "--crd", + "--kubeconfig", "/nonexistent/path/kubeconfig", + }) + err := cmd.Execute() + if err == nil { + t.Fatal("expected uninstall to fail with invalid kubeconfig") + } + // The flag should be accepted; the error should be about kubeconfig, not an unknown flag. + if strings.Contains(err.Error(), "unknown flag") { + t.Fatalf("--crd flag should be accepted, got: %v", err) + } +} + func TestWithImagePullPolicy_EmbeddedController(t *testing.T) { result := withImagePullPolicy(manifests.InstallController, "IfNotPresent") if !bytes.Contains(result, []byte("imagePullPolicy: IfNotPresent")) {