From 73a5fe799fa26e14e5eacfdcaacbc2f33c2a7240 Mon Sep 17 00:00:00 2001 From: Praveen Rewar <8457124+praveenrewar@users.noreply.github.com> Date: Tue, 29 Aug 2023 15:43:46 +0530 Subject: [PATCH] Add --app-namespace flag Signed-off-by: Praveen Rewar <8457124+praveenrewar@users.noreply.github.com> --- pkg/kapp/cmd/app/app_flags.go | 2 + pkg/kapp/cmd/app/factory.go | 12 ++++-- pkg/kapp/cmd/app/list.go | 2 +- pkg/kapp/cmd/appgroup/delete.go | 2 +- pkg/kapp/cmd/appgroup/deploy.go | 2 +- test/e2e/app_namespace_test.go | 71 +++++++++++++++++++++++++++++++++ 6 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 test/e2e/app_namespace_test.go diff --git a/pkg/kapp/cmd/app/app_flags.go b/pkg/kapp/cmd/app/app_flags.go index a4ed5f7b0..3b4d6e4ed 100644 --- a/pkg/kapp/cmd/app/app_flags.go +++ b/pkg/kapp/cmd/app/app_flags.go @@ -12,10 +12,12 @@ import ( type Flags struct { NamespaceFlags cmdcore.NamespaceFlags Name string + AppNamespace string } func (s *Flags) Set(cmd *cobra.Command, flagsFactory cmdcore.FlagsFactory) { s.NamespaceFlags.Set(cmd, flagsFactory) cmd.Flags().StringVarP(&s.Name, "app", "a", s.Name, "Set app name (or label selector) (format: name, label:key=val, !key)") + cmd.Flags().StringVar(&s.AppNamespace, "app-namespace", s.AppNamespace, "Set app namespace (to store app state)") } diff --git a/pkg/kapp/cmd/app/factory.go b/pkg/kapp/cmd/app/factory.go index 474d9ce77..74687d645 100644 --- a/pkg/kapp/cmd/app/factory.go +++ b/pkg/kapp/cmd/app/factory.go @@ -18,7 +18,7 @@ type FactorySupportObjs struct { Apps ctlapp.Apps } -func FactoryClients(depsFactory cmdcore.DepsFactory, nsFlags cmdcore.NamespaceFlags, +func FactoryClients(depsFactory cmdcore.DepsFactory, appNamespace string, resTypesFlags ResourceTypesFlags, logger logger.Logger) (FactorySupportObjs, error) { coreClient, err := depsFactory.CoreClient() @@ -42,7 +42,7 @@ func FactoryClients(depsFactory cmdcore.DepsFactory, nsFlags cmdcore.NamespaceFl }) resourcesImplOpts := ctlres.ResourcesImplOpts{ - FallbackAllowedNamespaces: []string{nsFlags.Name}, + FallbackAllowedNamespaces: []string{appNamespace}, ScopeToFallbackAllowedNamespaces: resTypesFlags.ScopeToFallbackAllowedNamespaces, } @@ -56,7 +56,7 @@ func FactoryClients(depsFactory cmdcore.DepsFactory, nsFlags cmdcore.NamespaceFl CoreClient: coreClient, ResourceTypes: resTypes, IdentifiedResources: identifiedResources, - Apps: ctlapp.NewApps(nsFlags.Name, coreClient, identifiedResources, logger), + Apps: ctlapp.NewApps(appNamespace, coreClient, identifiedResources, logger), } return result, nil @@ -65,7 +65,11 @@ func FactoryClients(depsFactory cmdcore.DepsFactory, nsFlags cmdcore.NamespaceFl func Factory(depsFactory cmdcore.DepsFactory, appFlags Flags, resTypesFlags ResourceTypesFlags, logger logger.Logger) (ctlapp.App, FactorySupportObjs, error) { - supportingObjs, err := FactoryClients(depsFactory, appFlags.NamespaceFlags, resTypesFlags, logger) + if appFlags.AppNamespace == "" { + appFlags.AppNamespace = appFlags.NamespaceFlags.Name + } + + supportingObjs, err := FactoryClients(depsFactory, appFlags.AppNamespace, resTypesFlags, logger) if err != nil { return nil, FactorySupportObjs{}, err } diff --git a/pkg/kapp/cmd/app/list.go b/pkg/kapp/cmd/app/list.go index 99801a587..947733d1a 100644 --- a/pkg/kapp/cmd/app/list.go +++ b/pkg/kapp/cmd/app/list.go @@ -56,7 +56,7 @@ func (o *ListOptions) Run() error { nsHeader.Hidden = false } - supportObjs, err := FactoryClients(o.depsFactory, o.NamespaceFlags, ResourceTypesFlags{}, o.logger) + supportObjs, err := FactoryClients(o.depsFactory, o.NamespaceFlags.Name, ResourceTypesFlags{}, o.logger) if err != nil { return err } diff --git a/pkg/kapp/cmd/appgroup/delete.go b/pkg/kapp/cmd/appgroup/delete.go index c67298699..baafe6e23 100644 --- a/pkg/kapp/cmd/appgroup/delete.go +++ b/pkg/kapp/cmd/appgroup/delete.go @@ -55,7 +55,7 @@ func (o *DeleteOptions) Run() error { return fmt.Errorf("Expected group name to be non-empty") } - supportObjs, err := cmdapp.FactoryClients(o.depsFactory, o.AppGroupFlags.NamespaceFlags, cmdapp.ResourceTypesFlags{}, o.logger) + supportObjs, err := cmdapp.FactoryClients(o.depsFactory, o.AppGroupFlags.NamespaceFlags.Name, cmdapp.ResourceTypesFlags{}, o.logger) if err != nil { return err } diff --git a/pkg/kapp/cmd/appgroup/deploy.go b/pkg/kapp/cmd/appgroup/deploy.go index 3004d8943..174a4d9b4 100644 --- a/pkg/kapp/cmd/appgroup/deploy.go +++ b/pkg/kapp/cmd/appgroup/deploy.go @@ -84,7 +84,7 @@ func (o *DeployOptions) Run() error { } } - supportObjs, err := cmdapp.FactoryClients(o.depsFactory, o.AppGroupFlags.NamespaceFlags, cmdapp.ResourceTypesFlags{}, o.logger) + supportObjs, err := cmdapp.FactoryClients(o.depsFactory, o.AppGroupFlags.NamespaceFlags.Name, cmdapp.ResourceTypesFlags{}, o.logger) if err != nil { return err } diff --git a/test/e2e/app_namespace_test.go b/test/e2e/app_namespace_test.go new file mode 100644 index 000000000..6cd9dcf7a --- /dev/null +++ b/test/e2e/app_namespace_test.go @@ -0,0 +1,71 @@ +// Copyright 2023 VMware, Inc. +// SPDX-License-Identifier: Apache-2.0 + +package e2e + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestAppNamespace(t *testing.T) { + env := BuildEnv(t) + logger := Logger{} + kapp := Kapp{t, env.Namespace, env.KappBinaryPath, logger} + kubectl := Kubectl{t, env.Namespace, logger} + + name := "test-app-namespace" + + cleanUp := func() { + kapp.Run([]string{"delete", "-a", name}) + } + + cleanUp() + defer cleanUp() + + yaml := ` +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: test-cm +` + + logger.Section("deploy app with -n flag", func() { + kapp.RunWithOpts([]string{"deploy", "-f", "-", "-a", name, "-n", env.Namespace}, RunOpts{NoNamespace: true, StdinReader: strings.NewReader(yaml)}) + + // both app meta configmap and the resources should be present in the -n namespace + NewPresentClusterResource("configmap", name, env.Namespace, kubectl) + NewPresentClusterResource("configmap", "test-cm", env.Namespace, kubectl) + }) + + logger.Section("deploy same app with both -n and --app-namespace flag", func() { + _, err := kapp.RunWithOpts([]string{"deploy", "-f", "-", "-a", name, "-n", env.Namespace, "--app-namespace", env.Namespace, "--diff-run", "--diff-exit-status"}, + RunOpts{NoNamespace: true, AllowError: true, StdinReader: strings.NewReader(yaml)}) + + require.Errorf(t, err, "Expected to receive error") + + require.Containsf(t, err.Error(), "Exiting after diffing with no pending changes (exit status 2)", "Expected to find stderr output") + require.Containsf(t, err.Error(), "exit code: '2'", "Expected to find exit code") + }) + + logger.Section("deploy same app with --app-namespace flag only", func() { + _, err := kapp.RunWithOpts([]string{"deploy", "-f", "-", "-a", name, "--app-namespace", env.Namespace, "--diff-run", "--diff-exit-status"}, + RunOpts{NoNamespace: true, AllowError: true, StdinReader: strings.NewReader(yaml)}) + + require.Errorf(t, err, "Expected to receive error") + // Resources would get created in the default namespace from kubeconfig since -n is not provided + require.Containsf(t, err.Error(), "Exiting after diffing with pending changes (exit status 3)", "Expected to find stderr output") + require.Containsf(t, err.Error(), "exit code: '3'", "Expected to find exit code") + }) + + logger.Section("delete app with --app-namespace flag only", func() { + kapp.RunWithOpts([]string{"delete", "-a", name, "--app-namespace", env.Namespace}, + RunOpts{NoNamespace: true}) + + NewMissingClusterResource(t, "configmap", name, env.Namespace, kubectl) + NewMissingClusterResource(t, "configmap", "test-cm", env.Namespace, kubectl) + }) +}