diff --git a/pkg/cluster/manager/cleanup.go b/pkg/cluster/manager/cleanup.go index 7db1472236..cd0311e84c 100644 --- a/pkg/cluster/manager/cleanup.go +++ b/pkg/cluster/manager/cleanup.go @@ -14,6 +14,10 @@ package manager import ( + "fmt" + "path" + "strings" + "github.com/fatih/color" "github.com/joomcode/errorx" perrs "github.com/pingcap/errors" @@ -22,6 +26,7 @@ import ( "github.com/pingcap/tiup/pkg/cluster/spec" "github.com/pingcap/tiup/pkg/cluster/task" "github.com/pingcap/tiup/pkg/logger/log" + "github.com/pingcap/tiup/pkg/set" ) // CleanCluster cleans the cluster without destroying it @@ -39,6 +44,44 @@ func (m *Manager) CleanCluster(name string, gOpt operator.Options, cleanOpt oper return err } + // calculate file paths to be deleted before the prompt + delFileMap := make(map[string]set.StringSet) + for _, com := range topo.ComponentsByStopOrder() { + instances := com.Instances() + retainDataRoles := set.NewStringSet(cleanOpt.RetainDataRoles...) + retainDataNodes := set.NewStringSet(cleanOpt.RetainDataNodes...) + + for _, ins := range instances { + // Some data of instances will be retained + dataRetained := retainDataRoles.Exist(ins.ComponentName()) || + retainDataNodes.Exist(ins.ID()) || retainDataNodes.Exist(ins.GetHost()) + + if dataRetained { + continue + } + + dataPaths := set.NewStringSet() + logPaths := set.NewStringSet() + + if cleanOpt.CleanupData && len(ins.DataDir()) > 0 { + for _, dataDir := range strings.Split(ins.DataDir(), ",") { + dataPaths.Insert(path.Join(dataDir, "*")) + } + } + + if cleanOpt.CleanupLog && len(ins.LogDir()) > 0 { + for _, logDir := range strings.Split(ins.LogDir(), ",") { + logPaths.Insert(path.Join(logDir, "*.log")) + } + } + + if delFileMap[ins.GetHost()] == nil { + delFileMap[ins.GetHost()] = set.NewStringSet() + } + delFileMap[ins.GetHost()].Join(logPaths).Join(dataPaths) + } + } + if !skipConfirm { target := "" switch { @@ -49,14 +92,25 @@ func (m *Manager) CleanCluster(name string, gOpt operator.Options, cleanOpt oper case cleanOpt.CleanupLog: target = "log" } + + // build file list string + delFileList := "" + for host, fileList := range delFileMap { + delFileList += fmt.Sprintf("\n%s:", color.CyanString(host)) + for _, dfp := range fileList.Slice() { + delFileList += fmt.Sprintf("\n %s", dfp) + } + } + if err := cliutil.PromptForConfirmOrAbortError( - "This operation will clean %s %s cluster %s's %s.\nNodes will be ignored: %s\nRoles will be ignored: %s\nDo you want to continue? [y/N]:", + "This operation will clean %s %s cluster %s's %s.\nNodes will be ignored: %s\nRoles will be ignored: %s\nFiles to be deleted are: %s\nDo you want to continue? [y/N]:", m.sysName, color.HiYellowString(base.Version), color.HiYellowString(name), target, cleanOpt.RetainDataNodes, - cleanOpt.RetainDataRoles); err != nil { + cleanOpt.RetainDataRoles, + delFileList); err != nil { return err } log.Infof("Cleanup cluster...") @@ -67,7 +121,7 @@ func (m *Manager) CleanCluster(name string, gOpt operator.Options, cleanOpt oper return operator.Stop(ctx, topo, operator.Options{}, tlsCfg) }). Func("CleanupCluster", func(ctx *task.Context) error { - return operator.Cleanup(ctx, topo, cleanOpt) + return operator.CleanupComponent(ctx, delFileMap) }). Build() diff --git a/pkg/cluster/operation/destroy.go b/pkg/cluster/operation/destroy.go index af60af70da..97f195eb73 100644 --- a/pkg/cluster/operation/destroy.go +++ b/pkg/cluster/operation/destroy.go @@ -18,7 +18,6 @@ import ( "crypto/tls" "fmt" "io/ioutil" - "path" "path/filepath" "strconv" "strings" @@ -34,24 +33,6 @@ import ( "github.com/pingcap/tiup/pkg/set" ) -// Cleanup the cluster -func Cleanup( - getter ExecutorGetter, - cluster spec.Topology, - options Options, -) error { - coms := cluster.ComponentsByStopOrder() - - for _, com := range coms { - insts := com.Instances() - if err := CleanupComponent(getter, insts, cluster, options); err != nil { - return errors.Annotatef(err, "failed to cleanup %s", com.Name()) - } - } - - return nil -} - // Destroy the cluster. func Destroy( getter ExecutorGetter, @@ -291,41 +272,11 @@ func DestroyMonitored(getter ExecutorGetter, inst spec.Instance, options *spec.M } // CleanupComponent cleanup the instances -func CleanupComponent(getter ExecutorGetter, instances []spec.Instance, cls spec.Topology, options Options) error { - retainDataRoles := set.NewStringSet(options.RetainDataRoles...) - retainDataNodes := set.NewStringSet(options.RetainDataNodes...) - - for _, ins := range instances { - // Some data of instances will be retained - dataRetained := retainDataRoles.Exist(ins.ComponentName()) || - retainDataNodes.Exist(ins.ID()) || retainDataNodes.Exist(ins.GetHost()) - - if dataRetained { - continue - } - - e := getter.Get(ins.GetHost()) - log.Infof("Cleanup instance %s", ins.GetHost()) - - delFiles := set.NewStringSet() - dataPaths := set.NewStringSet() - logPaths := set.NewStringSet() - - if options.CleanupData && len(ins.DataDir()) > 0 { - for _, dataDir := range strings.Split(ins.DataDir(), ",") { - dataPaths.Insert(path.Join(dataDir, "*")) - } - } - - if options.CleanupLog && len(ins.LogDir()) > 0 { - for _, logDir := range strings.Split(ins.LogDir(), ",") { - logPaths.Insert(path.Join(logDir, "*.log")) - } - } - - delFiles.Join(logPaths).Join(dataPaths) - - log.Debugf("Deleting paths on %s: %s", ins.GetHost(), strings.Join(delFiles.Slice(), " ")) +func CleanupComponent(getter ExecutorGetter, delFileMaps map[string]set.StringSet) error { + for host, delFiles := range delFileMaps { + e := getter.Get(host) + log.Infof("Cleanup instance %s", host) + log.Debugf("Deleting paths on %s: %s", host, strings.Join(delFiles.Slice(), " ")) c := module.ShellModuleConfig{ Command: fmt.Sprintf("rm -rf %s;", strings.Join(delFiles.Slice(), " ")), Sudo: true, // the .service files are in a directory owned by root @@ -343,11 +294,10 @@ func CleanupComponent(getter ExecutorGetter, instances []spec.Instance, cls spec } if err != nil { - return errors.Annotatef(err, "failed to cleanup: %s", ins.GetHost()) + return errors.Annotatef(err, "failed to cleanup: %s", host) } - log.Infof("Cleanup %s success", ins.GetHost()) - log.Infof("- Clanup %s files: %v", ins.ComponentName(), delFiles.Slice()) + log.Infof("Cleanup %s success", host) } return nil