Skip to content

Commit

Permalink
refactor(cli): install cmd and update cmd (#666)
Browse files Browse the repository at this point in the history
* refactor(cli): install and update cmd

* make lint

* add license
  • Loading branch information
lizzy-0323 authored Dec 15, 2024
1 parent 419a4f8 commit f3bb57f
Show file tree
Hide file tree
Showing 9 changed files with 264 additions and 137 deletions.
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ require (
github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.18.2
github.com/stretchr/testify v1.9.0
github.com/swaggo/files v1.0.1
github.com/swaggo/gin-swagger v1.6.0
github.com/swaggo/swag v1.16.3
Expand All @@ -46,7 +47,7 @@ require (
k8s.io/apimachinery v0.29.3
k8s.io/client-go v0.29.3
k8s.io/kubernetes v1.27.2
k8s.io/metrics v0.0.0
k8s.io/metrics v0.29.3
sigs.k8s.io/controller-runtime v0.15.0
)

Expand Down Expand Up @@ -144,7 +145,6 @@ require (
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/stretchr/testify v1.9.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
Expand Down
7 changes: 3 additions & 4 deletions internal/cli/cmd/install/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,12 @@ import (
"github.com/oceanbase/ob-operator/internal/cli/utils"
)

var componentList = []string{"ob-operator", "ob-dashboard", "local-path-provisioner", "cert-manager", "local-path-provisioner-dev", "ob-operator-dev"}

// NewCmd install the ob-operator and other components
func NewCmd() *cobra.Command {
o := install.NewInstallOptions()
logger := utils.GetDefaultLoggerInstance()
componentList := []string{}
for component := range o.Components {
componentList = append(componentList, component)
}
cmd := &cobra.Command{
Use: "install <component>",
Short: "Command for ob-operator and other components installation",
Expand All @@ -48,6 +46,7 @@ if not specified, install ob-operator and ob-dashboard by default, and cert-mana
logger.Println("Install ob-operator and ob-dashboard by default")
}
for component, version := range o.Components {
logger.Printf("Installing component %s, version %s\n", component, version)
if err := o.Install(component, version); err != nil {
logger.Fatalln(err)
} else {
Expand Down
16 changes: 8 additions & 8 deletions internal/cli/cmd/update/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,12 @@ import (
"github.com/oceanbase/ob-operator/internal/cli/utils"
)

var componentList = []string{"ob-operator", "ob-dashboard", "local-path-provisioner", "cert-manager"}

// NewCmd update the ob-operator and other components
func NewCmd() *cobra.Command {
o := update.NewUpdateOptions()
logger := utils.GetDefaultLoggerInstance()
componentList := []string{}
for component := range o.Components {
componentList = append(componentList, component)
}
cmd := &cobra.Command{
Use: "update <component>",
Short: "Command for ob-operator and other components update",
Expand All @@ -40,15 +38,17 @@ Currently support:
- 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, update ob-operator and ob-dashboard by default`,
PreRunE: o.Parse,
ValidArgs: componentList,
Args: cobra.MatchAll(cobra.MaximumNArgs(1), cobra.OnlyValidArgs),
PreRunE: o.Parse,
ValidArgs: componentList,
DisableFlagsInUseLine: true,
Args: cobra.MatchAll(cobra.MaximumNArgs(1), cobra.OnlyValidArgs),
Run: func(cmd *cobra.Command, args []string) {
componentCount := 0
for component, version := range o.Components {
if utils.CheckIfComponentExists(component) {
componentCount++
if err := o.Install(component, version); err != nil {
logger.Printf("Updating component %s, version %s\n", component, version)
if err := o.Update(component, version); err != nil {
logger.Fatalln(err)
} else {
logger.Printf("%s update successfully\n", component)
Expand Down
30 changes: 26 additions & 4 deletions internal/cli/utils/conf.go → internal/cli/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
package utils
package config

import (
"bytes"
Expand All @@ -20,14 +20,15 @@ import (
"github.com/spf13/viper"

"github.com/oceanbase/ob-operator/internal/cli/generated/bindata"
"github.com/oceanbase/ob-operator/internal/cli/utils"
)

// component config for test
var component_conf = "internal/assets/cli-templates/component_config.yaml"
var confPath = "internal/assets/cli-templates/component_config.yaml"

func GetComponentsConf() map[string]string {
func readComponentConf(path string) map[string]string {
components := make(map[string]string)
fileobj, err := bindata.Asset(component_conf)
fileobj, err := bindata.Asset(path)
// panic if file not exists
if err != nil {
panic(fmt.Errorf("Error reading component config file: %v", err))
Expand All @@ -42,3 +43,24 @@ func GetComponentsConf() map[string]string {
}
return components
}

// GetAllComponents returns all the components
func GetAllComponents() map[string]string {
return readComponentConf(confPath)
}

// GetDefaultComponents returns the default components to be installed
func GetDefaultComponents() map[string]string {
var componentsList []string
components := GetAllComponents()
defaultComponents := make(map[string]string) // Initialize the map
if !utils.CheckIfComponentExists("cert-manager") {
componentsList = []string{"cert-manager", "ob-operator", "ob-dashboard"}
} else {
componentsList = []string{"ob-operator", "ob-dashboard"}
}
for _, component := range componentsList {
defaultComponents[component] = components[component]
}
return defaultComponents
}
130 changes: 27 additions & 103 deletions internal/cli/install/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,135 +15,59 @@ package install

import (
"fmt"
"os"
"os/exec"

"github.com/spf13/cobra"

"github.com/oceanbase/ob-operator/internal/cli/config"
utils "github.com/oceanbase/ob-operator/internal/cli/utils"
)

type InstallOptions struct {
version string
Components map[string]string
obUrl string
localPathUrl string
version string
Components map[string]string
}

// NewInstallOptions create a new InstallOptions
func NewInstallOptions() *InstallOptions {
return &InstallOptions{
Components: utils.GetComponentsConf(),
obUrl: "https://raw.githubusercontent.com/oceanbase/ob-operator/",
localPathUrl: "https://raw.githubusercontent.com/rancher/local-path-provisioner/",
Components: make(map[string]string),
}
}

func (o *InstallOptions) AddFlags(cmd *cobra.Command) {
cmd.Flags().StringVar(&o.version, "version", "", "version of component")
}

func (o *InstallOptions) 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 v, ok := o.Components[name]; ok {
// if specified, use the specified component
if len(args) > 0 {
name := args[0]
components := config.GetAllComponents()
// check if the component is supported
defaultVersion, exist := components[name]
if !exist {
return fmt.Errorf("component `%v` is not supported", name)
}

// if version is not specified, use the default version
if o.version == "" {
o.Components = map[string]string{name: v}
o.Components = map[string]string{name: defaultVersion}
} else {
o.Components = map[string]string{name: o.version}
}
return nil
}
return fmt.Errorf("component `%v` is not supported", name)
}

// Install component
func (o *InstallOptions) Install(component, version string) error {
cmd, err := o.buildCmd(component, version)
if err != nil {
return err
}
return runCmd(cmd)
}

// buildCmd build cmd for installation
func (o *InstallOptions) buildCmd(component, version string) (*exec.Cmd, error) {
var cmd *exec.Cmd
var url string
switch component {
case "cert-manager":
componentFile := "cert-manager.yaml"
url = fmt.Sprintf("%s%s/deploy/%s", o.obUrl, version, componentFile)
cmd = exec.Command("kubectl", "apply", "-f", url)
case "ob-operator", "ob-operator-dev":
componentFile := "operator.yaml"
url = fmt.Sprintf("%s%s/deploy/%s", o.obUrl, version, componentFile)
cmd = exec.Command("kubectl", "apply", "-f", url)
case "local-path-provisioner", "local-path-provisioner-dev":
componentFile := "local-path-storage.yaml"
url = fmt.Sprintf("%s%s/deploy/%s", o.localPathUrl, version, componentFile)
cmd = exec.Command("kubectl", "apply", "-f", url)
case "ob-dashboard":
if err := addHelmRepo(); err != nil {
return nil, err
}
if err := updateHelmRepo(); err != nil {
return nil, err
}
versionFlag := fmt.Sprintf("--version=%s", version)
cmd = exec.Command("helm", "install", "oceanbase-dashboard", "ob-operator/oceanbase-dashboard", versionFlag)
default:
return nil, fmt.Errorf("unknown component: %s", component)
}
return cmd, nil
}

func (o *InstallOptions) GetDefaultComponents() map[string]string {
defaultComponents := make(map[string]string) // Initialize the map
var componentsList []string
if !utils.CheckIfComponentExists("cert-manager") {
componentsList = []string{"cert-manager", "ob-operator", "ob-dashboard"}
} else {
componentsList = []string{"ob-operator", "ob-dashboard"}
}
for _, component := range componentsList {
defaultComponents[component] = o.Components[component]
}
return defaultComponents
}

// addHelmRepo add ob-operator helm repo
func addHelmRepo() error {
cmdAddRepo := exec.Command("helm", "repo", "add", "ob-operator", "https://oceanbase.github.io/ob-operator/")
output, err := cmdAddRepo.CombinedOutput()
if err != nil {
return fmt.Errorf("adding repo failed: %s, %s", err, output)
// if no component is specified, install default components
defaultComponents := config.GetDefaultComponents()
o.Components = defaultComponents
}
return nil
}

// updateHelmRepo update ob-operator helm repo
func updateHelmRepo() error {
cmdUpdateRepo := exec.Command("helm", "repo", "update")
output, err := cmdUpdateRepo.CombinedOutput()
func (o *InstallOptions) Install(component, version string) error {
cmd, err := utils.BuildCmd(component, version)
if err != nil {
return fmt.Errorf("updating repo failed: %s, %s", err, output)
return err
}
return nil
return utils.RunCmd(cmd)
}

// runCmd run cmd for components' installation
func runCmd(cmd *exec.Cmd) error {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
return fmt.Errorf("%s command failed with error: %v", cmd.String(), err)
}
return nil
// AddFlags add flags to install command
func (o *InstallOptions) AddFlags(cmd *cobra.Command) {
cmd.Flags().StringVar(&o.version, "version", "", "version of component")
}
43 changes: 29 additions & 14 deletions internal/cli/update/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,46 @@ import (

"github.com/spf13/cobra"

"github.com/oceanbase/ob-operator/internal/cli/install"
"github.com/oceanbase/ob-operator/internal/cli/config"
"github.com/oceanbase/ob-operator/internal/cli/utils"
)

type UpdateOptions struct {
install.InstallOptions
Components map[string]string
}

// NewUpdateOptions create a new UpdateOptions
func NewUpdateOptions() *UpdateOptions {
return &UpdateOptions{
InstallOptions: *install.NewInstallOptions(),
Components: make(map[string]string),
}
}

func (o *UpdateOptions) Parse(_ *cobra.Command, args []string) error {
// if not specified, use default config
if len(args) == 0 {
defaultComponents := o.InstallOptions.GetDefaultComponents()
// update Components to default config
o.InstallOptions.Components = defaultComponents
return nil
// if specified, use the specified component
if len(args) > 0 {
name := args[0]
components := config.GetAllComponents()
// check if the component is supported
defaultVersion, exist := components[name]

// check if the component is supported
if !exist {
return fmt.Errorf("component %s is not supported", name)
}
o.Components = map[string]string{name: defaultVersion}
} else {
// if no component is specified, update default components
defaultComponents := config.GetDefaultComponents()
o.Components = defaultComponents
}
name := args[0]
if v, ok := o.InstallOptions.Components[name]; ok {
o.InstallOptions.Components = map[string]string{name: v}
return nil
return nil
}

func (o *UpdateOptions) Update(component, version string) error {
cmd, err := utils.BuildCmd(component, version)
if err != nil {
return err
}
return fmt.Errorf("component %s is not supported", name)
return utils.RunCmd(cmd)
}
4 changes: 2 additions & 2 deletions internal/cli/utils/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,11 @@ func CheckIfComponentExists(component string) bool {
switch component {
case "cert-manager":
return checkIfResourceExists(certManagerCheckCmd, certManagerResources...)
case "ob-operator":
case "ob-operator", "ob-operator-dev":
return checkIfResourceExists(operatorCheckCmd, operatorResources...)
case "ob-dashboard":
return checkIfResourceExists(dashboardCheckCmd, dashboardResources)
case "local-path-provisioner":
case "local-path-provisioner", "local-path-provisioner-dev":
return checkIfResourceExists(localPathProvisionerCheckCmd, localPathProvisionerResources)
default:
return false
Expand Down
Loading

0 comments on commit f3bb57f

Please sign in to comment.