diff --git a/cli/command/enter.go b/cli/command/enter.go index e7d54c10d..2beffa6f6 100644 --- a/cli/command/enter.go +++ b/cli/command/enter.go @@ -26,15 +26,22 @@ package command import ( "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" + task "github.com/opencurve/curveadm/internal/task/task/common" "github.com/opencurve/curveadm/internal/tools" "github.com/opencurve/curveadm/internal/utils" "github.com/spf13/cobra" ) type enterOptions struct { - id string + id string + role string + host string + verbose bool + showInstances bool } func NewEnterCommand(curveadm *cli.CurveAdm) *cobra.Command { @@ -43,8 +50,11 @@ func NewEnterCommand(curveadm *cli.CurveAdm) *cobra.Command { cmd := &cobra.Command{ Use: "enter ID", Short: "Enter service container", - Args: utils.ExactArgs(1), + Args: utils.RequiresMaxArgs(1), PreRunE: func(cmd *cobra.Command, args []string) error { + if len(args) == 0 { + return nil + } options.id = args[0] return curveadm.CheckId(options.id) }, @@ -57,27 +67,83 @@ func NewEnterCommand(curveadm *cli.CurveAdm) *cobra.Command { return cmd } +func genStatusForLeaderPlaybook(curveadm *cli.CurveAdm, + dcs []*topology.DeployConfig, + options statusOptions) (*playbook.Playbook, error) { + dcs = curveadm.FilterDeployConfig(dcs, topology.FilterOption{ + Id: options.id, + Role: options.role, + Host: options.host, + }) + if len(dcs) == 0 { + return nil, errno.ERR_NO_SERVICES_MATCHED + } + + steps := []int{playbook.INIT_SERVIE_STATUS, playbook.GET_SERVICE_STATUS_FOR_LEADER} + pb := playbook.NewPlaybook(curveadm) + for _, step := range steps { + pb.AddStep(&playbook.PlaybookStep{ + Type: step, + Configs: dcs, + ExecOptions: playbook.ExecOptions{ + //Concurrency: 10, + SilentSubBar: true, + SilentMainBar: step == playbook.INIT_SERVIE_STATUS, + SkipError: true, + }, + }) + } + return pb, nil +} + func runEnter(curveadm *cli.CurveAdm, options enterOptions) error { // 1) parse cluster topology dcs, err := curveadm.ParseTopology() if err != nil { return err } - - // 2) filter service - dcs = curveadm.FilterDeployConfig(dcs, topology.FilterOption{ - Id: options.id, - Role: "*", - Host: "*", - }) - if len(dcs) == 0 { - return errno.ERR_NO_SERVICES_MATCHED + var containerId string + var dc *topology.DeployConfig + //如果有ID执行如下 + if options.id != "" { + // 2) filter service + dcs = curveadm.FilterDeployConfig(dcs, topology.FilterOption{ + Id: options.id, + Role: "*", + Host: "*", + }) + if len(dcs) == 0 { + return errno.ERR_NO_SERVICES_MATCHED + } + // 3) get container id + dc = dcs[0] + } else { + statusOptions1 := statusOptions{id: "*", role: "*", host: "*"} + pb, err := genStatusForLeaderPlaybook(curveadm, dcs, statusOptions1) + if err != nil { + return err + } + err = pb.Run() + statuses := []task.ServiceStatus{} + value := curveadm.MemStorage().Get(comm.KEY_ALL_SERVICE_STATUS) + if value != nil { + m := value.(map[string]task.ServiceStatus) + for _, status := range m { + statuses = append(statuses, status) + } + } + for _, status := range statuses { + if status.IsLeader { + dc = status.Config + break + } + } + if dc == nil { + return errno.ERR_NO_LEADER_CONTAINER_FOUND + } } - - // 3) get container id - dc := dcs[0] serviceId := curveadm.GetServiceId(dc.GetId()) - containerId, err := curveadm.GetContainerId(serviceId) + containerId, err = curveadm.GetContainerId(serviceId) if err != nil { return err } diff --git a/cli/command/status.go b/cli/command/status.go index 041f52768..06699f446 100644 --- a/cli/command/status.go +++ b/cli/command/status.go @@ -153,6 +153,7 @@ func genStatusPlaybook(curveadm *cli.CurveAdm, } func runStatus(curveadm *cli.CurveAdm, options statusOptions) error { + // 1) parse cluster topology dcs, err := curveadm.ParseTopology() if err != nil { diff --git a/internal/errno/errno.go b/internal/errno/errno.go index fd40bbc00..7a4602e8e 100644 --- a/internal/errno/errno.go +++ b/internal/errno/errno.go @@ -261,7 +261,7 @@ var ( ERR_UNSUPPORT_CLEAN_ITEM = EC(210005, "unsupport clean item") ERR_NO_SERVICES_MATCHED = EC(210006, "no services matched") ERR_INVALID_DISK_TYPE = EC(210007, "diskType must be lowercase and only can only be one of ssd, hdd and nvme") - + ERR_NO_LEADER_CONTAINER_FOUND = EC(210008, "no leader container found") // 220: commad options (client common) ERR_UNSUPPORT_CLIENT_KIND = EC(220000, "unsupport client kind") // 221: command options (client/bs) diff --git a/internal/playbook/factory.go b/internal/playbook/factory.go index c38254b5e..a55b8b08b 100644 --- a/internal/playbook/factory.go +++ b/internal/playbook/factory.go @@ -84,6 +84,7 @@ const ( GET_CLIENT_STATUS INSTALL_CLIENT UNINSTALL_CLIENT + GET_SERVICE_STATUS_FOR_LEADER // bs FORMAT_CHUNKFILE_POOL @@ -153,12 +154,10 @@ func (p *Playbook) createTasks(step *PlaybookStep) (*tasks.Tasks, error) { if err != nil { return nil, err } - // (2) set key-value pair for options for k, v := range step.Options { p.curveadm.MemStorage().Set(k, v) } - // (3) create task one by one and added into tasks var t *task.Task once := map[string]bool{} @@ -240,6 +239,8 @@ func (p *Playbook) createTasks(step *PlaybookStep) (*tasks.Tasks, error) { t, err = comm.NewInitServiceStatusTask(curveadm, config.GetDC(i)) case GET_SERVICE_STATUS: t, err = comm.NewGetServiceStatusTask(curveadm, config.GetDC(i)) + case GET_SERVICE_STATUS_FOR_LEADER: + t, err = comm.NewGetServiceStatusForLeaderTask(curveadm, config.GetDC(i)) case CLEAN_SERVICE: t, err = comm.NewCleanServiceTask(curveadm, config.GetDC(i)) case INIT_SUPPORT: diff --git a/internal/task/task/common/service_status.go b/internal/task/task/common/service_status.go index 660fd68c7..6dd802a65 100644 --- a/internal/task/task/common/service_status.go +++ b/internal/task/task/common/service_status.go @@ -306,3 +306,61 @@ func NewGetServiceStatusTask(curveadm *cli.CurveAdm, dc *topology.DeployConfig) return t, nil } + +func NewGetServiceStatusForLeaderTask(curveadm *cli.CurveAdm, dc *topology.DeployConfig) (*task.Task, error) { + serviceId := curveadm.GetServiceId(dc.GetId()) + containerId, err := curveadm.GetContainerId(serviceId) + if curveadm.IsSkip(dc) { + return nil, nil + } else if err != nil { + return nil, err + } + hc, err := curveadm.GetHost(dc.GetHost()) + if err != nil { + return nil, err + } + + // new task + subname := fmt.Sprintf("host=%s role=%s containerId=%s", + dc.GetHost(), dc.GetRole(), tui.TrimContainerId(containerId)) + t := task.NewTask("Enter Leader container", subname, hc.GetSSHConfig()) + + // add step to task + var status string + var ports string + var isLeader bool + t.AddStep(&step.ListContainers{ + ShowAll: true, + Format: `"{{.Status}}"`, + Filter: fmt.Sprintf("id=%s", containerId), + Out: &status, + ExecOptions: curveadm.ExecOptions(), + }) + t.AddStep(&step.Lambda{ + Lambda: TrimContainerStatus(&status), + }) + t.AddStep(&Step2GetListenPorts{ + ContainerId: containerId, + Status: &status, + Ports: &ports, + ExecOptions: curveadm.ExecOptions(), + }) + t.AddStep(&step2GetLeader{ + dc: dc, + containerId: containerId, + status: &status, + isLeader: &isLeader, + execOptions: curveadm.ExecOptions(), + }) + t.AddStep(&step2FormatServiceStatus{ + dc: dc, + serviceId: serviceId, + containerId: containerId, + isLeader: &isLeader, + ports: &ports, + status: &status, + memStorage: curveadm.MemStorage(), + }) + + return t, nil +}