diff --git a/cli/command/cmd.go b/cli/command/cmd.go index a1f6c19f5..ae9c60c8c 100644 --- a/cli/command/cmd.go +++ b/cli/command/cmd.go @@ -26,7 +26,6 @@ package command import ( "fmt" - "github.com/opencurve/curveadm/cli/cli" "github.com/opencurve/curveadm/cli/command/client" "github.com/opencurve/curveadm/cli/command/cluster" @@ -34,6 +33,7 @@ import ( "github.com/opencurve/curveadm/cli/command/disks" "github.com/opencurve/curveadm/cli/command/hosts" "github.com/opencurve/curveadm/cli/command/http" + "github.com/opencurve/curveadm/cli/command/install" "github.com/opencurve/curveadm/cli/command/monitor" "github.com/opencurve/curveadm/cli/command/pfs" "github.com/opencurve/curveadm/cli/command/playground" @@ -72,6 +72,7 @@ func addSubCommands(cmd *cobra.Command, curveadm *cli.CurveAdm) { monitor.NewMonitorCommand(curveadm), // curveadm monitor ... http.NewHttpCommand(curveadm), // curveadm http website.NewWebsiteCommand(curveadm), // curveadm website ... + install.NewInstallCommand(curveadm), // curveadm install NewAuditCommand(curveadm), // curveadm audit NewCleanCommand(curveadm), // curveadm clean diff --git a/cli/command/install/cmd.go b/cli/command/install/cmd.go new file mode 100644 index 000000000..342e4f16b --- /dev/null +++ b/cli/command/install/cmd.go @@ -0,0 +1,21 @@ +package install + +import ( + "github.com/opencurve/curveadm/cli/cli" + cliutil "github.com/opencurve/curveadm/internal/utils" + "github.com/spf13/cobra" +) + +func NewInstallCommand(curveadm *cli.CurveAdm) *cobra.Command { + cmd := &cobra.Command{ + Use: "install", + Short: "Manage install", + Args: cliutil.NoArgs, + RunE: cliutil.ShowHelp(curveadm.Err()), + } + + cmd.AddCommand( + NewInstallToolCommand(curveadm), + ) + return cmd +} diff --git a/cli/command/install/tool.go b/cli/command/install/tool.go new file mode 100644 index 000000000..a93520842 --- /dev/null +++ b/cli/command/install/tool.go @@ -0,0 +1,89 @@ +package install + +import ( + "github.com/fatih/color" + "github.com/opencurve/curveadm/cli/cli" + comm "github.com/opencurve/curveadm/internal/common" + "github.com/opencurve/curveadm/internal/configure/topology" + "github.com/opencurve/curveadm/internal/errno" + "github.com/opencurve/curveadm/internal/playbook" + cliutil "github.com/opencurve/curveadm/internal/utils" + "github.com/spf13/cobra" +) + +var ( + INSTALL_TOOL_PLAYBOOK_STEPS = []int{ + playbook.INSTALL_TOOL, + } +) + +type installOptions struct { + host string + path string + confPath string +} + +func NewInstallToolCommand(curveadm *cli.CurveAdm) *cobra.Command { + var options installOptions + + cmd := &cobra.Command{ + Use: "tool [OPTIONS]", + Short: "Install tool v2 on the specified host", + Args: cliutil.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + return runInstallTool(curveadm, options) + }, + DisableFlagsInUseLine: true, + } + + flags := cmd.Flags() + flags.StringVar(&options.host, "host", "localhost", "Specify target host") + flags.StringVar(&options.path, "path", "/usr/local/bin/curve", "Specify target install path of tool v2") + flags.StringVar(&options.confPath, "confPath", "~/.curve/curve.yaml", "Specify target config path of tool v2") + + return cmd +} + +func genInstallToolPlaybook(curveadm *cli.CurveAdm, + dcs []*topology.DeployConfig, + options installOptions, +) (*playbook.Playbook, error) { + configs := curveadm.FilterDeployConfig(dcs, topology.FilterOption{Id: "*", Role: topology.ROLE_MDS, Host: options.host})[:1] + if len(configs) == 0 { + return nil, errno.ERR_NO_SERVICES_MATCHED + } + steps := INSTALL_TOOL_PLAYBOOK_STEPS + pb := playbook.NewPlaybook(curveadm) + for _, step := range steps { + pb.AddStep(&playbook.PlaybookStep{ + Type: step, + Configs: configs, + Options: map[string]interface{}{ + comm.KEY_INSTALL_PATH: options.path, + comm.KEY_INSTALL_CONF_PATH: options.confPath, + }, + }) + } + return pb, nil +} + +func runInstallTool(curveadm *cli.CurveAdm, options installOptions) error { + dcs, err := curveadm.ParseTopology() + if err != nil { + return err + } + + pb, err := genInstallToolPlaybook(curveadm, dcs, options) + if err != nil { + return err + } + + err = pb.Run() + if err != nil { + return err + } + + curveadm.WriteOutln(color.GreenString("Install %s to %s success."), + "curve tool v2", options.host) + return nil +} diff --git a/internal/common/common.go b/internal/common/common.go index df2b68c5b..81cc34858 100644 --- a/internal/common/common.go +++ b/internal/common/common.go @@ -134,6 +134,10 @@ const ( // website KEY_WEBSITE_STATUS = "WEBSITE_STATUS" + + // install + KEY_INSTALL_PATH = "INSTALL_PATH" + KEY_INSTALL_CONF_PATH = "INSTALL_CONF_PATH" ) // others diff --git a/internal/playbook/factory.go b/internal/playbook/factory.go index c38254b5e..69842500c 100644 --- a/internal/playbook/factory.go +++ b/internal/playbook/factory.go @@ -31,6 +31,7 @@ import ( "github.com/opencurve/curveadm/internal/task/task/checker" comm "github.com/opencurve/curveadm/internal/task/task/common" "github.com/opencurve/curveadm/internal/task/task/fs" + "github.com/opencurve/curveadm/internal/task/task/install" "github.com/opencurve/curveadm/internal/task/task/monitor" pg "github.com/opencurve/curveadm/internal/task/task/playground" "github.com/opencurve/curveadm/internal/task/task/website" @@ -84,6 +85,7 @@ const ( GET_CLIENT_STATUS INSTALL_CLIENT UNINSTALL_CLIENT + INSTALL_TOOL // bs FORMAT_CHUNKFILE_POOL @@ -260,6 +262,8 @@ func (p *Playbook) createTasks(step *PlaybookStep) (*tasks.Tasks, error) { t, err = comm.NewInstallClientTask(curveadm, config.GetCC(i)) case UNINSTALL_CLIENT: t, err = comm.NewUninstallClientTask(curveadm, nil) + case INSTALL_TOOL: + t, err = install.NewInstallToolTask(curveadm, config.GetDC(i)) // bs case FORMAT_CHUNKFILE_POOL: t, err = bs.NewFormatChunkfilePoolTask(curveadm, config.GetFC(i)) diff --git a/internal/task/task/install/install_tool.go b/internal/task/task/install/install_tool.go new file mode 100644 index 000000000..6352c1786 --- /dev/null +++ b/internal/task/task/install/install_tool.go @@ -0,0 +1,79 @@ +package install + +import ( + "fmt" + "github.com/opencurve/curveadm/cli/cli" + comm "github.com/opencurve/curveadm/internal/common" + "github.com/opencurve/curveadm/internal/configure/topology" + "github.com/opencurve/curveadm/internal/errno" + "github.com/opencurve/curveadm/internal/task/step" + "github.com/opencurve/curveadm/internal/task/task" + tui "github.com/opencurve/curveadm/internal/tui/common" + "github.com/opencurve/curveadm/pkg/module" + "path/filepath" +) + +func checkPathExist(path string, sshConfig *module.SSHConfig, curveadm *cli.CurveAdm) error { + sshClient, err := module.NewSSHClient(*sshConfig) + if err != nil { + return errno.ERR_SSH_CONNECT_FAILED.E(err) + } + + module := module.NewModule(sshClient) + cmd := module.Shell().Stat(path) + if _, err := cmd.Execute(curveadm.ExecOptions()); err == nil { + if pass := tui.ConfirmYes(tui.PromptPathExist(path)); !pass { + return errno.ERR_CANCEL_OPERATION + } + } + return nil +} + +func NewInstallToolTask(curveadm *cli.CurveAdm, dc *topology.DeployConfig) (*task.Task, error) { + layout := dc.GetProjectLayout() + path := curveadm.MemStorage().Get(comm.KEY_INSTALL_PATH).(string) + confPath := curveadm.MemStorage().Get(comm.KEY_INSTALL_CONF_PATH).(string) + hc, err := curveadm.GetHost(dc.GetHost()) + if err != nil { + return nil, err + } + + serviceId := curveadm.GetServiceId(dc.GetId()) + containerId, err := curveadm.GetContainerId(serviceId) + if err != nil { + return nil, err + } + + if err = checkPathExist(path, hc.GetSSHConfig(), curveadm); err != nil { + return nil, err + } + if err = checkPathExist(confPath, hc.GetSSHConfig(), curveadm); err != nil { + return nil, err + } + + subname := fmt.Sprintf("host=%s", dc.GetHost()) + t := task.NewTask("Install tool v2", subname, hc.GetSSHConfig()) + + t.AddStep(&step.CreateDirectory{ + Paths: []string{filepath.Dir(path)}, + ExecOptions: curveadm.ExecOptions(), + }) + t.AddStep(&step.CopyFromContainer{ + ContainerSrcPath: layout.ToolsV2BinaryPath, + ContainerId: containerId, + HostDestPath: path, + ExecOptions: curveadm.ExecOptions(), + }) + t.AddStep(&step.CreateDirectory{ + Paths: []string{filepath.Dir(confPath)}, + ExecOptions: curveadm.ExecOptions(), + }) + t.AddStep(&step.CopyFromContainer{ + ContainerSrcPath: layout.ToolsV2ConfSystemPath, + ContainerId: containerId, + HostDestPath: confPath, + ExecOptions: curveadm.ExecOptions(), + }) + + return t, nil +} diff --git a/internal/tui/common/prompt.go b/internal/tui/common/prompt.go index 52e8b1588..794c15e02 100644 --- a/internal/tui/common/prompt.go +++ b/internal/tui/common/prompt.go @@ -71,6 +71,9 @@ to watch the formatting progress. ` PROMPT_CANCEL_OPERATION = `[x] {{.operation}} canceled` + PROMPT_PATH_EXIST = `{{.path}} already exists. +` + DEFAULT_CONFIRM_PROMPT = "Do you want to continue?" ) @@ -236,3 +239,9 @@ func PromptAutoUpgrade(version string) string { prompt.data["version"] = version return prompt.Build() } + +func PromptPathExist(path string) string { + prompt := NewPrompt(color.YellowString(PROMPT_PATH_EXIST) + DEFAULT_CONFIRM_PROMPT) + prompt.data["path"] = path + return prompt.Build() +}