From b1deef064723ef31c656e36420dc8c2eaec903ba Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Sun, 19 Nov 2023 15:15:19 +0200 Subject: [PATCH] Enforce cluster selection for `bundle build` cmd Signed-off-by: Stefan Prodan --- cmd/timoni/bundle.go | 2 +- cmd/timoni/bundle_build.go | 12 +++++ cmd/timoni/bundle_build_test.go | 79 ++++++++++++++++++++++++++++++++- 3 files changed, 91 insertions(+), 2 deletions(-) diff --git a/cmd/timoni/bundle.go b/cmd/timoni/bundle.go index 006f65fd..f92c1dd0 100644 --- a/cmd/timoni/bundle.go +++ b/cmd/timoni/bundle.go @@ -41,7 +41,7 @@ func init() { "The local path to runtime.cue files.") bundleCmd.PersistentFlags().StringVar(&bundleArgs.runtimeCluster, "runtime-cluster", "*", "Filter runtime cluster by name.") - bundleCmd.PersistentFlags().StringVar(&bundleArgs.runtimeCluster, "runtime-group", "*", + bundleCmd.PersistentFlags().StringVar(&bundleArgs.runtimeClusterGroup, "runtime-group", "*", "Filter runtime clusters by group.") rootCmd.AddCommand(bundleCmd) } diff --git a/cmd/timoni/bundle_build.go b/cmd/timoni/bundle_build.go index 5efa5110..3276959c 100644 --- a/cmd/timoni/bundle_build.go +++ b/cmd/timoni/bundle_build.go @@ -114,6 +114,17 @@ func runBundleBuildCmd(cmd *cobra.Command, _ []string) error { return err } + clusters := rt.SelectClusters(bundleArgs.runtimeCluster, bundleArgs.runtimeClusterGroup) + if len(clusters) > 1 { + return fmt.Errorf("you must select a cluster with --runtime-cluster") + } + if len(clusters) == 0 { + return fmt.Errorf("no cluster found") + } + + cluster := clusters[0] + kubeconfigArgs.Context = &cluster.KubeContext + rm, err := runtime.NewResourceManager(kubeconfigArgs) if err != nil { return err @@ -126,6 +137,7 @@ func runBundleBuildCmd(cmd *cobra.Command, _ []string) error { } maps.Copy(runtimeValues, rv) + maps.Copy(runtimeValues, cluster.NameGroupValues()) } if err := bm.InitWorkspace(tmpDir, runtimeValues); err != nil { diff --git a/cmd/timoni/bundle_build_test.go b/cmd/timoni/bundle_build_test.go index 87586a76..aca6ddf8 100644 --- a/cmd/timoni/bundle_build_test.go +++ b/cmd/timoni/bundle_build_test.go @@ -135,12 +135,89 @@ bundle: g.Expect(err).ToNot(HaveOccurred()) g.Expect(found).To(BeTrue()) g.Expect(host).To(ContainSubstring("example.internal")) - }) } }) } +func Test_BundleBuild_Runtime(t *testing.T) { + g := NewWithT(t) + + bundleName := rnd("my-bundle", 5) + modPath := "testdata/module" + namespace := rnd("my-namespace", 5) + modName := rnd("my-mod", 5) + modURL := fmt.Sprintf("%s/%s", dockerRegistry, modName) + modVer := "1.0.0" + + _, err := executeCommand(fmt.Sprintf( + "mod push %s oci://%s -v %s", + modPath, + modURL, + modVer, + )) + g.Expect(err).ToNot(HaveOccurred()) + + bundleData := fmt.Sprintf(` +bundle: { + _cluster: string @timoni(runtime:string:TIMONI_CLUSTER_NAME) + + apiVersion: "v1alpha1" + name: "%[1]s" + instances: { + "\(_cluster)-app": { + module: { + url: "oci://%[2]s" + version: "%[3]s" + } + namespace: "%[4]s" + } + } +} +`, bundleName, modURL, modVer, namespace) + + runtimeCue := ` +runtime: { + apiVersion: "v1alpha1" + name: "fleet-test" + clusters: { + "staging": { + group: "staging" + kubeContext: "envtest" + } + "production": { + group: "production" + kubeContext: "envtest" + } + } + values: [] +} +` + + runtimePath := filepath.Join(t.TempDir(), "runtime.cue") + g.Expect(os.WriteFile(runtimePath, []byte(runtimeCue), 0644)).ToNot(HaveOccurred()) + + t.Run("fails for multiple clusters", func(t *testing.T) { + g := NewWithT(t) + _, err = executeCommandWithIn( + fmt.Sprintf("bundle build -f- -r %s -p main", runtimePath), + strings.NewReader(bundleData)) + g.Expect(err).To(HaveOccurred()) + g.Expect(err.Error()).To(ContainSubstring("select a cluster")) + }) + + t.Run("builds for a single cluster", func(t *testing.T) { + g := NewWithT(t) + + output, err := executeCommandWithIn( + fmt.Sprintf("bundle build -f- -r %s -p main --runtime-group=production", runtimePath), + strings.NewReader(bundleData)) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(output).ToNot(ContainSubstring("staging-app")) + g.Expect(output).To(ContainSubstring("production-app")) + }) +} + func getObjectByName(objs []*unstructured.Unstructured, name string) (*unstructured.Unstructured, error) { for _, obj := range objs { if obj.GetName() == name {