diff --git a/cli/command/cmd.go b/cli/command/cmd.go index a1f6c19f5..614784677 100644 --- a/cli/command/cmd.go +++ b/cli/command/cmd.go @@ -90,6 +90,7 @@ func addSubCommands(cmd *cobra.Command, curveadm *cli.CurveAdm) { NewStopCommand(curveadm), // curveadm stop NewSupportCommand(curveadm), // curveadm support NewUpgradeCommand(curveadm), // curveadm upgrade + NewExportCommand(curveadm), // curveadm export // commonly used shorthands hosts.NewSSHCommand(curveadm), // curveadm ssh hosts.NewPlaybookCommand(curveadm), // curveadm playbook diff --git a/cli/command/export.go b/cli/command/export.go new file mode 100644 index 000000000..0a3263019 --- /dev/null +++ b/cli/command/export.go @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2023 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: 2023-11-9 + * Author: Jiang Jun (youarefree123) + */ + +// __SIGN_BY_YOUAREFREE123__ + +package command + +import ( + "path" + "strings" + + "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 ( + GET_EXPORT_PLAYBOOK_STEPS = []int{ + playbook.SYNC_CONFIG, + playbook.EXPORT_TOOLSV2_CONF, + } +) + +type exportOptions struct { + output string +} + +func checkExportOptions(curveadm *cli.CurveAdm, options exportOptions) error { + if !strings.HasPrefix(options.output, "/") { + return errno.ERR_EXPORT_TOOLSV2_CONF_REQUIRE_ABSOLUTE_PATH. + F("/path/to/curve.yaml: %s", options.output) + } + return nil +} + +func NewExportCommand(curveadm *cli.CurveAdm) *cobra.Command { + var options exportOptions + + cmd := &cobra.Command{ + Use: "export [OPTIONS]", + Short: "Export curve.yaml", + Args: cliutil.NoArgs, + PreRunE: func(cmd *cobra.Command, args []string) error { + return checkExportOptions(curveadm, options) + }, + RunE: func(cmd *cobra.Command, args []string) error { + return runExport(curveadm, options) + }, + DisableFlagsInUseLine: true, + } + + flags := cmd.Flags() + flags.StringVarP(&options.output, "output", "o", path.Join(curveadm.PluginDir(), "curve.yaml"), "Path where the exported YAML is stored") + + return cmd +} + +func genExportPlaybook(curveadm *cli.CurveAdm, + dcs []*topology.DeployConfig, + options exportOptions) (*playbook.Playbook, error) { + + steps := GET_EXPORT_PLAYBOOK_STEPS + + pb := playbook.NewPlaybook(curveadm) + for _, step := range steps { + if step == playbook.EXPORT_TOOLSV2_CONF { + pb.AddStep(&playbook.PlaybookStep{ + Type: step, + Configs: dcs[:1], + Options: map[string]interface{}{ + comm.KEY_TOOLSV2_CONF_PATH: options.output, + }, + }) + } else { + pb.AddStep(&playbook.PlaybookStep{ + Type: step, + Configs: dcs, + Options: map[string]interface{}{ + comm.KEY_TOOLSV2_CONF_PATH: options.output, + }, + }) + } + + } + + return pb, nil +} + +func runExport(curveadm *cli.CurveAdm, options exportOptions) error { + // 1) parse cluster topology + dcs, err := curveadm.ParseTopology() + if err != nil { + return err + } + + // 2) generate get export playbook + pb, err := genExportPlaybook(curveadm, dcs, options) + if err != nil { + return err + } + + // 3) run playground + err = pb.Run() + if err != nil { + return err + } + + // 4) print success prompt + curveadm.WriteOutln("") + curveadm.WriteOutln(color.GreenString("Export curve.yaml to %s success ^_^"), options.output) + return err +} diff --git a/internal/common/common.go b/internal/common/common.go index df2b68c5b..49c71d521 100644 --- a/internal/common/common.go +++ b/internal/common/common.go @@ -48,6 +48,7 @@ const ( POOLSET = "poolset" POOLSET_DISK_TYPE = "poolset-disktype" DEBUG_MODE = "DEBUG_MODE" + KEY_TOOLSV2_CONF_PATH = "TOOLSV2_CONF_PATH" // disk DISK_DEFAULT_NULL_SIZE = "-" diff --git a/internal/errno/errno.go b/internal/errno/errno.go index fd40bbc00..b54ba66c9 100644 --- a/internal/errno/errno.go +++ b/internal/errno/errno.go @@ -280,6 +280,9 @@ var ( // 222: command options (client/fs) ERR_FS_MOUNTPOINT_REQUIRE_ABSOLUTE_PATH = EC(222000, "mount point must be an absolute path") + // 223: command options (export) + ERR_EXPORT_TOOLSV2_CONF_REQUIRE_ABSOLUTE_PATH = EC(223000, "/path/to/curve.yaml must be an absolute path") + // 230: command options (playground) ERR_UNSUPPORT_PLAYGROUND_KIND = EC(230000, "unsupport playground kind") ERR_MUST_SPECIFY_MOUNTPOINT_FOR_CURVEFS_PLAYGROUND = EC(230001, "you must specify mountpoint for curvefs playground") diff --git a/internal/playbook/factory.go b/internal/playbook/factory.go index c38254b5e..28409ec5b 100644 --- a/internal/playbook/factory.go +++ b/internal/playbook/factory.go @@ -84,6 +84,7 @@ const ( GET_CLIENT_STATUS INSTALL_CLIENT UNINSTALL_CLIENT + EXPORT_TOOLSV2_CONF // bs FORMAT_CHUNKFILE_POOL @@ -260,6 +261,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 EXPORT_TOOLSV2_CONF: + t, err = comm.NewExportToolsV2ConfTask(curveadm, config.GetDC(i)) // bs case FORMAT_CHUNKFILE_POOL: t, err = bs.NewFormatChunkfilePoolTask(curveadm, config.GetFC(i)) diff --git a/internal/task/task/common/export_toolsv2_conf.go b/internal/task/task/common/export_toolsv2_conf.go new file mode 100644 index 000000000..7eebff723 --- /dev/null +++ b/internal/task/task/common/export_toolsv2_conf.go @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023 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: 2023-11-12 + * Author: Jiang Jun (youarefree123) + */ + +package common + +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/task/step" + "github.com/opencurve/curveadm/internal/task/task" +) + +func NewExportToolsV2ConfTask(curveadm *cli.CurveAdm, dc *topology.DeployConfig) (*task.Task, error) { + serviceId := curveadm.GetServiceId(dc.GetId()) + containerId, err := curveadm.Storage().GetContainerId(serviceId) + if curveadm.IsSkip(dc) { + return nil, nil + } else if err != nil { + return nil, err + } else if len(containerId) == 0 { + return nil, nil + } else if containerId == comm.CLEANED_CONTAINER_ID { + return nil, nil + } + hc, err := curveadm.GetHost(dc.GetHost()) + if err != nil { + return nil, err + } + + var ToolsV2Conf string + localPath := curveadm.MemStorage().Get(comm.KEY_TOOLSV2_CONF_PATH).(string) + subname := fmt.Sprintf("output=%s", localPath) + t := task.NewTask("Export curve.yaml", subname, hc.GetSSHConfig()) + + t.AddStep(&step.ReadFile{ + ContainerId: containerId, + ContainerSrcPath: dc.GetProjectLayout().ToolsV2ConfSystemPath, + Content: &ToolsV2Conf, + ExecOptions: curveadm.ExecOptions(), + }) + + t.AddStep(&step.InstallFile{ + Content: &ToolsV2Conf, + HostDestPath: localPath, + ExecOptions: curveadm.ExecOptions(), + }) + + return t, nil +} diff --git a/internal/task/task/common/sync_config.go b/internal/task/task/common/sync_config.go index ba1243b39..5728ff58e 100644 --- a/internal/task/task/common/sync_config.go +++ b/internal/task/task/common/sync_config.go @@ -91,11 +91,11 @@ func newToolV2Mutate(dc *topology.DeployConfig, delimiter string, forceRender bo // replace variable value, err = dc.GetVariables().Rendering(value) - if err != nil { - return + if err == nil { + out = fmt.Sprintf("%s%s %s", key, delimiter, value) + } else { // FIX : add replace warring log + err = nil } - - out = fmt.Sprintf("%s%s %s", key, delimiter, value) return } }