diff --git a/cli/command/format.go b/cli/command/format.go index 7190b0232..d88c397ec 100644 --- a/cli/command/format.go +++ b/cli/command/format.go @@ -38,7 +38,8 @@ import ( const ( FORMAT_EXAMPLE = `Examples: $ curveadm format -f /path/to/format.yaml # Format chunkfile pool with specified configure file - $ curveadm format --status -f /path/to/format.yaml # Display formatting status` + $ curveadm format --status -f /path/to/format.yaml # Display formatting status + $ curveadm format --stop -f /path/to/format.yaml # Stop formatting progress` ) var ( @@ -49,11 +50,16 @@ var ( FORMAT_STATUS_PLAYBOOK_STEPS = []int{ playbook.GET_FORMAT_STATUS, } + // FORMAT_STOP_PLAYBOOK_STEPS stop formatting step + FORMAT_STOP_PLAYBOOK_STEPS = []int{ + playbook.STOP_FORMAT, + } ) type formatOptions struct { filename string showStatus bool + stopFormat bool } func NewFormatCommand(curveadm *cli.CurveAdm) *cobra.Command { @@ -73,6 +79,7 @@ func NewFormatCommand(curveadm *cli.CurveAdm) *cobra.Command { flags := cmd.Flags() flags.StringVarP(&options.filename, "formatting", "f", "format.yaml", "Specify the configure file for formatting chunkfile pool") flags.BoolVar(&options.showStatus, "status", false, "Show formatting status") + flags.BoolVar(&options.stopFormat, "stop", false, "Stop formatting progress") return cmd } @@ -84,10 +91,17 @@ func genFormatPlaybook(curveadm *cli.CurveAdm, return nil, errno.ERR_NO_DISK_FOR_FORMATTING } + if options.showStatus && options.stopFormat { + return nil, errno.ERR_UNSUPPORT_CONFIGURE_VALUE_TYPE + } + steps := FORMAT_PLAYBOOK_STEPS if options.showStatus { steps = FORMAT_STATUS_PLAYBOOK_STEPS } + if options.stopFormat { + steps = FORMAT_STOP_PLAYBOOK_STEPS + } pb := playbook.NewPlaybook(curveadm) for _, step := range steps { pb.AddStep(&playbook.PlaybookStep{ diff --git a/internal/playbook/factory.go b/internal/playbook/factory.go index fdf2ba3b9..fbccaa87f 100644 --- a/internal/playbook/factory.go +++ b/internal/playbook/factory.go @@ -114,6 +114,9 @@ const ( REMOVE_PLAYGROUND GET_PLAYGROUND_STATUS + // STOP_FORMAT type stop formatting + STOP_FORMAT + // unknown UNKNOWN ) @@ -232,6 +235,8 @@ func (p *Playbook) createTasks(step *PlaybookStep) (*tasks.Tasks, error) { t, err = bs.NewFormatChunkfilePoolTask(curveadm, config.GetFC(i)) case GET_FORMAT_STATUS: t, err = bs.NewGetFormatStatusTask(curveadm, config.GetFC(i)) + case STOP_FORMAT: + t, err = bs.NewStopFormatTask(curveadm, config.GetFC(i)) case BALANCE_LEADER: t, err = bs.NewBalanceTask(curveadm, config.GetDC(i)) case START_NEBD_SERVICE: diff --git a/internal/task/task/bs/format.go b/internal/task/task/bs/format.go index e1eca30d3..3157a9685 100644 --- a/internal/task/task/bs/format.go +++ b/internal/task/task/bs/format.go @@ -59,6 +59,7 @@ type ( mountPoint string oldUUID *string uuid string + skipAdd bool curveadm *cli.CurveAdm } ) @@ -137,12 +138,14 @@ func (s *step2EditFSTab) execute(ctx *context.Context) error { ExecOptions: curveadm.ExecOptions(), }) } - steps = append(steps, &step.Sed{ // add new record - Files: []string{os.GetFSTabPath()}, - Expression: &express2add, - InPlace: true, - ExecOptions: curveadm.ExecOptions(), - }) + if !s.skipAdd { + steps = append(steps, &step.Sed{ // add new record + Files: []string{os.GetFSTabPath()}, + Expression: &express2add, + InPlace: true, + ExecOptions: curveadm.ExecOptions(), + }) + } for _, step := range steps { err := step.Execute(ctx) diff --git a/internal/task/task/bs/format_stop.go b/internal/task/task/bs/format_stop.go new file mode 100644 index 000000000..424b1ec2a --- /dev/null +++ b/internal/task/task/bs/format_stop.go @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2022 NetEase Inc. + * + * 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. + */ + +/* + * Project: CurveAdm + * Created Date: 2022-11-16 + * Author: guiming liang (demoliang) + */ + +package bs + +import ( + "fmt" + + "github.com/opencurve/curveadm/cli/cli" + "github.com/opencurve/curveadm/internal/configure" + "github.com/opencurve/curveadm/internal/task/context" + "github.com/opencurve/curveadm/internal/task/step" + "github.com/opencurve/curveadm/internal/task/task" +) + +func skipStopFormat(containerId *string) step.LambdaType { + return func(ctx *context.Context) error { + if len(*containerId) < 0 { + return task.ERR_SKIP_TASK + } + return nil + } +} + +type stopContainer struct { + containerId *string + curveadm *cli.CurveAdm +} + +func (s *stopContainer) Execute(ctx *context.Context) error { + if len(*s.containerId) == 0 { + return nil + } + + steps := []task.Step{} + steps = append(steps, &step.StopContainer{ + ContainerId: *s.containerId, + Time: 1, + ExecOptions: s.curveadm.ExecOptions(), + }) + for _, s := range steps { + err := s.Execute(ctx) + if err != nil { + return err + } + } + return nil +} + +func NewStopFormatTask(curveadm *cli.CurveAdm, fc *configure.FormatConfig) (*task.Task, error) { + host := fc.GetHost() + hc, err := curveadm.GetHost(host) + if err != nil { + return nil, err + } + + // new task + device := fc.GetDevice() + mountPoint := fc.GetMountPoint() + containerName := device2ContainerName(device) + subname := fmt.Sprintf("host=%s device=%s mountPoint=%s containerName=%s", + fc.GetHost(), device, mountPoint, containerName) + t := task.NewTask("Stop Format Chunkfile Pool", subname, hc.GetSSHConfig()) + + var oldContainerId string + var oldUUID string + + // 1: list block device and edit fstab delete record + t.AddStep(&step.ListBlockDevice{ + Device: []string{device}, + Format: "UUID", + NoHeadings: true, + Out: &oldUUID, + ExecOptions: curveadm.ExecOptions(), + }) + t.AddStep(&step2EditFSTab{ + host: host, + device: device, + oldUUID: &oldUUID, + mountPoint: mountPoint, + curveadm: curveadm, + skipAdd: true, + }) + + // 2: list container id and add step to task + t.AddStep(&step.ListContainers{ + ShowAll: true, + Format: "'{{.ID}}'", + Quiet: true, + Filter: fmt.Sprintf("name=%s", containerName), + Out: &oldContainerId, + ExecOptions: curveadm.ExecOptions(), + }) + + t.AddStep(&step.Lambda{ + Lambda: skipStopFormat(&oldContainerId), + }) + + // 3: stop container + t.AddStep(&stopContainer{ + containerId: &oldContainerId, + curveadm: curveadm, + }) + + // 4. umount filesystem + t.AddStep(&step.UmountFilesystem{ + Directorys: []string{device}, + IgnoreUmounted: true, + IgnoreNotFound: true, + ExecOptions: curveadm.ExecOptions(), + }) + + return t, nil +}