diff --git a/cli/command/target/list.go b/cli/command/target/list.go index 6214891be..bfdb03a96 100644 --- a/cli/command/target/list.go +++ b/cli/command/target/list.go @@ -26,6 +26,7 @@ import ( "github.com/opencurve/curveadm/cli/cli" comm "github.com/opencurve/curveadm/internal/common" "github.com/opencurve/curveadm/internal/playbook" + "github.com/opencurve/curveadm/internal/task/step" "github.com/opencurve/curveadm/internal/task/task/bs" "github.com/opencurve/curveadm/internal/tui" cliutil "github.com/opencurve/curveadm/internal/utils" @@ -80,10 +81,10 @@ func genListPlaybook(curveadm *cli.CurveAdm, options listOptions) (*playbook.Pla } func displayTargets(curveadm *cli.CurveAdm) { - targets := []bs.Target{} + targets := []step.Target{} value := curveadm.MemStorage().Get(comm.KEY_ALL_TARGETS) if value != nil { - m := value.(map[string]*bs.Target) + m := value.(map[string]*step.Target) for _, target := range m { targets = append(targets, *target) } diff --git a/internal/common/common.go b/internal/common/common.go index 7887ef584..bd81cb5c0 100644 --- a/internal/common/common.go +++ b/internal/common/common.go @@ -130,3 +130,10 @@ const ( AUDIT_STATUS_FAIL AUDIT_STATUS_CANCEL ) + +// container restart policy +const ( + POLICY_ALWAYS_RESTART = "always" + POLICY_NEVER_RESTART = "no" + POLICY_UNLESS_STOPPED = "unless-stopped" +) diff --git a/internal/errno/errno.go b/internal/errno/errno.go index 4ac0f7204..bfa060355 100644 --- a/internal/errno/errno.go +++ b/internal/errno/errno.go @@ -539,6 +539,7 @@ var ( ERR_COPY_INTO_CONTAINER_FAILED = EC(630011, "copy file into container failed (docker cp SRC_PATH CONTAINER:DEST_PATH)") ERR_INSPECT_CONTAINER_FAILED = EC(630012, "get container low-level information failed (docker inspect ID)") ERR_GET_CONTAINER_LOGS_FAILED = EC(630013, "get container logs failed (docker logs ID)") + ERR_UPDATE_CONTAINER_FAILED = EC(630014, "update container failed (docker update ID)") // 690: execuetr task (others) ERR_START_CRONTAB_IN_CONTAINER_FAILED = EC(690000, "start crontab in container failed") diff --git a/internal/task/step/container.go b/internal/task/step/container.go index 52da2b6e0..54ec1dc92 100644 --- a/internal/task/step/container.go +++ b/internal/task/step/container.go @@ -152,6 +152,14 @@ type ( Success *bool module.ExecOptions } + + UpdateContainer struct { + ContainerId *string + Restart string + Out *string + Success *bool + module.ExecOptions + } ) func (s *DockerInfo) Execute(ctx *context.Context) error { @@ -312,3 +320,12 @@ func (s *ContainerLogs) Execute(ctx *context.Context) error { out, err := cli.Execute(s.ExecOptions) return PostHandle(s.Success, s.Out, out, err, errno.ERR_GET_CONTAINER_LOGS_FAILED) } + +func (s *UpdateContainer) Execute(ctx *context.Context) error { + cli := ctx.Module().DockerCli().UpdateContainer(*s.ContainerId) + if len(s.Restart) > 0 { + cli.AddOption("--restart %s", s.Restart) + } + out, err := cli.Execute(s.ExecOptions) + return PostHandle(s.Success, s.Out, out, err, errno.ERR_UPDATE_CONTAINER_FAILED) +} diff --git a/internal/task/step/daemon.go b/internal/task/step/daemon.go new file mode 100644 index 000000000..71a0cd4e1 --- /dev/null +++ b/internal/task/step/daemon.go @@ -0,0 +1,161 @@ +/* + * 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-03-16 + * Author: Cyber-SiKu + */ + +package step + +import ( + "encoding/json" + "fmt" + "strconv" + "strings" + + comm "github.com/opencurve/curveadm/internal/common" + "github.com/opencurve/curveadm/internal/task/context" + "github.com/opencurve/curveadm/internal/utils" + "github.com/opencurve/curveadm/pkg/module" +) + +const ( + AFTER_TASK_DIR = "/curve/init.d/" +) + +var ALLOC_ID int = 0 + +type afterRunTask struct { + ID int `json:"ID"` + Path string `json:"Path"` + Args []string `json:"Args"` + Env []string `json:"Env"` + Dir string `json:"Dir"` + OutputPath string `json:"OutputPath"` + InputPath string `json:"InputPath"` +} + +func (task afterRunTask) ToString() string { + b, err := json.Marshal(task) + if err != nil { + return "" + } + return string(b) +} + +func newDaemonTask(path string, args ...string) *afterRunTask { + task := afterRunTask{ + ID: ALLOC_ID, + Path: path, + Args: args, + } + return &task +} + +type AddDaemonTask struct { + ContainerId *string + Cmd string + Args []string + TaskName string + module.ExecOptions +} + +type DelDaemonTask struct { + ContainerId *string + Tid string + MemStorage *utils.SafeMap + module.ExecOptions +} + +func (s *AddDaemonTask) getAllocId(ctx *context.Context) { + if ALLOC_ID != 0 { + ALLOC_ID++ + return + } else { + // first add daemon task + // create dir AFTER_TASK_DIR + step := ContainerExec{ + ContainerId: s.ContainerId, + Command: fmt.Sprintf("mkdir -p %s", AFTER_TASK_DIR), + ExecOptions: s.ExecOptions, + } + err := step.Execute(ctx) + if err != nil { + return + } + } + var count string + // get max id + // The contents of the file are as follows: + // {"ID":1,"Path":"tgtd","Args":null,"Env":null,"Dir":"","OutputPath":"","InputPath":""} + step := ContainerExec{ + ContainerId: s.ContainerId, + Command: fmt.Sprintf("grep -r '\"ID\":[0-9]*,' %s | awk -F \":\" '{print $3}' | awk -F \",\" '{print $1}' | sort -n | tail -1", AFTER_TASK_DIR), + Out: &count, + ExecOptions: s.ExecOptions, + } + err := step.Execute(ctx) + if err != nil { + ALLOC_ID = 1 + } + id, err := strconv.Atoi(count) + if err != nil { + ALLOC_ID = 1 + } + ALLOC_ID = id + 1 +} + +func (s *AddDaemonTask) Execute(ctx *context.Context) error { + s.getAllocId(ctx) + content := newDaemonTask(s.Cmd, s.Args...).ToString() + step := InstallFile{ + Content: &content, + ContainerId: s.ContainerId, + ContainerDestPath: AFTER_TASK_DIR + s.TaskName + ".task", + ExecOptions: s.ExecOptions, + } + return step.Execute(ctx) +} + +type Target struct { + Host string + Tid string + Name string + Store string + Portal string +} + +func (s *DelDaemonTask) Execute(ctx *context.Context) error { + v := s.MemStorage.Get(comm.KEY_ALL_TARGETS) + target := v.(map[string]*Target)[s.Tid] + if target == nil { + return nil + } + stores := strings.Split(target.Store, "//") + if len(stores) < 2 { + // unable to recognize cbd:pool + return nil + } + path := AFTER_TASK_DIR + "addTarget_" + stores[1] + ".task" + step := ContainerExec{ + ContainerId: s.ContainerId, + Command: "rm -f " + path, + ExecOptions: s.ExecOptions, + } + return step.Execute(ctx) +} diff --git a/internal/task/task/bs/add_target.go b/internal/task/task/bs/add_target.go index a5f3beee5..4c59ee6bb 100644 --- a/internal/task/task/bs/add_target.go +++ b/internal/task/task/bs/add_target.go @@ -24,6 +24,8 @@ package bs import ( "fmt" + "regexp" + "strconv" "github.com/opencurve/curveadm/cli/cli" comm "github.com/opencurve/curveadm/internal/common" @@ -34,12 +36,12 @@ import ( ) type TargetOption struct { - Host string - User string - Volume string - Create bool - Size int - Tid string + Host string + User string + Volume string + Create bool + Size int + Tid string Blocksize uint64 } @@ -91,5 +93,18 @@ func NewAddTargetTask(curveadm *cli.CurveAdm, cc *configure.ClientConfig) (*task ExecOptions: curveadm.ExecOptions(), }) + t.AddStep(&step.AddDaemonTask{ // install addTarget.task + ContainerId: &containerId, + Cmd: "/bin/bash", + Args: []string{targetScriptPath, user, volume, strconv.FormatBool(options.Create), strconv.Itoa(options.Size), strconv.FormatUint(options.Blocksize, 10)}, + TaskName: "addTarget"+TranslateVolumeName(volume, user), + ExecOptions: curveadm.ExecOptions(), + }) + return t, nil } + +func TranslateVolumeName(volume, user string) string { + reg, _ := regexp.Compile("[^a-zA-Z0-9]+") + return reg.ReplaceAllString(volume, "_") + "_" + user + "_" +} diff --git a/internal/task/task/bs/create_volume.go b/internal/task/task/bs/create_volume.go index 41607ba96..02e585d45 100644 --- a/internal/task/task/bs/create_volume.go +++ b/internal/task/task/bs/create_volume.go @@ -84,6 +84,7 @@ func NewCreateVolumeTask(curveadm *cli.CurveAdm, cc *configure.ClientConfig) (*t script := scripts.CREATE_VOLUME scriptPath := "/curvebs/nebd/sbin/create.sh" command := fmt.Sprintf("/bin/bash %s %s %s %d", scriptPath, options.User, options.Volume, options.Size) + t.AddStep(&step.ListContainers{ ShowAll: true, Format: "'{{.Status}}'", diff --git a/internal/task/task/bs/delete_target.go b/internal/task/task/bs/delete_target.go index e5e58cb61..7f5a6135e 100644 --- a/internal/task/task/bs/delete_target.go +++ b/internal/task/task/bs/delete_target.go @@ -75,6 +75,24 @@ func NewDeleteTargetTask(curveadm *cli.CurveAdm, cc *client.ClientConfig) (*task t.AddStep(&step2CheckTgtdStatus{ output: &output, }) + t.AddStep(&step.ContainerExec{ + ContainerId: &containerId, + Command: fmt.Sprintf("tgtadm --lld iscsi --mode target --op show"), + Out: &output, + ExecOptions: curveadm.ExecOptions(), + }) + t.AddStep(&step2FormatTarget{ + host: options.Host, + hostname: hc.GetHostname(), + output: &output, + memStorage: curveadm.MemStorage(), + }) + t.AddStep(&step.DelDaemonTask{ + ContainerId: &containerId, + Tid: tid, + MemStorage: curveadm.MemStorage(), + ExecOptions: curveadm.ExecOptions(), + }) t.AddStep(&step.ContainerExec{ ContainerId: &containerId, Command: fmt.Sprintf("tgtadm --lld iscsi --mode target --op delete --tid %s", tid), diff --git a/internal/task/task/bs/list_targets.go b/internal/task/task/bs/list_targets.go index ccdd618ad..5e897bf75 100644 --- a/internal/task/task/bs/list_targets.go +++ b/internal/task/task/bs/list_targets.go @@ -46,22 +46,14 @@ type ( output *string memStorage *utils.SafeMap } - - Target struct { - Host string - Tid string - Name string - Store string - Portal string - } ) -func addTarget(memStorage *utils.SafeMap, id string, target *Target) { +func addTarget(memStorage *utils.SafeMap, id string, target *step.Target) { memStorage.TX(func(kv *utils.SafeMap) error { - m := map[string]*Target{} + m := map[string]*step.Target{} v := kv.Get(comm.KEY_ALL_TARGETS) if v != nil { - m = v.(map[string]*Target) + m = v.(map[string]*step.Target) } m[id] = target kv.Set(comm.KEY_ALL_TARGETS, m) @@ -84,13 +76,13 @@ func (s *step2FormatTarget) Execute(ctx *context.Context) error { output := *s.output lines := strings.Split(output, "\n") - var target *Target + var target *step.Target titlePattern := regexp.MustCompile("^Target ([0-9]+): (.+)$") storePattern := regexp.MustCompile("Backing store path: (cbd:pool//.+)$") for _, line := range lines { mu := titlePattern.FindStringSubmatch(line) if len(mu) > 0 { - target = &Target{ + target = &step.Target{ Host: s.host, Tid: mu[1], Name: mu[2], diff --git a/internal/task/task/bs/map.go b/internal/task/task/bs/map.go index 26f9a6a13..dcfdfcf62 100644 --- a/internal/task/task/bs/map.go +++ b/internal/task/task/bs/map.go @@ -106,6 +106,13 @@ func NewMapTask(curveadm *cli.CurveAdm, cc *configure.ClientConfig) (*task.Task, Args: []string{"nbds_max=64"}, ExecOptions: curveadm.ExecOptions(), }) + t.AddStep(&step.AddDaemonTask{ // install modprobe.task + ContainerId: &containerId, + Cmd: "modprobe", + Args: []string{comm.KERNERL_MODULE_NBD, "nbds_max=64"}, + TaskName: "modProbe", + ExecOptions: curveadm.ExecOptions(), + }) t.AddStep(&step.SyncFile{ // sync nebd-client config ContainerSrcId: &containerId, ContainerSrcPath: "/curvebs/conf/nebd-client.conf", @@ -130,6 +137,13 @@ func NewMapTask(curveadm *cli.CurveAdm, cc *configure.ClientConfig) (*task.Task, Mutate: newToolsV2Mutate(cc, TOOLSV2_CONFIG_DELIMITER), ExecOptions: curveadm.ExecOptions(), }) + t.AddStep(&step.AddDaemonTask{ // install map.task + ContainerId: &containerId, + Cmd: "/bin/bash", + Args: []string{scriptPath, options.User, options.Volume, mapOptions}, + TaskName: "map", + ExecOptions: curveadm.ExecOptions(), + }) t.AddStep(&step.ContainerExec{ ContainerId: &containerId, Command: command, diff --git a/internal/task/task/bs/start_nebd.go b/internal/task/task/bs/start_nebd.go index aaee80172..d71b34d7e 100644 --- a/internal/task/task/bs/start_nebd.go +++ b/internal/task/task/bs/start_nebd.go @@ -194,6 +194,7 @@ func NewStartNEBDServiceTask(curveadm *cli.CurveAdm, cc *configure.ClientConfig) Privileged: true, Volumes: getVolumes(cc), Out: &containerId, + Restart: comm.POLICY_UNLESS_STOPPED, ExecOptions: curveadm.ExecOptions(), }) t.AddStep(&step2InsertClient{ diff --git a/internal/task/task/bs/start_tgtd.go b/internal/task/task/bs/start_tgtd.go index 0aa917149..7c5142b63 100644 --- a/internal/task/task/bs/start_tgtd.go +++ b/internal/task/task/bs/start_tgtd.go @@ -100,6 +100,7 @@ func NewStartTargetDaemonTask(curveadm *cli.CurveAdm, cc *configure.ClientConfig Privileged: true, Volumes: getVolumes(cc), Out: &containerId, + Restart: comm.POLICY_UNLESS_STOPPED, ExecOptions: curveadm.ExecOptions(), }) for _, filename := range []string{"client.conf", "nebd-server.conf"} { @@ -113,6 +114,15 @@ func NewStartTargetDaemonTask(curveadm *cli.CurveAdm, cc *configure.ClientConfig ExecOptions: curveadm.ExecOptions(), }) } + t.AddStep(&step.SyncFile{ // sync client configuration for tgtd + ContainerSrcId: &containerId, + ContainerSrcPath: "/curvebs/conf/client.conf", + ContainerDestId: &containerId, + ContainerDestPath: "/etc/curve/client.conf", + KVFieldSplit: CLIENT_CONFIG_DELIMITER, + Mutate: newMutate(cc, CLIENT_CONFIG_DELIMITER), + ExecOptions: curveadm.ExecOptions(), + }) t.AddStep(&step.SyncFile{ // sync nebd-client config ContainerSrcId: &containerId, ContainerSrcPath: "/curvebs/conf/nebd-client.conf", @@ -128,8 +138,14 @@ func NewStartTargetDaemonTask(curveadm *cli.CurveAdm, cc *configure.ClientConfig ExecOptions: curveadm.ExecOptions(), }) t.AddStep(&step.ContainerExec{ - Command: "tgtd -f &", + Command: "tgtd", + ContainerId: &containerId, + ExecOptions: curveadm.ExecOptions(), + }) + t.AddStep(&step.AddDaemonTask{ // install tgtd.task ContainerId: &containerId, + Cmd: "tgtd", + TaskName: "tgtd", ExecOptions: curveadm.ExecOptions(), }) diff --git a/internal/task/task/common/create_container.go b/internal/task/task/common/create_container.go index d2cc87892..7de49259c 100644 --- a/internal/task/task/common/create_container.go +++ b/internal/task/task/common/create_container.go @@ -40,11 +40,6 @@ import ( log "github.com/opencurve/curveadm/pkg/log/glg" ) -const ( - POLICY_ALWAYS_RESTART = "always" - POLICY_NEVER_RESTART = "no" -) - type step2GetService struct { serviceId string containerId *string @@ -193,15 +188,15 @@ func getMountVolumes(dc *topology.DeployConfig, serviceMountDevice bool) []step. func getRestartPolicy(dc *topology.DeployConfig, serviceMountDevice bool) string { switch dc.GetRole() { case topology.ROLE_ETCD: - return POLICY_ALWAYS_RESTART + return comm.POLICY_ALWAYS_RESTART case topology.ROLE_MDS: - return POLICY_ALWAYS_RESTART + return comm.POLICY_ALWAYS_RESTART case topology.ROLE_CHUNKSERVER: if serviceMountDevice { - return POLICY_ALWAYS_RESTART + return comm.POLICY_ALWAYS_RESTART } } - return POLICY_NEVER_RESTART + return comm.POLICY_NEVER_RESTART } func trimContainerId(containerId *string) step.LambdaType { diff --git a/internal/task/task/fs/mount.go b/internal/task/task/fs/mount.go index 95c02e0fb..a9a48161c 100644 --- a/internal/task/task/fs/mount.go +++ b/internal/task/task/fs/mount.go @@ -27,8 +27,10 @@ import ( "errors" "fmt" "strings" + "time" "github.com/opencurve/curveadm/cli/cli" + "github.com/opencurve/curveadm/internal/common" comm "github.com/opencurve/curveadm/internal/common" "github.com/opencurve/curveadm/internal/configure" "github.com/opencurve/curveadm/internal/configure/topology" @@ -39,6 +41,7 @@ import ( "github.com/opencurve/curveadm/internal/task/task" "github.com/opencurve/curveadm/internal/task/task/checker" "github.com/opencurve/curveadm/internal/utils" + "github.com/opencurve/curveadm/pkg/module" ) const ( @@ -50,6 +53,10 @@ const ( KEY_CURVEBS_CLUSTER = "curvebs.cluster" CURVEBS_CONF_PATH = "/etc/curve/client.conf" + + CURVEFS_LIST_FS = "curvefs_tool list-fs" + + CHECK_MOUTPOINT_TIMES = 3 ) type ( @@ -72,6 +79,12 @@ type ( MountPoint string `json:"mount_point,"` Config string `json:"config,omitempty"` // TODO(P1) } + + CheckMountDone struct { + ContainerId *string + MountPoint string + module.ExecOptions + } ) var ( @@ -358,6 +371,7 @@ func NewMountFSTask(curveadm *cli.CurveAdm, cc *configure.ClientConfig) (*task.T Privileged: true, Out: &containerId, ExecOptions: curveadm.ExecOptions(), + Restart: common.POLICY_ALWAYS_RESTART, }) t.AddStep(&step2InsertClient{ curveadm: curveadm, @@ -420,8 +434,98 @@ func NewMountFSTask(curveadm *cli.CurveAdm, cc *configure.ClientConfig) (*task.T t.AddStep(&step.Lambda{ Lambda: checkStartContainerStatus(&success, &out), }) - // TODO(P0): wait mount done + t.AddStep(&CheckMountDone{ + ContainerId: &containerId, + MountPoint: mountPoint, + ExecOptions: curveadm.ExecOptions(), + }) + t.AddStep(&step.UpdateContainer{ + ContainerId: &containerId, + Restart: comm.POLICY_UNLESS_STOPPED, + ExecOptions: curveadm.ExecOptions(), + }) return t, nil } + +func (s *CheckMountDone) Execute(ctx *context.Context) error { + steps := []task.Step{} + var success bool + var out, hostname string + // get hostname + steps = append(steps, &step.Hostname{ + Success: &success, + Out: &hostname, + ExecOptions: s.ExecOptions, + }) + for i := 0; i < CHECK_MOUTPOINT_TIMES; i++ { + steps = append(steps, &step.ContainerExec{ + ContainerId: s.ContainerId, + Command: CURVEFS_LIST_FS, + Success: &success, + Out: &out, + ExecOptions: s.ExecOptions, + }) + } + // list fs 3 times to check mountpoint + // if no this mountpoint stop container + steps = append(steps, &step.StopContainer{ + ContainerId: *s.ContainerId, + ExecOptions: s.ExecOptions, + }) + mountPoint := configure.GetFSClientMountPath(s.MountPoint) + for _, step := range steps { + time.Sleep(time.Duration(1) * time.Second) + err := step.Execute(ctx) + if err == nil && success && out != "" { + if checkMountpointExist(out, mountPoint, hostname) { + return nil + } + } + } + return errno.ERR_MOUNT_FILESYSTEM_FAILED +} + +const ( + JSON_FS_INFO = "fsInfo" + JSON_MOUNT_NUM = "mountNum" + JSON_MOUNTPOINTS = "mountpoints" + JSON_HOSTNAME = "hostname" + JSON_PATH = "path" +) + +func checkMountpointExist(out, path, hostname string) bool { + var jsonMap map[string]interface{} + err := json.Unmarshal([]byte(out), &jsonMap) + if err != nil || jsonMap[JSON_FS_INFO] == nil { + return false + } + + if !utils.IsAnySlice(jsonMap[JSON_FS_INFO]) { + return false + } + + for _, fsinfo := range jsonMap[JSON_FS_INFO].([]interface{}) { + if !utils.IsStringAnyMap(fsinfo) { + continue + } + info := fsinfo.(map[string]interface{}) + if !utils.IsFloat64(info[JSON_MOUNT_NUM]) || + int(info[JSON_MOUNT_NUM].(float64)) <= 0 || + !utils.IsAnySlice(info[JSON_MOUNTPOINTS].([]interface{})) { + continue + } + for _, mountpoint := range info[JSON_MOUNTPOINTS].([]interface{}) { + if !utils.IsStringAnyMap(mountpoint) { + continue + } + point := mountpoint.(map[string]interface{}) + if point[JSON_HOSTNAME] == hostname && point[JSON_PATH] == path { + return true + } + } + } + + return false +} diff --git a/internal/task/task/fs/umount.go b/internal/task/task/fs/umount.go index 6c14c93af..8d4b35d05 100644 --- a/internal/task/task/fs/umount.go +++ b/internal/task/task/fs/umount.go @@ -147,6 +147,12 @@ func NewUmountFSTask(curveadm *cli.CurveAdm, v interface{}) (*task.Task, error) mountPoint: options.MountPoint, curveadm: curveadm, }) + if containerId != "" { + t.AddStep(&step.StopContainer{ + ContainerId: containerId, + ExecOptions: curveadm.ExecOptions(), + }) + } t.AddStep(&step2RemoveContainer{ status: &status, containerId: containerId, diff --git a/internal/tui/targets.go b/internal/tui/targets.go index 262ca09ba..2bda6a389 100644 --- a/internal/tui/targets.go +++ b/internal/tui/targets.go @@ -25,19 +25,19 @@ package tui import ( "sort" - task "github.com/opencurve/curveadm/internal/task/task/bs" + "github.com/opencurve/curveadm/internal/task/step" "github.com/opencurve/curveadm/internal/tui/common" tuicommon "github.com/opencurve/curveadm/internal/tui/common" ) -func sortTargets(targets []task.Target) { +func sortTargets(targets []step.Target) { sort.Slice(targets, func(i, j int) bool { t1, t2 := targets[i], targets[j] return t1.Tid < t2.Tid }) } -func FormatTargets(targets []task.Target) string { +func FormatTargets(targets []step.Target) string { lines := [][]interface{}{} title := []string{"Tid", "Host", "Target Name", "Store", "Portal"} first, second := tuicommon.FormatTitle(title) diff --git a/internal/utils/common.go b/internal/utils/common.go index ec310a615..be9aae86a 100644 --- a/internal/utils/common.go +++ b/internal/utils/common.go @@ -74,6 +74,8 @@ func Type(v interface{}) string { return "string_interface_map" case []interface{}: return "any_slice" + case float64: + return "float64" default: return "unknown" } @@ -107,6 +109,10 @@ func IsFunc(v interface{}) bool { return reflect.TypeOf(v).Kind() == reflect.Func } +func IsFloat64(v interface{}) bool { + return Type(v) == "float64" +} + func All2Str(v interface{}) (value string, ok bool) { ok = true if IsString(v) { diff --git a/pkg/module/docker_cli.go b/pkg/module/docker_cli.go index 83fe1ccfd..40b588b97 100644 --- a/pkg/module/docker_cli.go +++ b/pkg/module/docker_cli.go @@ -45,6 +45,7 @@ const ( TEMPLATE_COPY_INTO_CONTAINER = "docker cp {{.options}} {{.srcPath}} {{.container}}:{{.destPath}}" TEMPLATE_INSPECT_CONTAINER = "docker inspect {{.options}} {{.container}}" TEMPLATE_CONTAINER_LOGS = "docker logs {{.options}} {{.container}}" + TEMPLATE_UPDATE_CONTAINER = "docker update {{.options}} {{.container}}" ) type DockerCli struct { @@ -160,3 +161,9 @@ func (cli *DockerCli) ContainerLogs(containerId string) *DockerCli { cli.data["container"] = containerId return cli } + +func (cli *DockerCli) UpdateContainer(containerId string) *DockerCli { + cli.tmpl = template.Must(template.New("UpdateContainer").Parse(TEMPLATE_UPDATE_CONTAINER)) + cli.data["container"] = containerId + return cli +} diff --git a/playbook/automount/hosts.yaml b/playbook/automount/hosts.yaml new file mode 100644 index 000000000..0e78c6b3b --- /dev/null +++ b/playbook/automount/hosts.yaml @@ -0,0 +1,20 @@ +global: + user: curve + ssh_port: 22 + private_key_file: /home/curve/.ssh/id_rsa + +hosts: + - host: server-host1 + hostname: 10.0.1.1 + labels: + - automount + envs: + - SUDO_ALIAS=sudo + - OPTIONS="" + - host: server-host2 + hostname: 10.0.1.2 + labels: + - automount + envs: + - SUDO_ALIAS=sudo + - OPTIONS="" \ No newline at end of file diff --git a/playbook/automount/scripts/add_disk.sh b/playbook/automount/scripts/add_disk.sh new file mode 100644 index 000000000..26a761ce9 --- /dev/null +++ b/playbook/automount/scripts/add_disk.sh @@ -0,0 +1,137 @@ +#!/usr/bin/env bash + +# +# 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. +# + +# check parameters +if [ $# -ne 2 ]; then + echo "Usage: $0 " + exit 1 +fi + +g_device=$1 +g_mountpoint=$2 +g_systemd_name="" +g_disk_uuid="" +g_filesystem_type="" +g_options="defaults" + +g_blkid_cmd="${SUDO_ALIAS} blkid -o value" +g_lsblk_cmd="${SUDO_ALIAS} lsblk" +g_mkdir_cmd="${SUDO_ALIAS} mkdir -p" +g_mount_cmd="${SUDO_ALIAS} mount" +g_umount_cmd="${SUDO_ALIAS} umount" +g_systemctl_cmd="${SUDO_ALIAS} systemctl" +g_cat_cmd="${SUDO_ALIAS} cat" +g_tee_cmd="${SUDO_ALIAS} tee" + +function msg() { + printf '%b' "$1" >&2 +} + +function success() { + msg "\33[32m[✔]\33[0m ${1}${2}" +} + +function die() { + msg "\33[31m[✘]\33[0m ${1}${2}" + exit 1 +} + +precheck() { + # check block devices + ${g_lsblk_cmd} ${g_device} >& /dev/null + if [ $? -ne 0 ];then + die "${g_device} is not a block devices!\n" + exit 1 + fi + # mkdir mountpoint + if [ ! -d ${g_mountpoint} ];then + die "${g_mountpoint} is not a directory!\n" + fi + + # check uuid + g_disk_uuid=`${g_blkid_cmd} -s UUID ${g_device}` + if [ ! ${g_disk_uuid} ];then + die "${g_device} has no uuid!\n" + fi + + # check options by mount + ${g_umount_cmd} ${g_mountpoint} >& /dev/null + if [ "${OPTIONS}" != "" ];then + g_options=${OPTIONS} + fi + out=`${g_mount_cmd} --options ${g_options} ${g_device} ${g_mountpoint} 2>&1` + if [ $? -ne 0 ];then + die "${out}!\n" + exit 1 + fi + ${g_umount_cmd} ${g_mountpoint} >& /dev/null +} + +init() { + src=${g_mountpoint//\//-} + g_systemd_name=${src#-} + g_filesystem_type=`${g_blkid_cmd} -s TYPE ${g_device}` +} + +create_systemd() { + # add mount + echo "[Unit] +Description=Mount ${g_device} at ${g_mountpoint} + +[Mount] +What=/dev/disk/by-uuid/${g_disk_uuid} +Where=${g_mountpoint} +Type=${g_filesystem_type} +Options=${g_options} + +[Install] +WantedBy=multi-user.target + " | ${g_tee_cmd} /etc/systemd/system/${g_systemd_name}.mount >& /dev/null + + # add automount + echo "[Unit] +Description=Automount ${g_device} at ${g_mountpoint} + +[Automount] +Where=${g_mountpoint} + +[Install] +WantedBy=multi-user.target + " | ${g_tee_cmd} /etc/systemd/system/${g_systemd_name}.automount >& /dev/null + + ${g_systemctl_cmd} daemon-reload >& /dev/null + ${g_systemctl_cmd} enable ${g_systemd_name}.mount >& /dev/null + ${g_systemctl_cmd} enable ${g_systemd_name}.automount >& /dev/null + ${g_systemctl_cmd} start ${g_systemd_name}.automount >& /dev/null + ${g_systemctl_cmd} start ${g_systemd_name}.mount >& /dev/null + + sleep 3 + + status=`${g_systemctl_cmd} is-active ${g_systemd_name}.mount` + auto_status=`${g_systemctl_cmd} is-active ${g_systemd_name}.automount` + if [ "${status}" == "active" ] && [ "${auto_status}" == "active" ];then + success "add automount ${g_device} to ${g_mountpoint} successfully!\n" + else + die "add automount ${g_device} to ${g_mountpoint} failed please check!\n" + exit 1 + fi +} + +precheck +init +create_systemd diff --git a/playbook/automount/scripts/del_disk.sh b/playbook/automount/scripts/del_disk.sh new file mode 100644 index 000000000..8718a16b0 --- /dev/null +++ b/playbook/automount/scripts/del_disk.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash + +# +# 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. +# + +# check parameters +if [ $# -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +g_mountpoint=$1 +g_systemd_name="" +g_rm_cmd="${SUDO_ALIAS} rm" +g_umount_cmd="${SUDO_ALIAS} umount" + +function msg() { + printf '%b' "$1" >&2 +} + +function success() { + msg "\33[32m[✔]\33[0m ${1}${2}" +} + +function die() { + msg "\33[31m[✘]\33[0m ${1}${2}" + exit 1 +} + +precheck() { + # check systemd file is exist + src=${g_mountpoint//\//-} + g_systemd_name=${src#-} + if [ ! -e /etc/systemd/system/${g_systemd_name}.automount ];then + die "no /etc/systemd/system/${g_systemd_name}.automount file!\n" + exit 1 + fi + + if [ ! -e /etc/systemd/system/${g_systemd_name}.mount ];then + die "no /etc/systemd/system/${g_systemd_name}.mount file!\n" + exit 1 + fi +} + +del_systemd() { + ${g_rm_cmd} /etc/systemd/system/${g_systemd_name}.automount + ${g_rm_cmd} /etc/systemd/system/${g_systemd_name}.mount + ${g_rm_cmd} /etc/systemd/system/multi-user.target.wants/${g_systemd_name}.automount + ${g_rm_cmd} /etc/systemd/system/multi-user.target.wants/${g_systemd_name}.mount + + ${g_systemctl_cmd} daemon-reload >& /dev/null + + ${g_umount_cmd} ${g_mountpoint} + + success "rm automount ${g_mountpoint} successfully" +} + +precheck +init +del_systemd