From 5d37b30e669278a99a3c173cf109b3fe8659a396 Mon Sep 17 00:00:00 2001 From: lzy <674194901@qq.com> Date: Mon, 18 Nov 2024 15:50:16 +0800 Subject: [PATCH] fix: check if resource exists in `update` cmd --- internal/cli/cmd/install/install.go | 8 ++-- internal/cli/cmd/update/update.go | 22 +++++---- internal/cli/install/install.go | 36 ++------------- internal/cli/update/update.go | 11 +++-- internal/cli/utils/checker.go | 72 +++++++++++++++++++++++++++++ 5 files changed, 101 insertions(+), 48 deletions(-) diff --git a/internal/cli/cmd/install/install.go b/internal/cli/cmd/install/install.go index ffd09e063..5b2c24a1c 100644 --- a/internal/cli/cmd/install/install.go +++ b/internal/cli/cmd/install/install.go @@ -26,8 +26,8 @@ func NewCmd() *cobra.Command { logger := utils.GetDefaultLoggerInstance() cmd := &cobra.Command{ Use: "install ", - Short: "Command for ob-operator and components installation", - Long: `Command for ob-operator and components installation. + Short: "Command for ob-operator and other components installation", + Long: `Command for ob-operator and other components installation. Currently support: - ob-operator: A Kubernetes operator that simplifies the deployment and management of OceanBase cluster and related resources on Kubernetes. @@ -35,7 +35,7 @@ Currently support: - local-path-provisioner: Provides a way for the Kubernetes users to utilize the local storage in each node, Storage of OceanBase cluster relies on it, which should be installed beforehand. - cert-manager: Creates TLS certificates for workloads in Kubernetes and renews the certificates before they expire, ob-operator relies on it for certificate management, which should be installed beforehand. -if not specified, install ob-operator and ob-dashboard by default`, +if not specified, install ob-operator and ob-dashboard by default, and cert-manager if it is not found in cluster.`, PreRunE: o.Parse, Args: cobra.MaximumNArgs(1), Run: func(cmd *cobra.Command, args []string) { @@ -46,7 +46,7 @@ if not specified, install ob-operator and ob-dashboard by default`, if err := o.Install(component, version); err != nil { logger.Fatalln(err) } else { - logger.Printf("%s install successfully", component) + logger.Printf("%s install successfully\n", component) } } }, diff --git a/internal/cli/cmd/update/update.go b/internal/cli/cmd/update/update.go index 2c00c317b..64dd487f8 100644 --- a/internal/cli/cmd/update/update.go +++ b/internal/cli/cmd/update/update.go @@ -26,8 +26,8 @@ func NewCmd() *cobra.Command { logger := utils.GetDefaultLoggerInstance() cmd := &cobra.Command{ Use: "update ", - Short: "Command for ob-operator and components update", - Long: `Command for ob-operator and components update. + Short: "Command for ob-operator and other components update", + Long: `Command for ob-operator and other components update. Currently support: - ob-operator: A Kubernetes operator that simplifies the deployment and management of OceanBase cluster and related resources on Kubernetes. @@ -39,16 +39,22 @@ if not specified, update ob-operator and ob-dashboard by default`, PreRunE: o.Parse, Args: cobra.MaximumNArgs(1), Run: func(cmd *cobra.Command, args []string) { - if len(args) == 0 { - logger.Println("update ob-operator and ob-dashboard by default") - } + componentCount := 0 for component, version := range o.Components { - if err := o.Install(component, version); err != nil { - logger.Fatalln(err) + if utils.CheckIfComponentExists(component) { + componentCount++ + if err := o.Install(component, version); err != nil { + logger.Fatalln(err) + } else { + logger.Printf("%s update successfully\n", component) + } } else { - logger.Printf("%s update successfully", component) + logger.Printf("Component %s is not found\n", component) } } + if componentCount == 0 { + logger.Println("No components to update") + } }, } return cmd diff --git a/internal/cli/install/install.go b/internal/cli/install/install.go index 998d8b8ed..920565fd4 100644 --- a/internal/cli/install/install.go +++ b/internal/cli/install/install.go @@ -14,7 +14,6 @@ See the Mulan PSL v2 for more details. package install import ( - "bytes" "fmt" "os" "os/exec" @@ -46,7 +45,7 @@ func (o *InstallOptions) AddFlags(cmd *cobra.Command) { func (o *InstallOptions) Parse(_ *cobra.Command, args []string) error { // if not specified, use default config if len(args) == 0 { - defaultComponents := o.getDefaultComponents() + defaultComponents := o.GetDefaultComponents() // update Components to default config o.Components = defaultComponents return nil @@ -104,39 +103,10 @@ func (o *InstallOptions) buildCmd(component, version string) (*exec.Cmd, error) return cmd, nil } -// checkCertManager checks cert-manager in the environment -func checkCertManager() bool { - cmd := exec.Command("kubectl", "get", "crds", "-o", "name", "|", "grep", "cert-manager") - var out bytes.Buffer - cmd.Stdout = &out - err := cmd.Run() - if err != nil { - return false - } - - // Check if the output contains cert-manager resources - expectedResources := []string{ - "challenges.acme.cert-manager.io", - "orders.acme.cert-manager.io", - "certificaterequests.cert-manager.io", - "certificates.cert-manager.io", - "clusterissuers.cert-manager.io", - "issuers.cert-manager.io", - } - - for _, resource := range expectedResources { - if !bytes.Contains(out.Bytes(), []byte(resource)) { - return false - } - } - - return true -} - -func (o *InstallOptions) getDefaultComponents() map[string]string { +func (o *InstallOptions) GetDefaultComponents() map[string]string { defaultComponents := make(map[string]string) // Initialize the map var componentsList []string - if !checkCertManager() { + if !utils.CheckIfComponentExists("cert-manager") { componentsList = []string{"cert-manager", "ob-operator", "ob-dashboard"} } else { componentsList = []string{"ob-operator", "ob-dashboard"} diff --git a/internal/cli/update/update.go b/internal/cli/update/update.go index f91d8721e..00d9b2928 100644 --- a/internal/cli/update/update.go +++ b/internal/cli/update/update.go @@ -32,12 +32,17 @@ func NewUpdateOptions() *UpdateOptions { } func (o *UpdateOptions) Parse(_ *cobra.Command, args []string) error { + // if not specified, use default config if len(args) == 0 { + defaultComponents := o.GetDefaultComponents() + // update Components to default config + o.Components = defaultComponents return nil } name := args[0] - if _, ok := o.Components[name]; !ok { - return fmt.Errorf("%s update not supported", name) + if v, ok := o.Components[name]; ok { + o.Components = map[string]string{name: v} + return nil } - return nil + return fmt.Errorf("component %s is not supported", name) } diff --git a/internal/cli/utils/checker.go b/internal/cli/utils/checker.go index eb0a833b7..33cb548ef 100644 --- a/internal/cli/utils/checker.go +++ b/internal/cli/utils/checker.go @@ -14,7 +14,9 @@ See the Mulan PSL v2 for more details. package utils import ( + "bytes" "fmt" + "os/exec" apitypes "github.com/oceanbase/ob-operator/api/types" "github.com/oceanbase/ob-operator/api/v1alpha1" @@ -22,6 +24,41 @@ import ( "github.com/oceanbase/ob-operator/internal/const/status/tenantstatus" ) +var ( + operatorCheckCmd = "kubectl get crds -A -o name | grep oceanbase.oceanbase.com" + certManagerCheckCmd = "kubectl get crds -o name | grep cert-manager" + dashboardCheckCmd = "helm list | grep oceanbase-dashboard" + localPathProvisionerCheckCmd = "kubectl get deployment -A | grep local-path-provisioner" +) + +var ( + // Define the resources to check for each command + certManagerResources = []string{ + "challenges.acme.cert-manager.io", + "orders.acme.cert-manager.io", + "certificaterequests.cert-manager.io", + "certificates.cert-manager.io", + "clusterissuers.cert-manager.io", + "issuers.cert-manager.io", + } + + operatorResources = []string{ + "obparameters.oceanbase.oceanbase.com", + "observers.oceanbase.oceanbase.com", + "obclusters.oceanbase.oceanbase.com", + "obtenantbackups.oceanbase.oceanbase.com", + "obtenantrestores.oceanbase.oceanbase.com", + "obzones.oceanbase.oceanbase.com", + "obtenants.oceanbase.oceanbase.com", + "obtenantoperations.oceanbase.oceanbase.com", + "obtenantbackuppolicies.oceanbase.oceanbase.com", + } + + dashboardResources = "oceanbase-dashboard" + + localPathProvisionerResources = "local-path-provisioner" +) + // CheckTenantStatus checks running status of obtenant func CheckTenantStatus(tenant *v1alpha1.OBTenant) error { if tenant.Status.Status != tenantstatus.Running { @@ -53,3 +90,38 @@ func CheckTenantRole(tenant *v1alpha1.OBTenant, role apitypes.TenantRole) error } return nil } + +// CheckIfComponentExists checks if component exists in the environment +func CheckIfComponentExists(component string) bool { + switch component { + case "cert-manager": + return checkIfResourceExists(certManagerCheckCmd, certManagerResources...) + case "ob-operator": + return checkIfResourceExists(operatorCheckCmd, operatorResources...) + case "ob-dashboard": + return checkIfResourceExists(dashboardCheckCmd, dashboardResources) + case "local-path-provisioner": + return checkIfResourceExists(localPathProvisionerCheckCmd, localPathProvisionerResources) + default: + return false + } +} + +// checkIfResourceExists checks if the resource exists in the environment +func checkIfResourceExists(checkCmd string, resourceList ...string) bool { + cmd := exec.Command("sh", "-c", checkCmd) + var out bytes.Buffer + cmd.Stdout = &out + err := cmd.Run() + + if err != nil { + return false + } + + for _, resource := range resourceList { + if !bytes.Contains(out.Bytes(), []byte(resource)) { + return false + } + } + return true +}