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:
zeaslity
2025-02-28 17:45:12 +08:00
parent bffb643a56
commit 5c39bd7594
16 changed files with 586 additions and 86 deletions

View File

@@ -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

View File

@@ -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{

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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"
}
}

View File

@@ -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

View File

@@ -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() {

View File

@@ -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 <<<<<<<<")
}

View File

@@ -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
}

View 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"

View File

@@ -1,4 +1,5 @@
Available commands:
acme acme相关的内容
base 服务器基础操作
docker Docker相关操作
@@ -19,11 +20,6 @@ base 服务器基础操作
swap 关闭系统的Swap
sysconfig 修改系统的sysconfig
tools 通用工具安装 利用本机的yumapt等从网络安装常用的软件
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]

View 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

View 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

View File

@@ -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

View File

@@ -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)
}