diff --git a/cli/pkg/kctrl/cmd/package/repository/add_or_update.go b/cli/pkg/kctrl/cmd/package/repository/add_or_update.go index 672500b52..559097ee7 100644 --- a/cli/pkg/kctrl/cmd/package/repository/add_or_update.go +++ b/cli/pkg/kctrl/cmd/package/repository/add_or_update.go @@ -19,6 +19,7 @@ import ( kcpkg "github.com/vmware-tanzu/carvel-kapp-controller/pkg/apis/packaging/v1alpha1" kcclient "github.com/vmware-tanzu/carvel-kapp-controller/pkg/client/clientset/versioned" versions "github.com/vmware-tanzu/carvel-vendir/pkg/vendir/versions/v1alpha1" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -33,6 +34,7 @@ type AddOrUpdateOptions struct { SecureNamespaceFlags cmdcore.SecureNamespaceFlags Name string URL string + CreateNamespace bool CreateRepository bool @@ -72,6 +74,8 @@ func NewAddCmd(o *AddOrUpdateOptions, flagsFactory cmdcore.FlagsFactory) *cobra. // TODO consider how to support other repository types cmd.Flags().StringVar(&o.URL, "url", "", "OCI registry url for package repository bundle (required)") + cmd.Flags().BoolVar(&o.CreateNamespace, "create-namespace", false, "Create the package repository namespace if not present (default false)") + o.WaitFlags.Set(cmd, flagsFactory, &cmdcore.WaitFlagsOpts{ AllowDisableWait: true, DefaultInterval: 1 * time.Second, @@ -141,6 +145,28 @@ func (o *AddOrUpdateOptions) Run(args []string) error { return err } + if o.CreateNamespace { + coreClient, err := o.depsFactory.CoreClient() + if err != nil { + return err + } + + namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: o.NamespaceFlags.Name, + }, + } + + _, err = coreClient.CoreV1().Namespaces().Create(context.Background(), namespace, metav1.CreateOptions{}) + if err != nil { + if !errors.IsAlreadyExists(err) { + return err + } + } else { + o.statusUI.PrintMessagef("Created namespace '%s'", o.NamespaceFlags.Name) + } + } + existingRepository, err := client.PackagingV1alpha1().PackageRepositories(o.NamespaceFlags.Name).Get( context.Background(), o.Name, metav1.GetOptions{}) if err != nil { @@ -162,7 +188,6 @@ func (o *AddOrUpdateOptions) Run(args []string) error { } if o.WaitFlags.Enabled { - o.ui.PrintLinef("Waiting for package repository to be updated") err = o.waitForPackageRepositoryInstallation(client) } diff --git a/cli/test/e2e/package_repository_test.go b/cli/test/e2e/package_repository_test.go index b2a05a4fb..75d5b5c61 100644 --- a/cli/test/e2e/package_repository_test.go +++ b/cli/test/e2e/package_repository_test.go @@ -20,10 +20,13 @@ func TestPackageRepository(t *testing.T) { pkgrName := "test-package-repository" pkgrURL := `index.docker.io/k8slt/kc-e2e-test-repo:latest` + newRepoNamespace := "carvel-test-repo-a" + kind := "PackageRepository" cleanUp := func() { RemoveClusterResource(t, kind, pkgrName, env.Namespace, kubectl) + RemoveClusterResource(t, kind, pkgrName, newRepoNamespace, kubectl) } cleanUp() @@ -127,4 +130,16 @@ func TestPackageRepository(t *testing.T) { require.Exactly(t, expectedOutputRows, output.Tables[0].Rows) }) + logger.Section("creating a repository in a new namespace that doesn't exist", func() { + kappCtrl.Run([]string{"package", "repository", "add", "-r", pkgrName, "--url", pkgrURL, "-n", newRepoNamespace, "--create-namespace"}) + + kubectl.Run([]string{"get", kind, pkgrName, "-n", newRepoNamespace}) + }) + + logger.Section("creating a repository in a namespace that already exists", func() { + kappCtrl.Run([]string{"package", "repository", "add", "-r", pkgrName, "--url", pkgrURL, "-n", env.Namespace, "--create-namespace"}) + + kubectl.Run([]string{"get", kind, pkgrName, "-n", env.Namespace}) + }) + }