func Confirm(prompt, cancel string) (bool, error) {
   var yesRx = regexp.MustCompile("^(?:y(?:es)?)$")
   var noRx = regexp.MustCompile("^(?:n(?:o)?)$")
   var input string
   for {
      fmt.Printf("%s Yes [y/yes], No [n/no] : ", prompt)
      _, err := fmt.Scanln(&input)
      if err != nil {
         return false, err
      }
      if yesRx.MatchString(input) {
         return true, nil
      }
      if noRx.MatchString(input) {
         fmt.Println(cancel)
         return false, nil
      }
   }
}
func Confirm(prompt string) bool {
   var (
      inputStr string
      err      error
   )
   _, err = fmt.Fprint(os.Stdout, prompt)
   if err != nil {
      logger.Error("fmt.Fprint err", err)
      os.Exit(-1)
   }
   _, err = fmt.Scanf("%s", &inputStr)
   if err != nil {
      logger.Error("fmt.Scanf err", err)
      os.Exit(-1)
   }
   return GetConfirmResult(inputStr)
}
func GetConfirmResult(str string) bool {
   return YesRx.MatchString(str)
}
package install
import (
   "fmt"
   "os"
   "strings"
   "sync"
   "github.com/fanux/sealos/ipvs"
   "github.com/fanux/sealos/pkg/logger"
   sshcmd "github.com/fanux/sealos/pkg/sshcmd/cmd"
)
type SealosClean struct {
   SealosInstaller
   cleanAll bool
}
// BuildClean clean the build resources.
func BuildClean(deleteNodes, deleteMasters []string) {
   i := &SealosClean{cleanAll: false}
   masters := MasterIPs
   nodes := NodeIPs
   //1. 删除masters
   if len(deleteMasters) != 0 {
      if !CleanForce { // false
         prompt := fmt.Sprintf("clean command will clean masters [%s], continue clean (y/n)?", strings.Join(deleteMasters, ","))
         result := Confirm(prompt)
         if !result {
            logger.Debug("clean masters command is skip")
            goto node
         }
      }
      //只清除masters
      i.Masters = deleteMasters
   }
   //2. 删除nodes
node:
   if len(deleteNodes) != 0 {
      if !CleanForce { // flase
         prompt := fmt.Sprintf("clean command will clean nodes [%s], continue clean (y/n)?", strings.Join(deleteNodes, ","))
         result := Confirm(prompt)
         if !result {
            logger.Debug("clean nodes command is skip")
            goto all
         }
      }
      //只清除nodes
      i.Nodes = deleteNodes
   }
   //3. 删除所有节点
all:
   if len(deleteNodes) == 0 && len(deleteMasters) == 0 && CleanAll {
      if !CleanForce { // flase
         result := Confirm(`clean command will clean all masters and nodes, continue clean (y/n)?`)
         if !result {
            logger.Debug("clean all node command is skip")
            goto end
         }
      }
      // 所有master节点
      i.Masters = masters
      // 所有node节点
      i.Nodes = nodes
      i.cleanAll = true
   }
end:
   if len(i.Masters) == 0 && len(i.Nodes) == 0 {
      logger.Warn("clean nodes and masters is empty,please check your args and config.yaml.")
      os.Exit(-1)
   }
   i.CheckValid()
   i.Clean()
   if i.cleanAll {
      logger.Info("if clean all and clean sealos config")
      home, _ := os.UserHomeDir()
      cfgPath := home + defaultConfigPath
      sshcmd.Cmd("/bin/sh", "-c", "rm -rf "+cfgPath)
   }
}
//Clean clean cluster.
func (s *SealosClean) Clean() {
   var wg sync.WaitGroup
   //s 是要删除的数据
   //全局是当前的数据
   if len(s.Nodes) > 0 {
      //1. 再删除nodes
      for _, node := range s.Nodes {
         wg.Add(1)
         go func(node string) {
            defer wg.Done()
            s.cleanNode(node)
         }(node)
      }
      wg.Wait()
   }
   if len(s.Masters) > 0 {
      //2. 先删除master
      lock := sync.Mutex{}
      for _, master := range s.Masters {
         wg.Add(1)
         go func(master string) {
            lock.Lock()
            defer lock.Unlock()
            defer wg.Done()
            s.cleanMaster(master)
         }(master)
      }
      wg.Wait()
   }
}
func (s *SealosClean) cleanNode(node string) {
   cleanRoute(node)
   clean(node)
   //remove node
   NodeIPs = SliceRemoveStr(NodeIPs, node)
   if !s.cleanAll {
      logger.Debug("clean node in master")
      if len(MasterIPs) > 0 {
         hostname := isHostName(MasterIPs[0], node)
         cmd := "kubectl delete node %s"
         _ = SSHConfig.CmdAsync(MasterIPs[0], fmt.Sprintf(cmd, strings.TrimSpace(hostname)))
      }
   }
}
func (s *SealosClean) cleanMaster(master string) {
   clean(master)
   //remove master
   MasterIPs = SliceRemoveStr(MasterIPs, master)
   if !s.cleanAll {
      logger.Debug("clean node in master")
      if len(MasterIPs) > 0 {
         hostname := isHostName(MasterIPs[0], master)
         cmd := "kubectl delete node %s"
         _ = SSHConfig.CmdAsync(MasterIPs[0], fmt.Sprintf(cmd, strings.TrimSpace(hostname)))
      }
      //清空所有的nodes的数据
      yaml := ipvs.LvsStaticPodYaml(VIP, MasterIPs, LvscareImage)
      var wg sync.WaitGroup
      for _, node := range NodeIPs {
         wg.Add(1)
         go func(node string) {
            defer wg.Done()
            _ = SSHConfig.CmdAsync(node, "rm -rf  /etc/kubernetes/manifests/kube-sealyun-lvscare*")
            _ = SSHConfig.CmdAsync(node, fmt.Sprintf("mkdir -p /etc/kubernetes/manifests && echo '%s' > /etc/kubernetes/manifests/kube-sealyun-lvscare.yaml", yaml))
         }(node)
      }
      wg.Wait()
   }
}
func clean(host string) {
   cmd := "kubeadm reset -f " + vlogToStr()
   _ = SSHConfig.CmdAsync(host, cmd)
   cmd = `sed -i '/kubectl/d;/sealos/d' /root/.bashrc`
   _ = SSHConfig.CmdAsync(host, cmd)
   cmd = "modprobe -r ipip  && lsmod"
   _ = SSHConfig.CmdAsync(host, cmd)
   cmd = "rm -rf ~/.kube/ && rm -rf /etc/kubernetes/"
   _ = SSHConfig.CmdAsync(host, cmd)
   cmd = "rm -rf /etc/systemd/system/kubelet.service.d && rm -rf /etc/systemd/system/kubelet.service"
   _ = SSHConfig.CmdAsync(host, cmd)
   cmd = "rm -rf /usr/bin/kube* && rm -rf /usr/bin/crictl"
   _ = SSHConfig.CmdAsync(host, cmd)
   cmd = "rm -rf /etc/cni && rm -rf /opt/cni"
   _ = SSHConfig.CmdAsync(host, cmd)
   cmd = "rm -rf /var/lib/etcd && rm -rf /var/etcd"
   _ = SSHConfig.CmdAsync(host, cmd)
   cmd = fmt.Sprintf("sed -i \"/%s/d\" /etc/hosts ", APIServer)
   _ = SSHConfig.CmdAsync(host, cmd)
   cmd = "rm -rf ~/kube"
   _ = SSHConfig.CmdAsync(host, cmd)
   //clean pki certs
   cmd = "rm -rf /etc/kubernetes/pki"
   _ = SSHConfig.CmdAsync(host, cmd)
   //clean sealos in /usr/bin/ except exec sealos
   cmd = "ps -ef |grep -v 'grep'|grep sealos >/dev/null || rm -rf /usr/bin/sealos"
   _ = SSHConfig.CmdAsync(host, cmd)
}
func cleanRoute(node string) {
   // clean route
   cmdRoute := fmt.Sprintf("sealos route --host %s", IPFormat(node))
   status := SSHConfig.CmdToString(node, cmdRoute, "")
   if status != "ok" {
      // 删除为 vip创建的路由。
      delRouteCmd := fmt.Sprintf("sealos route del --host %s --gateway %s", VIP, IPFormat(node))
      SSHConfig.CmdToString(node, delRouteCmd, "")
   }
}