Enhance Docker Installation and Management Commands
- Improved Docker installation process for Ubuntu systems - Added support for dynamic Docker version detection - Enhanced Docker local and online installation commands - Implemented more robust Docker removal functionality - Updated Docker installation to use system-specific package sources - Added better error handling and logging for Docker operations - Refined Docker service startup and configuration checks
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"agent-wdd/utils"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -282,8 +283,14 @@ func addSSHSubcommands(sshCmd *cobra.Command) {
|
||||
port := "22333"
|
||||
log.Info("[ModifySSHPort] modify ssh port to: %s", port)
|
||||
|
||||
// 文件中已经包含了Port 22333 则pass
|
||||
sshdPortString := fmt.Sprintf("Port %s", port)
|
||||
if utils.FindContentInFile(sshdPortString, "/etc/ssh/sshd_config") {
|
||||
log.Info("[ModifySSHPort] ssh port already modified to: %s", port)
|
||||
} else {
|
||||
// 修改ssh端口
|
||||
utils.AppendContentToFile(fmt.Sprintf("Port %s", port), "/etc/ssh/sshd_config")
|
||||
utils.AppendContentToFile(sshdPortString, "/etc/ssh/sshd_config")
|
||||
}
|
||||
|
||||
// 重启ssh服务
|
||||
ok, resultLog := op.SystemdRestart("sshd")
|
||||
@@ -309,7 +316,7 @@ func addSSHSubcommands(sshCmd *cobra.Command) {
|
||||
}
|
||||
|
||||
// 修改ssh配置
|
||||
utils.AppendContentToFile(beans.DefaultSshdConfig, "/etc/ssh/sshd_config")
|
||||
utils.AppendOverwriteContentToFile(beans.DefaultSshdConfig, "/etc/ssh/sshd_config")
|
||||
|
||||
// 重启ssh服务
|
||||
ok, resultLog := op.SystemdRestart("sshd")
|
||||
@@ -330,8 +337,7 @@ func addSSHSubcommands(sshCmd *cobra.Command) {
|
||||
func addDockerSubcommands(cmd *cobra.Command) {
|
||||
onlineCmd := &cobra.Command{
|
||||
Use: "online [version]",
|
||||
Short: "网络安装Docker",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Short: "网络安装Docker, 如果不指定参数默认安装20.10.15版本",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
// 检查参数
|
||||
@@ -339,15 +345,124 @@ func addDockerSubcommands(cmd *cobra.Command) {
|
||||
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"})
|
||||
|
||||
configCache := config.ConfigCache
|
||||
if configCache.Agent.OS.IsUbuntuType {
|
||||
// 安装apt-transport-https ca-certificates curl gnupg software-properties-common 依赖部分
|
||||
packOperator.Install([]string{"apt-transport-https", "ca-certificates", "curl", "gnupg", "software-properties-common"})
|
||||
|
||||
// 安装docker的 gpg key
|
||||
dockerGPGFilePath := "/etc/apt/keyrings/docker.gpg"
|
||||
dockerAPTFilePath := "/etc/apt/sources.list.d/docker.list"
|
||||
dockerGPGSource := "https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg"
|
||||
dockerAPTSource := "https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu"
|
||||
|
||||
// 创建docker的 gpg key 文件
|
||||
utils.CreateFolder("/etc/apt/keyrings")
|
||||
|
||||
// 删除docker的 gpg key 文件
|
||||
utils.RemoveFile(dockerGPGFilePath)
|
||||
utils.RemoveFile(dockerAPTFilePath)
|
||||
|
||||
// 如果可以访问外网,则使用外网源
|
||||
if configCache.Agent.Network.Internet == 9 {
|
||||
dockerGPGSource = "https://download.docker.com/linux/ubuntu/gpg"
|
||||
dockerAPTSource = "https://download.docker.com/linux/ubuntu"
|
||||
}
|
||||
|
||||
ok, l2 := op.PipeLineCommandExecutor([][]string{
|
||||
{
|
||||
"curl",
|
||||
"-fsSL",
|
||||
dockerGPGSource,
|
||||
},
|
||||
{
|
||||
"gpg",
|
||||
"--dearmor",
|
||||
"-o",
|
||||
dockerGPGFilePath,
|
||||
},
|
||||
})
|
||||
|
||||
if !ok {
|
||||
log.Error("下载docker gpg文件失败: %s", l2)
|
||||
return
|
||||
}
|
||||
|
||||
if !utils.FileExistAndNotNull(dockerGPGFilePath) {
|
||||
log.Error("添加gpg失败!")
|
||||
return
|
||||
}
|
||||
|
||||
op.SingleLineCommandExecutor([]string{
|
||||
"chmod",
|
||||
"a+r",
|
||||
dockerGPGFilePath,
|
||||
},
|
||||
)
|
||||
|
||||
if configCache.Agent.OS.OSReleaseCode == "" {
|
||||
log.Error("获取系统发行版代号失败! 无法安装docker!")
|
||||
return
|
||||
}
|
||||
|
||||
dockerAPTSourceCommand := "deb [arch=" + configCache.Agent.OS.Arch + " signed-by=" + dockerGPGFilePath + "] " + dockerAPTSource + " " + configCache.Agent.OS.OSReleaseCode + " stable"
|
||||
|
||||
log.Info("dockerAPTSourceCommand is => %s ", dockerAPTSourceCommand)
|
||||
|
||||
utils.AppendOverwriteContentToFile(dockerAPTSourceCommand, dockerAPTFilePath)
|
||||
|
||||
// 强制初始化APT update
|
||||
packOperator.PackageInitForce()
|
||||
|
||||
// 20.04 default
|
||||
specificDockerVersion := "5:20.10.24~3-0~ubuntu-" + configCache.Agent.OS.OSReleaseCode
|
||||
// apt-cache madison docker-ce | grep 20.10.20 | awk '{print$3}'
|
||||
|
||||
// get by method
|
||||
ok, log4 := op.HardCodeCommandExecutor("apt-cache madison docker-ce | grep 20.10.20 | awk '{print$3}'")
|
||||
if ok && log4 != nil && len(log4) > 0 {
|
||||
specificDockerVersion = strings.TrimSpace(log4[0])
|
||||
fmt.Println("get docker version from online => " + specificDockerVersion)
|
||||
}
|
||||
|
||||
log.Info("需要安装的docker版本为 => %s", specificDockerVersion)
|
||||
|
||||
dockerStaffList := []string{
|
||||
"docker-ce=" + specificDockerVersion,
|
||||
"docker-ce-cli=" + specificDockerVersion,
|
||||
"containerd.io",
|
||||
"docker-compose-plugin",
|
||||
}
|
||||
|
||||
ok = packOperator.Install(dockerStaffList)
|
||||
if !ok {
|
||||
log.Error("安装docker存在问题,请检查!")
|
||||
return
|
||||
}
|
||||
|
||||
} else {
|
||||
log.Error("当前系统不是ubuntu系统,暂时无法安装docker!")
|
||||
return
|
||||
}
|
||||
|
||||
log.Info("安装docker成功!")
|
||||
|
||||
// 启动docker
|
||||
op.SystemdUp("docker")
|
||||
op.SystemdEnable("docker")
|
||||
|
||||
// 检查docker是否启动成功
|
||||
ok, resultLog := op.SystemIsRunning("docker")
|
||||
if !ok {
|
||||
log.Error("docker启动失败: %s", resultLog)
|
||||
return
|
||||
}
|
||||
|
||||
log.Info("docker启动成功! ")
|
||||
|
||||
},
|
||||
}
|
||||
@@ -357,13 +472,45 @@ func addDockerSubcommands(cmd *cobra.Command) {
|
||||
Short: "卸载Docker",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println("Removing Docker...")
|
||||
|
||||
// 检查docker是二进制安装还是通过包安装的
|
||||
dockerExists := op.CommandExistsByPath("docker")
|
||||
if !dockerExists {
|
||||
log.Info("Docker 未安装,无需卸载!")
|
||||
return
|
||||
}
|
||||
|
||||
// 卸载docker
|
||||
packOperator := op.AgentPackOperator
|
||||
packOperator.PackageInit()
|
||||
packOperator.Remove([]string{"docker-ce", "docker-ce-cli", "containerd.io", "docker-buildx-plugin", "docker-compose-plugin"})
|
||||
|
||||
// 删除docker目录
|
||||
utils.RemoveFile("/usr/bin/docker")
|
||||
utils.RemoveFile("/usr/bin/docker-compose")
|
||||
utils.RemoveFile("/usr/bin/docker-buildx")
|
||||
utils.RemoveFile("/usr/bin/docker-compose-plugin")
|
||||
utils.RemoveFile("/usr/bin/containerd")
|
||||
|
||||
// 删除docker的配置文件 systemd
|
||||
utils.RemoveFile("/etc/systemd/system/docker.service")
|
||||
utils.RemoveFile("/etc/systemd/system/docker.socket")
|
||||
utils.RemoveFile("/etc/systemd/system/containerd.service")
|
||||
utils.RemoveFile(beans.ContainerdServiceFile)
|
||||
utils.RemoveFile(beans.DockerSocketFile)
|
||||
utils.RemoveFile(beans.DockerServiceFile)
|
||||
|
||||
// 删除docker的日志文件
|
||||
utils.RemoveFile("/var/log/docker")
|
||||
|
||||
log.Info("Docker 卸载成功!")
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
localCmd := &cobra.Command{
|
||||
Use: "local [path]",
|
||||
Short: "本地安装Docker",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Use: "local",
|
||||
Short: "本地安装Docker, 默认安装20.10.15版本, 安装目录为 " + dockerLocalInstallPath,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
log.Info("Installing Docker from local file: %s", dockerLocalInstallPath)
|
||||
@@ -385,12 +532,25 @@ func addDockerSubcommands(cmd *cobra.Command) {
|
||||
}
|
||||
|
||||
// 设置权限
|
||||
chmodCmd := []string{"chmod", "777", "-R", "/usr/bin/docker*"}
|
||||
ok, resultLog := op.SingleLineCommandExecutor(chmodCmd)
|
||||
dockerBinList := []string{
|
||||
"docker-init",
|
||||
"containerd",
|
||||
"ctr",
|
||||
"runc",
|
||||
"dockerd",
|
||||
"docker-proxy",
|
||||
"containerd-shim",
|
||||
"docker",
|
||||
"containerd-shim-runc-v2",
|
||||
}
|
||||
|
||||
for _, bin := range dockerBinList {
|
||||
ok, resultLog := op.HardCodeCommandExecutor("chmod 777 /usr/bin/" + bin)
|
||||
if !ok {
|
||||
log.Error("Failed to set permissions for Docker binaries: %s", resultLog)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 配置并启动Docker服务
|
||||
// systemd daemonize docker
|
||||
@@ -408,7 +568,7 @@ func addDockerSubcommands(cmd *cobra.Command) {
|
||||
}
|
||||
log.Info("docker dameon file append success !")
|
||||
|
||||
ok, resultLog = op.SystemdDaemonReload()
|
||||
ok, resultLog := op.SystemdDaemonReload()
|
||||
if !ok {
|
||||
log.Error("daemon reload error ! %s", resultLog)
|
||||
return
|
||||
|
||||
@@ -76,13 +76,13 @@ func addZshSubcommands(cmd *cobra.Command) {
|
||||
log.Info("安装zsh完成, 开始安装插件!")
|
||||
|
||||
pluginsHardCodeUrl := []string{
|
||||
"git clone https://gitee.com/wangl-cc/zsh-autosuggestions.git ~/.oh-my-zsh/plugins/zsh-autosuggestions",
|
||||
"git clone https://gitee.com/xiaoqqya/zsh-syntax-highlighting.git ~/.oh-my-zsh/plugins/zsh-syntax-highlighting",
|
||||
"git clone https://gitee.com/wangl-cc/zsh-autosuggestions.git /root/.oh-my-zsh/plugins/zsh-autosuggestions",
|
||||
"git clone https://gitee.com/xiaoqqya/zsh-syntax-highlighting.git /root/.oh-my-zsh/plugins/zsh-syntax-highlighting",
|
||||
}
|
||||
|
||||
pluginsHardCodeOutsideUrl := []string{
|
||||
"git clone https://github.com/zsh-users/zsh-autosuggestions ~/.oh-my-zsh/plugins/zsh-autosuggestions",
|
||||
"git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ~/.oh-my-zsh/plugins/zsh-syntax-highlighting",
|
||||
"git clone https://github.com/zsh-users/zsh-autosuggestions /root/.oh-my-zsh/plugins/zsh-autosuggestions",
|
||||
"git clone https://github.com/zsh-users/zsh-syntax-highlighting.git /root/.oh-my-zsh/plugins/zsh-syntax-highlighting",
|
||||
}
|
||||
|
||||
pluginsListUrl := []string{
|
||||
@@ -122,9 +122,9 @@ func addZshSubcommands(cmd *cobra.Command) {
|
||||
}
|
||||
|
||||
// 修改ZSH配置
|
||||
utils.FindAndReplaceContentInFile("/root/.zshrc", "robbyrussell", "agnoster")
|
||||
utils.FindAndReplaceContentInFile("/root/.zshrc", "# DISABLE_AUTO_UPDATE=\"true\"", "DISABLE_AUTO_UPDATE=\"true\"")
|
||||
utils.FindAndReplaceContentInFile("/root/.zshrc", "plugins=(git)", "plugins=(git zsh-autosuggestions zsh-syntax-highlighting command-not-found z themes)")
|
||||
utils.FindAndReplaceContentInFile("robbyrussell", "agnoster", "/root/.zshrc")
|
||||
utils.FindAndReplaceContentInFile("# DISABLE_AUTO_UPDATE=\"true\"", "DISABLE_AUTO_UPDATE=\"true\"", "/root/.zshrc")
|
||||
utils.FindAndReplaceContentInFile("plugins=(git)", "plugins=(git zsh-autosuggestions zsh-syntax-highlighting command-not-found z themes)", "/root/.zshrc")
|
||||
|
||||
//
|
||||
op.SingleLineCommandExecutor([]string{
|
||||
|
||||
@@ -15,13 +15,17 @@ var rootCmd = &cobra.Command{
|
||||
Short: "wdd应用程序是wdd封装的NB工具",
|
||||
Long: `使用golang的强大特性,加上 WDD 的高超技术,打造一个方便、高效、适用于各种LINUX系统的瑞士军刀工具!
|
||||
尽情享用! 尽情享用! 尽情享用!`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
// Do Stuff Here
|
||||
DisableAutoGenTag: true,
|
||||
CompletionOptions: cobra.CompletionOptions{
|
||||
DisableDefaultCmd: true,
|
||||
DisableNoDescFlag: true,
|
||||
DisableDescriptions: true,
|
||||
HiddenDefaultCmd: true,
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
// 初始化配置
|
||||
cobra.OnInitialize(config.InitConfig)
|
||||
}
|
||||
|
||||
@@ -138,7 +142,7 @@ func Execute() {
|
||||
|
||||
func printAllCommands(cmd *cobra.Command, writer io.Writer) {
|
||||
// 打印命令标题
|
||||
fmt.Fprintf(writer, "Available commands:\n")
|
||||
fmt.Fprintf(writer, "All available commands:\n\n")
|
||||
|
||||
// 递归打印命令树
|
||||
var traverse func(*cobra.Command, int)
|
||||
|
||||
@@ -50,15 +50,16 @@ type Agent struct {
|
||||
}
|
||||
|
||||
type OS struct {
|
||||
Hostname string `yaml:"hostname"`
|
||||
OsName string `yaml:"os_name"`
|
||||
OsFamily string `yaml:"os_family"`
|
||||
OsVersion string `yaml:"os_version"`
|
||||
OsType string `yaml:"os_type"`
|
||||
Kernel string `yaml:"kernel"`
|
||||
Arch string `yaml:"arch"`
|
||||
IsUbuntuType bool `yaml:"is_ubuntu_type" comment:"是否是ubuntu类型的操作系统"`
|
||||
PackInit bool `yaml:"pack_init" comment:"是否初始化,ubuntu需要"`
|
||||
Hostname string `mapstructure:"hostname" yaml:"hostname" comment:"主机名"`
|
||||
OsName string `mapstructure:"os_name" yaml:"os_name" comment:"操作系统名称"`
|
||||
OsFamily string `mapstructure:"os_family" yaml:"os_family" comment:"操作系统家族"`
|
||||
OsVersion string `mapstructure:"os_version" yaml:"os_version" comment:"操作系统版本"`
|
||||
OsType string `mapstructure:"os_type" yaml:"os_type" comment:"操作系统类型"`
|
||||
Kernel string `mapstructure:"kernel" yaml:"kernel" comment:"内核版本"`
|
||||
Arch string `mapstructure:"arch" yaml:"arch" comment:"架构"`
|
||||
IsUbuntuType bool `mapstructure:"is_ubuntu_type" yaml:"is_ubuntu_type" comment:"是否是ubuntu类型的操作系统"`
|
||||
PackInit bool `mapstructure:"pack_init" yaml:"pack_init" comment:"是否初始化,ubuntu需要"`
|
||||
OSReleaseCode string `mapstructure:"os_release_code" yaml:"os_release_code" comment:"主机操作系统的发行版代号, focal之类的"`
|
||||
}
|
||||
|
||||
type Network struct {
|
||||
@@ -73,6 +74,7 @@ type PublicInfo struct {
|
||||
Country string `yaml:"country"`
|
||||
City string `yaml:"city"`
|
||||
ASN string `yaml:"asn"`
|
||||
Timezone string `yaml:"timezone"`
|
||||
}
|
||||
|
||||
type Interface struct {
|
||||
@@ -122,7 +124,6 @@ func InitConfig() {
|
||||
v.SetConfigType("yaml")
|
||||
|
||||
if err := v.ReadInConfig(); err != nil {
|
||||
|
||||
log.Error("读取配置文件失败: %w", err)
|
||||
panic(err)
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ func GetInterfaces() []Interface {
|
||||
|
||||
// 获取所有网卡信息
|
||||
netInterfaces, err := net.Interfaces()
|
||||
log.Info("all network interfaces: %v", netInterfaces)
|
||||
// log.Info("all network interfaces: %v", netInterfaces)
|
||||
if err != nil {
|
||||
log.Error("获取网卡信息失败: %v", err)
|
||||
return interfaces
|
||||
@@ -120,17 +120,35 @@ func judgeCanConnectInternet() int {
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
results := make(chan int, 2)
|
||||
|
||||
go func() {
|
||||
_, err := client.Get("https://www.google.com")
|
||||
if err == nil {
|
||||
return 9
|
||||
results <- 9
|
||||
} else {
|
||||
results <- 1
|
||||
}
|
||||
}()
|
||||
|
||||
_, err = client.Get("https://www.baidu.com")
|
||||
go func() {
|
||||
_, err := client.Get("https://www.baidu.com")
|
||||
if err == nil {
|
||||
return 7
|
||||
results <- 7
|
||||
} else {
|
||||
results <- 1
|
||||
}
|
||||
}()
|
||||
|
||||
maxResult := 1
|
||||
for i := 0; i < 2; i++ {
|
||||
result := <-results
|
||||
if result > maxResult {
|
||||
maxResult = result
|
||||
}
|
||||
}
|
||||
|
||||
return 1
|
||||
return maxResult
|
||||
}
|
||||
|
||||
// GetPublicInfo 获取服务器的公网信息
|
||||
@@ -194,13 +212,14 @@ func (p PublicInfo) GetPublicInfo() PublicInfo {
|
||||
}
|
||||
|
||||
// 打印解析结果
|
||||
log.Info("IP信息:\n%+v\n", info)
|
||||
// log.Info("IP信息:\n%+v\n", info)
|
||||
|
||||
// 保存信息
|
||||
p.IPv4 = info.IP
|
||||
p.ASN = info.Org
|
||||
p.Country = info.Country
|
||||
p.City = info.City
|
||||
p.Timezone = info.Timezone
|
||||
|
||||
ConfigCache.Agent.Network.Public = p
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ func (o *OS) Gather() {
|
||||
}
|
||||
|
||||
o.OsType = "linux" // 固定为linux
|
||||
o.IsUbuntuType = true // 默认为ubuntu
|
||||
|
||||
// 解析系统信息
|
||||
file, err := os.Open("/etc/os-release")
|
||||
@@ -78,12 +79,30 @@ func (o *OS) Gather() {
|
||||
}
|
||||
|
||||
// 检查包管理的方式
|
||||
c := exec.Command("command", "-v", "apt")
|
||||
_, err = c.Output()
|
||||
if err == nil {
|
||||
o.IsUbuntuType = true
|
||||
if strings.Contains(o.OsFamily, "centos") || strings.Contains(o.OsFamily, "rhel") {
|
||||
o.IsUbuntuType = false
|
||||
}
|
||||
|
||||
// 获取系统架构
|
||||
o.Arch = runtime.GOARCH
|
||||
|
||||
// 获取系统发行版代号
|
||||
o.OSReleaseCode = judgeUbuntuReleaseFromOsVersion(o.OsVersion)
|
||||
|
||||
}
|
||||
|
||||
func judgeUbuntuReleaseFromOsVersion(osVersion string) string {
|
||||
|
||||
switch osVersion {
|
||||
case "16.04":
|
||||
return "xenial"
|
||||
case "18.04":
|
||||
return "bionic"
|
||||
case "20.04":
|
||||
return "focal"
|
||||
case "22.04":
|
||||
return "jammy"
|
||||
default:
|
||||
return "ubuntu-unknown"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ try {
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
Write-Host "1. Building binary exec file..." -ForegroundColor Cyan
|
||||
& "C:\Users\wdd\go\bin\gox.exe" -osarch="linux/amd64" -output "build/agent-wdd_{{.OS}}_{{.Arch}}"
|
||||
& "C:\Users\wddsh\go\bin\gox.exe" -osarch="linux/amd64" -output "build/agent-wdd_{{.OS}}_{{.Arch}}"
|
||||
|
||||
# 执行远程ssh命令 ssh root@192.168.35.71 "rm /root/agent-wdd_linux_amd64"
|
||||
Write-Host "2. Cleaning old binary file..." -ForegroundColor Yellow
|
||||
@@ -16,7 +16,7 @@ try {
|
||||
Write-Host "4. Exec the command ..." -ForegroundColor Blue
|
||||
Write-Host ""
|
||||
Write-Host ""
|
||||
ssh root@192.168.35.71 "chmod +x agent-wdd_linux_amd64 && ./agent-wdd_linux_amd64 info network"
|
||||
ssh root@192.168.35.71 "chmod +x agent-wdd_linux_amd64 && ./agent-wdd_linux_amd64 help"
|
||||
Write-Host ""
|
||||
Write-Host ""
|
||||
Write-Host "5. Cheak Info Result ..." -ForegroundColor Blue
|
||||
|
||||
@@ -179,7 +179,7 @@ func HardCodeCommandExecutor(hardCodeCommand string) (ok bool, resultLog []strin
|
||||
cmd := exec.Command(hardCodeCommand)
|
||||
|
||||
// 执行命令并获取错误信息
|
||||
err := cmd.Run()
|
||||
cmd.Run()
|
||||
|
||||
// 合并输出结果
|
||||
stdoutBuf := bytes.Buffer{}
|
||||
@@ -189,7 +189,7 @@ func HardCodeCommandExecutor(hardCodeCommand string) (ok bool, resultLog []strin
|
||||
|
||||
output := mergeOutput(&stdoutBuf, &stderrBuf)
|
||||
|
||||
return err == nil, output
|
||||
return true, output
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
@@ -3,12 +3,10 @@ package op
|
||||
import (
|
||||
"agent-wdd/config"
|
||||
"agent-wdd/log"
|
||||
"agent-wdd/utils"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -60,8 +58,11 @@ func (op *PackageOperator) Install(tools []string) bool {
|
||||
ok, result := SingleLineCommandExecutor(append(AgentPackOperator.installPrefix, tool))
|
||||
if !ok {
|
||||
log.Error("[install] failed! => %s", tool)
|
||||
utils.BeautifulPrint(result)
|
||||
}
|
||||
|
||||
// 打印安装的过程内容
|
||||
beautifulPrintListWithTitle(result, fmt.Sprintf("安装 %s 的过程内容", tool))
|
||||
|
||||
}
|
||||
|
||||
return true
|
||||
@@ -71,21 +72,29 @@ func (op *PackageOperator) Install(tools []string) bool {
|
||||
func (op *PackageOperator) PackageInit() bool {
|
||||
log.Info("PackageInit !")
|
||||
|
||||
// beautifulPrintListWithTitle(config.ConfigCache)
|
||||
|
||||
// package init
|
||||
os := config.ConfigCache.Agent.OS
|
||||
|
||||
if os.PackInit {
|
||||
log.Info("PackageInit already done! skip!")
|
||||
return true
|
||||
}
|
||||
|
||||
// 判定本机的包管理Operator
|
||||
ok := generatePackageOperator()
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
// package init
|
||||
os := config.ConfigCache.Agent.OS
|
||||
osFamily := strings.ToLower(os.OsFamily)
|
||||
os.PackInit = true
|
||||
os.SaveConfig()
|
||||
|
||||
if strings.Contains(osFamily, "ubuntu") || strings.Contains(osFamily, "debian") {
|
||||
if os.IsUbuntuType {
|
||||
ok, resultLog := SingleLineCommandExecutor(aptPackageOperator.initCommand)
|
||||
if !ok {
|
||||
log.Error("APT init failed! please check !")
|
||||
utils.BeautifulPrint(resultLog)
|
||||
log.Error("APT init failed! please check ! %s", resultLog)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,6 +102,23 @@ func (op *PackageOperator) PackageInit() bool {
|
||||
|
||||
}
|
||||
|
||||
func (op *PackageOperator) PackageInitForce() bool {
|
||||
|
||||
log.Info("PackageInitForce !")
|
||||
|
||||
os := config.ConfigCache.Agent.OS
|
||||
|
||||
if os.IsUbuntuType {
|
||||
ok, resultLog := SingleLineCommandExecutor(aptPackageOperator.initCommand)
|
||||
if !ok {
|
||||
log.Error("APT init failed! please check ! %s", resultLog)
|
||||
}
|
||||
log.Info("APT init success! %s", resultLog)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (op *PackageOperator) Remove(tools []string) {
|
||||
// 判定本机的包管理Operator
|
||||
generatePackageOperator()
|
||||
@@ -102,7 +128,7 @@ func (op *PackageOperator) Remove(tools []string) {
|
||||
ok, result := SingleLineCommandExecutor(append(AgentPackOperator.removePrefix, tool))
|
||||
if !ok {
|
||||
log.Error("[remove] failed! => %s", tool)
|
||||
utils.BeautifulPrint(result)
|
||||
beautifulPrintListWithTitle(result, fmt.Sprintf("移除 %s 的过程内容", tool))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,6 +138,7 @@ func generatePackageOperator() bool {
|
||||
|
||||
// cache return
|
||||
if AgentPackOperator.initCommand != nil {
|
||||
log.Info("PackageOperator init success! %v", AgentPackOperator.initCommand)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -125,13 +152,14 @@ func generatePackageOperator() bool {
|
||||
os := config.ConfigCache.Agent.OS
|
||||
if os.Hostname == "" {
|
||||
os.Gather()
|
||||
|
||||
os.SaveConfig()
|
||||
}
|
||||
|
||||
if os.IsUbuntuType {
|
||||
log.Info("Ubuntu type detected! use apt package operator!")
|
||||
AgentPackOperator = aptPackageOperator
|
||||
} else {
|
||||
log.Info("Other type detected! use yum package operator!")
|
||||
AgentPackOperator = yumPackageOperator
|
||||
}
|
||||
|
||||
@@ -195,3 +223,13 @@ func CommandExistsByPath(command string) bool {
|
||||
ok, _ := SingleLineCommandExecutor([]string{"find", "/usr/bin", "/usr/local/bin", "-name", command})
|
||||
return ok
|
||||
}
|
||||
|
||||
func beautifulPrintListWithTitle(contend []string, title string) {
|
||||
|
||||
fmt.Println()
|
||||
fmt.Println(">>>>>>>> " + title + " <<<<<<<<")
|
||||
for _, line := range contend {
|
||||
fmt.Println(line)
|
||||
}
|
||||
fmt.Println(">>>>>>>> end <<<<<<<<")
|
||||
}
|
||||
|
||||
@@ -79,3 +79,11 @@ func SystemdDaemonReload() (bool, []string) {
|
||||
}
|
||||
return true, resultLog
|
||||
}
|
||||
|
||||
func SystemIsRunning(serviceName string) (bool, []string) {
|
||||
ok, resultLog := SingleLineCommandExecutor([]string{"systemctl", "is-active", serviceName})
|
||||
if !ok {
|
||||
return false, resultLog
|
||||
}
|
||||
return true, resultLog
|
||||
}
|
||||
|
||||
27
agent-wdd/test/one-click-build-run.ps1
Normal file
27
agent-wdd/test/one-click-build-run.ps1
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
|
||||
# mc.exe alias set oracle-osaka-1 https://axzsapxffbbn.compat.objectstorage.ap-osaka-1.oraclecloud.com b0696c316f87b644b4a13bcb020f095cd147be0b GAIaM/064epLzQcXsRbj2gwlFOrVepjCR23wj2tfJ+A=
|
||||
|
||||
# 重新build项目
|
||||
Set-Location "C:\Users\wddsh\Documents\IdeaProjects\ProjectOctopus\agent-wdd"
|
||||
& "C:\Users\wddsh\go\bin\gox.exe" -osarch="linux/amd64" -output "build/agent-wdd_{{.OS}}_{{.Arch}}"
|
||||
|
||||
|
||||
# mc.exe ls oracle-osaka-1/osaka
|
||||
# 删除上面存在的旧的内容
|
||||
mc.exe rm oracle-osaka-1/osaka/agent-wdd_linux_amd64
|
||||
mc.exe rm oracle-osaka-1/osaka/test-shell.sh
|
||||
|
||||
|
||||
# 上传文件
|
||||
mc.exe cp C:\Users\wddsh\Documents\IdeaProjects\ProjectOctopus\agent-wdd\build\agent-wdd_linux_amd64 oracle-osaka-1/osaka/
|
||||
mc.exe cp C:\Users\wddsh\Documents\IdeaProjects\ProjectOctopus\agent-wdd\test\test-shell.sh oracle-osaka-1/osaka/
|
||||
|
||||
|
||||
Set-Location "C:\Users\wddsh\Documents\IdeaProjects\ProjectOctopus\agent-wdd\test"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
Available commands:
|
||||
|
||||
acme acme相关的内容
|
||||
base 服务器基础操作
|
||||
docker Docker相关操作
|
||||
@@ -19,11 +20,6 @@ base 服务器基础操作
|
||||
swap 关闭系统的Swap
|
||||
sysconfig 修改系统的sysconfig
|
||||
tools 通用工具安装 利用本机的yum,apt等从网络安装常用的软件
|
||||
completion Generate the autocompletion script for the specified shell
|
||||
bash Generate the autocompletion script for bash
|
||||
fish Generate the autocompletion script for fish
|
||||
powershell Generate the autocompletion script for powershell
|
||||
zsh Generate the autocompletion script for zsh
|
||||
config 配置文件管理
|
||||
show 显示agent运行配置
|
||||
download 文件下载,直接下载 [url] [dest_path]
|
||||
52
agent-wdd/test/run_test.sh
Normal file
52
agent-wdd/test/run_test.sh
Normal file
@@ -0,0 +1,52 @@
|
||||
#!/bin/bash
|
||||
|
||||
rm -f /usr/local/bin/agent-wdd
|
||||
rm -f /usr/local/bin/test-shell.sh
|
||||
|
||||
wget https://pan.107421.xyz/d/oracle-osaka-1/agent-wdd_linux_amd64 -O /usr/local/bin/agent-wdd
|
||||
|
||||
chmod +x /usr/local/bin/agent-wdd
|
||||
|
||||
|
||||
wget https://pan.107421.xyz/d/oracle-osaka-1/test-shell.sh -O /usr/local/bin/test-shell.sh
|
||||
|
||||
chmod +x /usr/local/bin/test-shell.sh
|
||||
|
||||
|
||||
|
||||
|
||||
bash /usr/local/bin/test-shell.sh
|
||||
|
||||
|
||||
|
||||
|
||||
/usr/local/bin/agent-wdd info network
|
||||
/usr/local/bin/agent-wdd info cpu
|
||||
/usr/local/bin/agent-wdd info mem
|
||||
/usr/local/bin/agent-wdd info swap
|
||||
/usr/local/bin/agent-wdd info disks
|
||||
|
||||
cat /usr/local/etc/wdd/agent-wdd-config.yaml
|
||||
|
||||
|
||||
/usr/local/bin/agent-wdd base docker local
|
||||
|
||||
/usr/local/bin/agent-wdd info os
|
||||
/usr/local/bin/agent-wdd base docker online
|
||||
|
||||
/usr/local/bin/agent-wdd info os
|
||||
/usr/local/bin/agent-wdd zsh
|
||||
|
||||
/usr/local/bin/agent-wdd base tools
|
||||
|
||||
/usr/local/bin/agent-wdd base swap
|
||||
|
||||
/usr/local/bin/agent-wdd base firewall
|
||||
|
||||
/usr/local/bin/agent-wdd base selinux
|
||||
|
||||
/usr/local/bin/agent-wdd base sysconfig
|
||||
|
||||
|
||||
/usr/local/bin/agent-wdd download https://pan.107421.xyz/d/oracle-osaka-1/docker-amd64-20.10.15.tgz /root/wdd
|
||||
|
||||
135
agent-wdd/test/test-shell.sh
Normal file
135
agent-wdd/test/test-shell.sh
Normal file
@@ -0,0 +1,135 @@
|
||||
#!/bin/bash
|
||||
# set -eo pipefail
|
||||
|
||||
# 测试配置
|
||||
TEST_REPEATS=2
|
||||
AGENT_BIN="/usr/local/bin/agent-wdd" # 修正路径拼写错误
|
||||
|
||||
# 输出颜色定义
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[0;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
# 测试统计
|
||||
declare -i TOTAL_TESTS=0 PASSED_TESTS=0 FAILED_TESTS=0
|
||||
|
||||
# 实用函数
|
||||
log() {
|
||||
echo -e "${YELLOW}[INFO] $* ${NC}"
|
||||
}
|
||||
|
||||
pass() {
|
||||
echo -e "${GREEN}PASS: $* ${NC}"
|
||||
((PASSED_TESTS++))
|
||||
((TOTAL_TESTS++))
|
||||
}
|
||||
|
||||
fail() {
|
||||
echo -e "${RED}FAIL: $* ${NC}"
|
||||
((FAILED_TESTS++))
|
||||
((TOTAL_TESTS++))
|
||||
}
|
||||
|
||||
test_command() {
|
||||
local cmd="$1"
|
||||
local expected="${2:-0}"
|
||||
|
||||
if ! eval "$cmd"; then
|
||||
local exit_code=$?
|
||||
[[ $exit_code -eq "$expected" ]] || {
|
||||
fail "$cmd (exit $exit_code)"
|
||||
return 1
|
||||
}
|
||||
fi
|
||||
pass "$cmd"
|
||||
return 0
|
||||
}
|
||||
|
||||
repeat_test() {
|
||||
local times=$1
|
||||
local cmd="$2"
|
||||
local expected="${3:-0}"
|
||||
|
||||
for ((i=1; i<=times; i++)); do
|
||||
test_command "$cmd" "$expected"
|
||||
done
|
||||
}
|
||||
|
||||
test_base_docker() {
|
||||
log "\nTesting Docker commands..."
|
||||
test_command "$AGENT_BIN base docker remove" 0
|
||||
test_command "$AGENT_BIN base docker online" 0
|
||||
repeat_test $TEST_REPEATS "$AGENT_BIN base docker local" 0
|
||||
|
||||
if docker --version >/dev/null 2>&1; then
|
||||
pass "docker installation"
|
||||
else
|
||||
fail "docker installation"
|
||||
fi
|
||||
}
|
||||
|
||||
test_base_ssh() {
|
||||
log "\nTesting SSH commands..."
|
||||
repeat_test $TEST_REPEATS "$AGENT_BIN base ssh port 2222" 0
|
||||
test_command "$AGENT_BIN base ssh config" 0
|
||||
}
|
||||
|
||||
test_tools() {
|
||||
log "\nTesting tools installation..."
|
||||
local tools=("htop" "tmux" "nano")
|
||||
for tool in "${tools[@]}"; do
|
||||
if command -v "$tool" >/dev/null 2>&1; then
|
||||
pass "$tool already installed"
|
||||
else
|
||||
test_command "$AGENT_BIN base tools $tool" 0
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
test_info_commands() {
|
||||
log "\nTesting info commands..."
|
||||
local commands=(
|
||||
"$AGENT_BIN info all"
|
||||
"$AGENT_BIN info cpu"
|
||||
"$AGENT_BIN info disk"
|
||||
"$AGENT_BIN info mem"
|
||||
"$AGENT_BIN info network"
|
||||
"$AGENT_BIN info os"
|
||||
)
|
||||
|
||||
for cmd in "${commands[@]}"; do
|
||||
repeat_test $TEST_REPEATS "$cmd" 0
|
||||
done
|
||||
}
|
||||
|
||||
main() {
|
||||
# 前置检查
|
||||
[[ -x "$AGENT_BIN" ]] || {
|
||||
log "Error: Agent binary not found or not executable: $AGENT_BIN"
|
||||
exit 1
|
||||
}
|
||||
|
||||
log "Starting tests with $AGENT_BIN..."
|
||||
|
||||
# 基本信息测试
|
||||
test_command "$AGENT_BIN version" 0
|
||||
test_command "$AGENT_BIN help" 0
|
||||
|
||||
# 基础模块测试
|
||||
test_base_docker
|
||||
test_base_ssh
|
||||
test_tools
|
||||
|
||||
# 信息模块测试
|
||||
test_info_commands
|
||||
|
||||
log "\nTest Summary:"
|
||||
echo -e "Total Tests: $TOTAL_TESTS"
|
||||
echo -e "${GREEN}Passed: $PASSED_TESTS ${NC}"
|
||||
echo -e "${RED}Failed: $FAILED_TESTS ${NC}"
|
||||
|
||||
exit "$FAILED_TESTS"
|
||||
}
|
||||
|
||||
main
|
||||
@@ -1,10 +1,13 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"agent-wdd/log"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@@ -18,7 +21,19 @@ func DownloadFile(url string, path string) (bool, string) {
|
||||
return DownloadFileWithClient(client, url, path)
|
||||
}
|
||||
|
||||
// DownloadFileWithClient 使用http客户端下载文件
|
||||
func DownloadFileWithClient(client *http.Client, url string, path string) (bool, string) {
|
||||
|
||||
// path如果是一个目录,则需要获取文件名
|
||||
// 获取url使用 / 分割最后的一部分
|
||||
// 如果path是目录,则需要获取文件名
|
||||
|
||||
if IsDirOrFile(path) {
|
||||
fileName := strings.Split(url, "/")[len(strings.Split(url, "/"))-1]
|
||||
path = filepath.Join(path, fileName)
|
||||
log.Info("path是目录,自动获取文件名为 => : %s", path)
|
||||
}
|
||||
|
||||
return downloadWithProgress(client, url, path)
|
||||
}
|
||||
|
||||
@@ -27,14 +42,14 @@ func downloadWithProgress(client *http.Client, url, dest string) (bool, string)
|
||||
// 创建目标文件
|
||||
file, err := os.Create(dest)
|
||||
if err != nil {
|
||||
return false, fmt.Sprintf("创建文件失败: %w", err)
|
||||
return false, fmt.Sprintf("创建文件失败: %s", err.Error())
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// 发起请求
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
return false, fmt.Sprintf("HTTP请求失败: %w", err)
|
||||
return false, fmt.Sprintf("HTTP请求失败: %s", err.Error())
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
@@ -46,6 +61,13 @@ func downloadWithProgress(client *http.Client, url, dest string) (bool, string)
|
||||
size := resp.ContentLength
|
||||
var downloaded int64
|
||||
|
||||
// 不支持下载超过10GB的文件
|
||||
|
||||
if size > 10*1024*1024*1024 || size < 0 {
|
||||
log.Error("文件大小超过10GB,或者文件大小未知,不支持高级下载方式! 尝试使用wget下载")
|
||||
return downloadFileByWget(url, dest)
|
||||
}
|
||||
|
||||
// 打印下载信息
|
||||
fmt.Printf("开始下载: %s 大小: %s\n", url, HumanSizeInt(size))
|
||||
|
||||
@@ -60,13 +82,32 @@ func downloadWithProgress(client *http.Client, url, dest string) (bool, string)
|
||||
|
||||
// 执行拷贝
|
||||
if _, err := io.Copy(file, progressReader); err != nil {
|
||||
return false, fmt.Sprintf("文件拷贝失败: %w", err)
|
||||
return false, fmt.Sprintf("文件拷贝失败: %s", err.Error())
|
||||
}
|
||||
|
||||
fmt.Print("\n") // 保持最后进度显示的完整性
|
||||
return true, fmt.Sprintf("文件下载成功: %s", dest)
|
||||
}
|
||||
|
||||
// 使用wget下载文件
|
||||
func downloadFileByWget(url, dest string) (bool, string) {
|
||||
|
||||
log.Info("使用wget下载文件: %s", fmt.Sprintf("wget %s -qO %s", url, dest))
|
||||
cmd := exec.Command("wget", url, "-qO", dest)
|
||||
_, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return false, fmt.Sprintf("wget下载失败: %s", err.Error())
|
||||
}
|
||||
|
||||
// 检查文件是否存在且不为空
|
||||
fileInfo, err := os.Stat(dest)
|
||||
if err != nil || fileInfo.Size() == 0 {
|
||||
return false, fmt.Sprintf("wget下载失败 文件不存在或为空: %s", dest)
|
||||
}
|
||||
|
||||
return true, fmt.Sprintf("wget下载成功: %s", dest)
|
||||
}
|
||||
|
||||
// 进度跟踪Reader
|
||||
type progressReader struct {
|
||||
io.Reader
|
||||
|
||||
@@ -41,7 +41,7 @@ func BeautifulPrintWithTitle(contend any, title string) {
|
||||
func BeautifulPrintListWithTitle(contend []string, title string) {
|
||||
|
||||
fmt.Println()
|
||||
fmt.Println(fmt.Sprintf("content tile is => %s", title))
|
||||
fmt.Println(">>>>>>>> " + title + " <<<<<<<<")
|
||||
for _, line := range contend {
|
||||
fmt.Println(line)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user