From f5f5ff514f6b8138e751f4e434d9b504d0238468 Mon Sep 17 00:00:00 2001 From: wyike Date: Mon, 13 Dec 2021 19:47:32 +0800 Subject: [PATCH] Feat: cli manage addon registry and apiserver addon status return app status info (#2910) * Fix: cli add addon registry add more detail info for addon workflow info Signed-off-by: wangyike * fix: set app status in addon status directly Signed-off-by: wangyike * add e2e test Signed-off-by: wangyike --- e2e/addon/addon_test.go | 36 ++++ pkg/addon/registry.go | 3 + pkg/apiserver/rest/apis/v1/types.go | 1 + pkg/apiserver/rest/usecase/addon.go | 4 +- references/cli/addon-registry.go | 303 ++++++++++++++++++++++++++++ references/cli/addon.go | 1 + 6 files changed, 347 insertions(+), 1 deletion(-) create mode 100644 references/cli/addon-registry.go diff --git a/e2e/addon/addon_test.go b/e2e/addon/addon_test.go index e4ce1cf21..d1f8db1da 100644 --- a/e2e/addon/addon_test.go +++ b/e2e/addon/addon_test.go @@ -19,6 +19,7 @@ package e2e import ( "context" "encoding/xml" + "fmt" "net/http" "os" "path" @@ -116,6 +117,41 @@ var _ = Describe("Addon Test", func() { }) }) + + Context("Addon registry test", func() { + It("List all addon registry", func() { + output, err := e2e.Exec("vela addon registry list") + Expect(err).NotTo(HaveOccurred()) + Expect(output).To(ContainSubstring("KubeVela")) + }) + + It("Get addon registry", func() { + output, err := e2e.Exec("vela addon registry get KubeVela") + Expect(err).NotTo(HaveOccurred()) + Expect(output).To(ContainSubstring("KubeVela")) + }) + + It("Add test addon registry", func() { + output, err := e2e.LongTimeExec("vela addon registry add my-repo --type=git --gitUrl=https://github.com/oam-dev/catalog --path=/experimental/addons", 600*time.Second) + Expect(err).NotTo(HaveOccurred()) + Expect(output).To(ContainSubstring("Successfully add an addon registry my-repo")) + + Eventually(func() error { + output, err := e2e.LongTimeExec("vela addon registry update my-repo --type=git --gitUrl=https://github.com/oam-dev/catalog --path=/addons", 300*time.Second) + if err != nil { + return err + } + if !strings.Contains(output, "Successfully update an addon registry my-repo") { + return fmt.Errorf("cannot update addon registry") + } + return nil + }, 30*time.Second, 300*time.Millisecond).Should(BeNil()) + + output, err = e2e.LongTimeExec("vela addon registry delete my-repo", 600*time.Second) + Expect(err).NotTo(HaveOccurred()) + Expect(output).To(ContainSubstring("Successfully delete an addon registry my-repo")) + }) + }) }) var velaRegistry = ` diff --git a/pkg/addon/registry.go b/pkg/addon/registry.go index ac56b22f0..84cad292a 100644 --- a/pkg/addon/registry.go +++ b/pkg/addon/registry.go @@ -157,6 +157,9 @@ func (r registryImpl) UpdateRegistry(ctx context.Context, registry Registry) err if err := json.Unmarshal([]byte(cm.Data[registriesKey]), ®istries); err != nil { return err } + if _, ok := registries[registry.Name]; !ok { + return fmt.Errorf("addon registry %s not exist", registry.Name) + } registries[registry.Name] = registry b, err := json.Marshal(registries) if err != nil { diff --git a/pkg/apiserver/rest/apis/v1/types.go b/pkg/apiserver/rest/apis/v1/types.go index 9c882ae40..fed33cd10 100644 --- a/pkg/apiserver/rest/apis/v1/types.go +++ b/pkg/apiserver/rest/apis/v1/types.go @@ -132,6 +132,7 @@ type AddonStatusResponse struct { Args map[string]string `json:"args"` EnablingProgress *EnablingProgress `json:"enabling_progress,omitempty"` + AppStatus common.AppStatus `json:"appStatus,omitempty"` } // EnablingProgress defines the progress of enabling an addon diff --git a/pkg/apiserver/rest/usecase/addon.go b/pkg/apiserver/rest/usecase/addon.go index 15d8a1e9b..511ae52cf 100644 --- a/pkg/apiserver/rest/usecase/addon.go +++ b/pkg/apiserver/rest/usecase/addon.go @@ -178,6 +178,9 @@ func (u *addonUsecaseImpl) StatusAddon(ctx context.Context, name string) (*apis. Phase: convertAppStateToAddonPhase(app.Status.Phase), EnablingProgress: nil, } + + res.AppStatus = app.Status + if res.Phase != apis.AddonPhaseEnabled { return &res, nil } @@ -195,7 +198,6 @@ func (u *addonUsecaseImpl) StatusAddon(ctx context.Context, name string) (*apis. } } - return &res, nil } diff --git a/references/cli/addon-registry.go b/references/cli/addon-registry.go new file mode 100644 index 000000000..4d629604b --- /dev/null +++ b/references/cli/addon-registry.go @@ -0,0 +1,303 @@ +/* +Copyright 2021 The KubeVela Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cli + +import ( + "context" + "fmt" + "net/url" + + "github.com/gosuri/uitable" + "github.com/pkg/errors" + "github.com/spf13/cobra" + + pkgaddon "github.com/oam-dev/kubevela/pkg/addon" + "github.com/oam-dev/kubevela/pkg/utils/common" + cmdutil "github.com/oam-dev/kubevela/pkg/utils/util" +) + +const ( + addonRegistryType = "type" + addonOssEndpoint = "ossEndpoint" + addonOssBucket = "ossBucket" + addonGitURL = "gitUrl" + addonPath = "path" + addonGitToken = "gitToken" + addonOssType = "oss" + addonGitType = "git" +) + +// NewAddonRegistryCommand return an addon registry command +func NewAddonRegistryCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command { + cmd := &cobra.Command{ + Use: "registry", + Short: "Manage addon registry in KubeVela", + Long: "Manage addon registry in KubeVela", + } + cmd.AddCommand( + NewAddAddonRegistryCommand(c, ioStreams), + NewListAddonRegistryCommand(c, ioStreams), + NewUpdateAddonRegistryCommand(c, ioStreams), + NewDeleteAddonRegistryCommand(c, ioStreams), + NewGetAddonRegistryCommand(c, ioStreams), + ) + return cmd +} + +// NewAddAddonRegistryCommand return an addon registry create command +func NewAddAddonRegistryCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command { + cmd := &cobra.Command{ + Use: "add", + Short: "Add an addon registry in KubeVela", + Long: "Add an addon registry in KubeVela", + Example: "vela addon registry add my-repo --type oss --ossEndpoint=xxxxx --ossBucket=xxxx", + RunE: func(cmd *cobra.Command, args []string) error { + registry, err := getRegistryFromArgs(cmd, args) + if err != nil { + return err + } + if err := addAddonRegistry(context.Background(), *registry); err != nil { + return err + } + return nil + }, + } + parseArgsFromFlag(cmd) + return cmd +} + +// NewGetAddonRegistryCommand return an addon registry get command +func NewGetAddonRegistryCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command { + return &cobra.Command{ + Use: "get", + Short: "Get an addon registry in KubeVela", + Long: "Get an addon registry in KubeVela", + Example: "vela addon registry get my-repo ", + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) != 1 { + return errors.New("must specify the registry name") + } + name := args[0] + err := getAddonRegistry(context.Background(), name) + if err != nil { + return err + } + return nil + }, + } +} + +// NewListAddonRegistryCommand return an addon registry list command +func NewListAddonRegistryCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command { + return &cobra.Command{ + Use: "list", + Short: "List addon registries in KubeVela", + Long: "List addon registries in KubeVela", + Example: "vela addon registry list", + RunE: func(cmd *cobra.Command, args []string) error { + if err := listAddonRegistry(context.Background()); err != nil { + return err + } + return nil + }, + } +} + +// NewUpdateAddonRegistryCommand return an addon registry update command +func NewUpdateAddonRegistryCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command { + cmd := &cobra.Command{ + Use: "update", + Short: "Update an addon registry in KubeVela", + Long: "Update an addon registry in KubeVela", + Example: "vela addon registry update my-repo --type oss --ossEndpoint=xxxxx --ossBucket=xxxx", + RunE: func(cmd *cobra.Command, args []string) error { + registry, err := getRegistryFromArgs(cmd, args) + if err != nil { + return err + } + if err := updateAddonRegistry(context.Background(), *registry); err != nil { + return err + } + return nil + }, + } + parseArgsFromFlag(cmd) + return cmd +} + +// NewDeleteAddonRegistryCommand return an addon registry delete command +func NewDeleteAddonRegistryCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command { + return &cobra.Command{ + Use: "delete", + Short: "Delete an addon registry in KubeVela", + Long: "Delete an addon registry in KubeVela", + Example: "vela addon registry delete my-repo ", + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) != 1 { + return errors.New("must specify the registry name") + } + name := args[0] + err := deleteAddonRegistry(context.Background(), name) + if err != nil { + return err + } + return nil + }, + } +} + +func listAddonRegistry(ctx context.Context) error { + ds := pkgaddon.NewRegistryDataStore(clt) + registries, err := ds.ListRegistries(ctx) + if err != nil { + return err + } + table := uitable.New() + table.AddRow("Name", "Type", "URL") + for _, registry := range registries { + var repoType, repoURL string + if registry.Oss != nil { + repoType = "Oss" + u, err := url.Parse(registry.Oss.EndPoint) + if err != nil { + continue + } + if registry.Oss.Bucket == "" { + repoURL = u.String() + } else { + if u.Scheme == "" { + u.Scheme = "https" + } + repoURL = fmt.Sprintf("%s://%s.%s", u.Scheme, registry.Oss.Bucket, u.Host) + } + } else { + repoType = "Git" + repoURL = fmt.Sprintf("%s/tree/master/%s", registry.Git.URL, registry.Git.Path) + } + table.AddRow(registry.Name, repoType, repoURL) + } + fmt.Println(table.String()) + return nil +} + +func getAddonRegistry(ctx context.Context, name string) error { + ds := pkgaddon.NewRegistryDataStore(clt) + registry, err := ds.GetRegistry(ctx, name) + if err != nil { + return err + } + table := uitable.New() + if registry.Oss != nil { + table.AddRow("NAME", "ENDPOINT", "BUCKET") + table.AddRow(registry.Name, registry.Oss.EndPoint, registry.Oss.Bucket) + } else { + table.AddRow("NAME", "URL", "PATH") + table.AddRow(registry.Name, registry.Git.URL, registry.Git.Path) + } + fmt.Println(table.String()) + return nil +} + +func deleteAddonRegistry(ctx context.Context, name string) error { + ds := pkgaddon.NewRegistryDataStore(clt) + if err := ds.DeleteRegistry(ctx, name); err != nil { + return err + } + fmt.Printf("Successfully delete an addon registry %s \n", name) + return nil +} + +func addAddonRegistry(ctx context.Context, registry pkgaddon.Registry) error { + ds := pkgaddon.NewRegistryDataStore(clt) + if err := ds.AddRegistry(ctx, registry); err != nil { + return err + } + fmt.Printf("Successfully add an addon registry %s \n", registry.Name) + return nil +} + +func updateAddonRegistry(ctx context.Context, registry pkgaddon.Registry) error { + ds := pkgaddon.NewRegistryDataStore(clt) + if err := ds.UpdateRegistry(ctx, registry); err != nil { + return err + } + fmt.Printf("Successfully update an addon registry %s \n", registry.Name) + return nil +} + +func parseArgsFromFlag(cmd *cobra.Command) { + cmd.Flags().StringP(addonRegistryType, "", "", "specify the addon registry type") + cmd.Flags().StringP(addonOssEndpoint, "", "", "specify the oss endpoint") + cmd.Flags().StringP(addonOssBucket, "", "", "specify the oss bucket") + cmd.Flags().StringP(addonGitURL, "", "", "specify the git repo url") + cmd.Flags().StringP(addonPath, "", "", "specify the repo path") + cmd.Flags().StringP(addonGitToken, "", "", "specify the github repo token") +} + +func getRegistryFromArgs(cmd *cobra.Command, args []string) (*pkgaddon.Registry, error) { + r := &pkgaddon.Registry{} + if len(args) != 1 { + return nil, errors.New("must specify the registry name") + } + r.Name = args[0] + + registryType, err := cmd.Flags().GetString(addonRegistryType) + if err != nil { + return nil, err + } + + switch registryType { + case addonOssType: + r.Oss = &pkgaddon.OSSAddonSource{} + endpoint, err := cmd.Flags().GetString(addonOssEndpoint) + if err != nil { + return nil, err + } + if endpoint == "" { + return nil, errors.New("oss type registry must set --ossEndpoint") + } + r.Oss.EndPoint = endpoint + bucket, err := cmd.Flags().GetString(addonOssBucket) + if err != nil { + return nil, err + } + r.Oss.Bucket = bucket + case addonGitType: + r.Git = &pkgaddon.GitAddonSource{} + gitURL, err := cmd.Flags().GetString(addonGitURL) + if err != nil { + return nil, err + } + if gitURL == "" { + return nil, errors.New("oss type registry must set --gitUrl") + } + r.Git.URL = gitURL + path, err := cmd.Flags().GetString(addonPath) + if err != nil { + return nil, err + } + r.Git.Path = path + token, err := cmd.Flags().GetString(addonGitToken) + if err != nil { + return nil, err + } + r.Git.Token = token + default: + return nil, errors.New("not support addon registry type") + } + return r, nil +} diff --git a/references/cli/addon.go b/references/cli/addon.go index 9aab2baa4..511e0f5f1 100644 --- a/references/cli/addon.go +++ b/references/cli/addon.go @@ -99,6 +99,7 @@ func NewAddonCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command NewAddonEnableCommand(c, ioStreams), NewAddonDisableCommand(ioStreams), NewAddonStatusCommand(ioStreams), + NewAddonRegistryCommand(c, ioStreams), ) return cmd }