package cmd import ( "agent-wdd/cmd/beans" "agent-wdd/config" "agent-wdd/log" "agent-wdd/op" "agent-wdd/utils" "fmt" "runtime" "github.com/spf13/cobra" ) var ( ubuntuCommonTools = []string{ "iputils-ping", "net-tools", "dnsutils", "lsof", "curl", "wget", "mtr-tiny", "vim", "htop", "lrzsz", } centosCommonTools = []string{ "deltarpm", "net-tools", "iputils", "bind-utils", "lsof", "curl", "wget", "vim", "mtr", "htop", } dockerLocalInstallPath = "/root/wdd/docker-amd64-20.10.15.tgz" // 本地安装docker的文件路径 dockerComposeLocalInstallPath = "/root/wdd/docker-compose-v2.18.0-linux-amd64" // 本地安装docker compose的文件路径 ) func init() { switch runtime.GOARCH { case "amd64": dockerLocalInstallPath = "/root/wdd/docker-amd64-20.10.15.tgz" // 本地安装docker的文件路径 dockerComposeLocalInstallPath = "/root/wdd/docker-compose-v2.18.0-linux-amd64" // 本地安装docker compose的文件路径 case "arm64": dockerLocalInstallPath = "/root/wdd/docker-arm64-20.10.15.tgz" // 本地安装docker的文件路径 dockerComposeLocalInstallPath = "/root/wdd/docker-compose-v2.18.0-linux-arm64" // 本地安装docker compose的文件路径 } } // 添加base子命令 func addBaseSubcommands(cmd *cobra.Command) { // 1.1 docker dockerCmd := &cobra.Command{ Use: "docker", Short: "Docker相关操作", } addDockerSubcommands(dockerCmd) // 1.2 dockercompose dockerComposeCmd := &cobra.Command{ Use: "dockercompose", Short: "Docker Compose相关操作", } addDockerComposeSubcommands(dockerComposeCmd) // 其他base子命令... swapCmd := &cobra.Command{ Use: "swap", Short: "关闭系统的Swap", Run: func(cmd *cobra.Command, args []string) { log.Info("Swap 关闭!") // 实现这个函数,能够关闭centos或者ubuntu系统的swap // 备份文件存在,pass if !utils.FileExistAndNotNull("/etc/fstab_back_wdd_swap") { utils.AppendOverwriteContentToFile( "/etc/fstab", "/etc/fstab_back_wdd_swap", ) } // 执行关闭操作 op.SingleLineCommandExecutor([]string{ "swapoff", "-a", }) op.SingleLineCommandExecutor([]string{ "sed", "-i", "/swap/d", "/etc/fstab", }) log.Info("Swap 关闭成功!") }, } selinuxCmd := &cobra.Command{ Use: "selinux", Short: "关闭selinux", Run: func(cmd *cobra.Command, args []string) { log.Info("Selinux 关闭!") // 如果configCache的OS为空,则收集OS信息 if config.ConfigCache.Agent.OS.Hostname == "" { log.Warning("ConfigCache OS is nil") config.ConfigCache.Agent.OS.Gather() config.ConfigCache.Agent.OS.SaveConfig() } os := config.ConfigCache.Agent.OS if os.IsUbuntuType { log.Info("Ubuntu 系统,跳过关闭selinux!") return } else { op.SingleLineCommandExecutor([]string{ "setenforce", "0", }) // 备份一下/etc/selinux/config if !utils.FileExistAndNotNull("/etc/selinux/config_back_wdd_selinux") { utils.AppendOverwriteContentToFile( "/etc/selinux/config", "/etc/selinux/config_back_wdd_selinux", ) } // 持久化关闭selinux utils.FindAndDeleteContentInFile("SELINUX=enforcing", "/etc/selinux/config") utils.FindAndDeleteContentInFile("SELINUX=permissive", "/etc/selinux/config") utils.FindAndDeleteContentInFile("SELINUX=disabled", "/etc/selinux/config") utils.AppendContentToFile("SELINUX=disabled", "/etc/selinux/config") } log.Info("Selinux 关闭成功!") }, } firewallCmd := &cobra.Command{ Use: "firewall", Short: "关闭防火墙", Run: func(cmd *cobra.Command, args []string) { log.Info("Firewall 关闭!") // 调用systemd关闭firewalld op.SystemdDown("firewalld") op.SystemdDisable("firewalld") // 调用systemd关闭ufw op.SystemdDown("ufw") op.SystemdDisable("ufw") // 清空路由表 log.Info("清空路由表...") op.HardCodeCommandExecutor("iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -t raw -F") op.HardCodeCommandExecutor("ip6tables -F && ip6tables -t nat -F && ip6tables -t mangle -F && ip6tables -t raw -F") log.Info("Firewall 关闭成功!") }, } sysconfigCmd := &cobra.Command{ Use: "sysconfig", Short: "修改系统的sysconfig", Run: func(cmd *cobra.Command, args []string) { log.Info("Sysconfig 修改!") // 修改系统的sysconfig sysctlConfigFile := "/etc/sysctl.d/wdd-k8s.conf" if !utils.AppendOverwriteContentToFile(beans.SysctlConfig, sysctlConfigFile) { log.Error("[ModifySysConfigBastion] - error appending sysctl config to sysctl.d !") return } op.SingleLineCommandExecutor([]string{ "sysctl", "-p", sysctlConfigFile, }) log.Info("Sysconfig 修改成功!") }, } // 通用工具安装 commonToolsInstall := &cobra.Command{ Use: "tools", Short: "通用工具安装 利用本机的yum,apt等从网络安装常用的软件", Run: func(cmd *cobra.Command, args []string) { log.Info("Common tool installation!") // Whether It can connect to internet if config.CanConnectInternet() <= 1 { log.Error("服务器无法连接互联网,无法执行tools") return } // package install // only support ubuntu(debian) centos(debian openEuler) packOperator := op.AgentPackOperator packOperator.PackageInit() os := config.ConfigCache.Agent.OS if os.IsUbuntuType { packOperator.Install(ubuntuCommonTools) } else { packOperator.Install(centosCommonTools) } }, } sshCmd := &cobra.Command{ Use: "ssh", Short: "修改ssh配置", } addSSHSubcommands(sshCmd) cmd.AddCommand( dockerCmd, dockerComposeCmd, swapCmd, commonToolsInstall, selinuxCmd, firewallCmd, sysconfigCmd, sshCmd, // 其他命令... ) } func addSSHSubcommands(sshCmd *cobra.Command) { keyCmd := &cobra.Command{ Use: "key", Short: "安装默认的ssh-key", Run: func(cmd *cobra.Command, args []string) { log.Info("安装默认的ssh-key!") // 创建.ssh目录 utils.CreateFolder("/root/.ssh") // 检查密钥是否存在 if utils.FileExistAndNotNull("/root/.ssh/id_ed25519") && utils.FileExistAndNotNull("/root/.ssh/id_ed25519.pub") && utils.FindContentInFile("wdd@cmii.com", "/root/.ssh/authorized_keys") { log.Info("SSH密钥已存在,无需重新安装。") return } // 下载标准的私钥和公钥 if !utils.AppendOverwriteContentToFile(beans.Ed25519PrivateKey, "/root/.ssh/id_ed25519") { log.Error("[InstallDefaultSSHKey] - error appending private ssh key to authorized_keys !") return } if !utils.AppendOverwriteContentToFile(beans.Ed25519PublicKey, "/root/.ssh/id_ed25519.pub") { log.Error("[InstallDefaultSSHKey] - error appending public ssh key to authorized_keys !") return } // 写入到authorized_keys if !utils.AppendFileToFile("/root/.ssh/id_ed25519.pub", "/root/.ssh/authorized_keys") { log.Error("[InstallDefaultSSHKey] - error appending ssh key to authorized_keys !") return } // 设置权限 op.SingleLineCommandExecutor([]string{ "chmod", "600", "/root/.ssh/id_ed25519", }) // 检查 if utils.FindContentInFile("wdd@cmii.com", "/root/.ssh/authorized_keys") { log.Info("[InstallDefaultSSHKey] - install success !") } else { log.Error("[InstallDefaultSSHKey] - authorized_keys don't contain the ssh-pub key !") } }, } portCmd := &cobra.Command{ Use: "port", Short: "修改ssh端口", Run: func(cmd *cobra.Command, args []string) { log.Info("修改ssh端口!") // 检查参数 if len(args) > 0 { fmt.Printf("modify ssh port to: %s\n", args[0]) } // 没有传递参数,使用默认参数 port := "22333" log.Info("[ModifySSHPort] modify ssh port to: %s", port) // 修改ssh端口 utils.AppendContentToFile(fmt.Sprintf("Port %s", port), "/etc/ssh/sshd_config") // 重启ssh服务 ok, resultLog := op.SystemdRestart("sshd") if !ok { log.Error("[ModifySSHPort] restart sshd error: %s", resultLog) return } log.Info("[ModifySSHPort] modify ssh port to: %s success!", port) }, } configCmd := &cobra.Command{ Use: "config", Short: "修改ssh配置 为wdd默认配置!", Run: func(cmd *cobra.Command, args []string) { log.Info("修改ssh配置 为wdd默认配置!") // 备份文件 if !utils.FileExistAndNotNull("/etc/ssh/sshd_config_back_wdd_ssh") { utils.AppendOverwriteContentToFile("/etc/ssh/sshd_config", "/etc/ssh/sshd_config_back_wdd_ssh") } // 修改ssh配置 utils.AppendContentToFile(beans.DefaultSshdConfig, "/etc/ssh/sshd_config") // 重启ssh服务 ok, resultLog := op.SystemdRestart("sshd") if !ok { log.Error("sshd 重启失败: %s", resultLog) return } log.Info("[sshd配置修改] 成功!") }, } sshCmd.AddCommand(keyCmd, portCmd, configCmd) } // 添加docker子命令 func addDockerSubcommands(cmd *cobra.Command) { onlineCmd := &cobra.Command{ Use: "online [version]", Short: "网络安装Docker", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { // 检查参数 if len(args) > 0 { fmt.Printf("Installing Docker version: %s\n", args[0]) } // 没有传递参数,使用默认参数 version := "20.10.15" log.Info("Installing Docker version: %s", version) // 安装docker packOperator := op.AgentPackOperator packOperator.PackageInit() // ubuntu 和 centos的安装命令是不是一样的 packOperator.Install([]string{"docker-ce", "docker-ce-cli", "containerd.io", "docker-buildx-plugin", "docker-compose-plugin"}) }, } removeCmd := &cobra.Command{ Use: "remove", Short: "卸载Docker", Run: func(cmd *cobra.Command, args []string) { fmt.Println("Removing Docker...") }, } localCmd := &cobra.Command{ Use: "local [path]", Short: "本地安装Docker", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { log.Info("Installing Docker from local file: %s", dockerLocalInstallPath) exist := utils.FileExistAndNotNull(dockerLocalInstallPath) if !exist { log.Error("Docker local install file not found: %s", dockerLocalInstallPath) return } // 解压文件 utils.UnzipFile(dockerLocalInstallPath, "/root/wdd") // 安装docker err := utils.MoveFolerToAnother("/root/wdd/docker", "/usr/bin") if err != nil { log.Error("Failed to move Docker binaries: %s", err.Error()) return } // 设置权限 chmodCmd := []string{"chmod", "777", "-R", "/usr/bin/docker*"} ok, resultLog := op.SingleLineCommandExecutor(chmodCmd) if !ok { log.Error("Failed to set permissions for Docker binaries: %s", resultLog) return } // 配置并启动Docker服务 // systemd daemonize docker utils.AppendOverwriteContentToFile(beans.ContainerdDaemonService, beans.ContainerdServiceFile) if !utils.FileExistAndNotNull(beans.ContainerdServiceFile) { log.Error("docker deamon file not exists !") } utils.AppendOverwriteContentToFile(beans.DockerSocketDaemonService, beans.DockerSocketFile) if !utils.FileExistAndNotNull(beans.DockerSocketFile) { log.Error("docker deamon file not exists !") } utils.AppendOverwriteContentToFile(beans.DockerDaemonService, beans.DockerServiceFile) if !utils.FileExistAndNotNull(beans.DockerServiceFile) { log.Error("docker deamon file not exists !") } log.Info("docker dameon file append success !") ok, resultLog = op.SystemdDaemonReload() if !ok { log.Error("daemon reload error ! %s", resultLog) return } op.SingleLineCommandExecutor([]string{"systemctl", "unmask", "containerd"}) op.SingleLineCommandExecutor([]string{"systemctl", "unmask", "docker.socket"}) op.SingleLineCommandExecutor([]string{"systemctl", "unmask", "docker"}) op.SingleLineCommandExecutor([]string{"groupadd", "docker"}) op.SingleLineCommandExecutor([]string{"usermod", "-aG", "docker", "root"}) op.SingleLineCommandExecutor([]string{"newgrp", "docker"}) systemdUp, resultLog := op.SystemdUp("containerd") if !systemdUp { log.Error("[InstallDockerBastion] - start containerd service error ! %s", resultLog) return } ok, resultLog = op.SystemdUp("docker.socket") if !ok { log.Error("[InstallDockerBastion] - start docker.socket error ! %s", resultLog) return } ok, resultLog = op.SystemdUp("docker") if !ok { log.Error("[InstallDockerBastion] - start docker service error ! %s", resultLog) return } log.Info("Docker installed successfully from local file!") }, } cmd.AddCommand(onlineCmd, removeCmd, localCmd) } func addDockerComposeSubcommands(cmd *cobra.Command) { installCmd := &cobra.Command{ Use: "online [version]", Short: "安装Docker Compose", Run: func(cmd *cobra.Command, args []string) { log.Info("Installing Docker Compose...") // 检查参数 if len(args) > 0 { fmt.Printf("Installing Docker Compose version: %s\n", args[0]) } // 默认安装最新版本 version := "latest" if len(args) > 0 { version = args[0] } // 如果是最新版本,则通过GitHub API查询 if version == "latest" { latestVersion, err := op.GetLatestGithubReleaseVersion("docker", "compose") if err != nil { log.Error("获取Docker Compose最新版本失败: %s", err) } else { version = latestVersion log.Info("获取到Docker Compose最新版本: %s", version) } } log.Info("安装 Docker Compose 版本: %s", version) // 检查是否可以连接互联网 if config.CanConnectInternet() <= 1 { log.Error("服务器无法连接互联网,无法在线安装 Docker Compose") return } // 检查 Docker 是否已安装 dockerExists := op.CommandExistsByPath("docker") if !dockerExists { log.Error("Docker 未安装,请先安装 Docker") return } // 根据架构选择合适的下载链接 arch := runtime.GOARCH downloadURL := fmt.Sprintf("https://github.com/docker/compose/releases/download/%s/docker-compose-linux-%s", version, arch) log.Info("Downloading Docker Compose from: %s", downloadURL) // 下载 Docker Compose ok, ccc := op.DownloadFile(downloadURL, "/usr/local/bin/docker-compose") if !ok { log.Error("下载 Docker Compose 失败: %s", ccc) return } // 设置执行权限 chmodCmd := []string{"chmod", "+x", "/usr/local/bin/docker-compose"} ok, resultLog := op.SingleLineCommandExecutor(chmodCmd) if !ok { log.Error("设置 Docker Compose 权限失败: %s", resultLog) return } // 创建软链接 linkCmd := []string{"ln", "-sf", "/usr/local/bin/docker-compose", "/usr/bin/docker-compose"} op.SingleLineCommandExecutor(linkCmd) // 验证安装 verifyCmd := []string{"docker-compose", "--version"} ok, resultLog = op.SingleLineCommandExecutor(verifyCmd) if !ok { log.Error("Docker Compose 安装验证失败: %s", resultLog) return } log.Info("Docker Compose 安装成功: %s", resultLog) }, } removeCmd := &cobra.Command{ Use: "remove", Short: "卸载Docker Compose", Run: func(cmd *cobra.Command, args []string) { log.Info("Removing Docker Compose...") if utils.RemoveFile("/usr/local/bin/docker-compose") { log.Info("Docker Compose removed successfully!") } else { log.Error("Failed to remove Docker Compose!") } }, } localCmd := &cobra.Command{ Use: "local [path]", Short: "本地安装Docker Compose", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { log.Info("Installing Docker Compose from local file...") exist := utils.FileExistAndNotNull(dockerLocalInstallPath) if !exist { log.Error("Docker local install file not found: %s", dockerLocalInstallPath) return } // move file to /usr/local/bin err := utils.MoveFolerToAnother(dockerComposeLocalInstallPath, "/usr/local/bin") if err != nil { log.Error("Failed to move Docker Compose binaries: %s", err.Error()) return } // set permission chmodCmd := []string{"chmod", "+x", "/usr/local/bin/docker-compose"} ok, resultLog := op.SingleLineCommandExecutor(chmodCmd) if !ok { log.Error("Failed to set permissions for Docker Compose binaries: %s", resultLog) return } log.Info("Docker Compose installed successfully from local file!") }, } versionCmd := &cobra.Command{ Use: "version", Short: "查看Docker Compose版本", Run: func(cmd *cobra.Command, args []string) { log.Info("Docker Compose version...") ok, resultLog := op.SingleLineCommandExecutor([]string{"docker-compose", "--version"}) if !ok { log.Error("Failed to get Docker Compose version: %s", resultLog) return } log.Info("Docker Compose version: %s", resultLog) }, } cmd.AddCommand( installCmd, removeCmd, localCmd, versionCmd, ) }