更新工作区配置,删除不再使用的Cloudflare相关文件,优化日志输出格式,增强主机信息收集功能,调整代码结构以提高可维护性。

This commit is contained in:
zeaslity
2025-03-28 00:15:08 +08:00
parent c2ca7eb6d7
commit 6816638267
19 changed files with 847 additions and 155 deletions

50
.idea/workspace.xml generated
View File

@@ -5,35 +5,25 @@
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="6047a167-18d5-4f8e-a170-63c3fd101bda" name="Changes" comment=""> <list default="true" id="6047a167-18d5-4f8e-a170-63c3fd101bda" name="Changes" comment="">
<change afterPath="$PROJECT_DIR$/agent-wdd/a_run/one-build-and-run.ps1" afterDir="false" />
<change afterPath="$PROJECT_DIR$/agent-wdd/a_run/one-build-and-upload.ps1" afterDir="false" />
<change afterPath="$PROJECT_DIR$/agent-wdd/a_run/readme_help.txt" afterDir="false" />
<change afterPath="$PROJECT_DIR$/agent-wdd/a_run/run_test.sh" afterDir="false" />
<change afterPath="$PROJECT_DIR$/agent-wdd/a_run/test-shell.sh" afterDir="false" />
<change afterPath="$PROJECT_DIR$/agent-wdd/host_info/CPU.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/agent-wdd/host_info/Config.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/agent-wdd/host_info/Disk.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/agent-wdd/host_info/Memory.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/agent-wdd/host_info/Network.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/agent-wdd/host_info/OS.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/vcs.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/vcs.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/agent-wdd/agent-wdd-config.yaml" beforeDir="false" /> <change beforePath="$PROJECT_DIR$/agent-wdd/a_run/run_test.sh" beforeDir="false" afterPath="$PROJECT_DIR$/agent-wdd/a_run/run_test.sh" afterDir="false" />
<change beforePath="$PROJECT_DIR$/agent-wdd/build/agent-wdd_linux_amd64" beforeDir="false" afterPath="$PROJECT_DIR$/agent-wdd/build/agent-wdd_linux_amd64" afterDir="false" /> <change beforePath="$PROJECT_DIR$/agent-wdd/build/agent-wdd_linux_amd64" beforeDir="false" afterPath="$PROJECT_DIR$/agent-wdd/build/agent-wdd_linux_amd64" afterDir="false" />
<change beforePath="$PROJECT_DIR$/agent-wdd/cert_manager_wdd/AcmeClient.go" beforeDir="false" afterPath="$PROJECT_DIR$/agent-wdd/cert_manager_wdd/AcmeClient.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/agent-wdd/cloudflare/Cloudflare.go" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/agent-wdd/cloudflare/Cloudflare_test.go" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/agent-wdd/cloudflare/DNS.go" beforeDir="false" afterPath="$PROJECT_DIR$/agent-wdd/cloudflare/DNS.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/agent-wdd/cloudflare/Zone.go" beforeDir="false" afterPath="$PROJECT_DIR$/agent-wdd/cloudflare/Zone.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/agent-wdd/cmd/Acme.go" beforeDir="false" afterPath="$PROJECT_DIR$/agent-wdd/cmd/Acme.go" afterDir="false" /> <change beforePath="$PROJECT_DIR$/agent-wdd/cmd/Acme.go" beforeDir="false" afterPath="$PROJECT_DIR$/agent-wdd/cmd/Acme.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/agent-wdd/cmd/Config.go" beforeDir="false" afterPath="$PROJECT_DIR$/agent-wdd/cmd/Config.go" afterDir="false" /> <change beforePath="$PROJECT_DIR$/agent-wdd/cmd/Base.go" beforeDir="false" afterPath="$PROJECT_DIR$/agent-wdd/cmd/Base.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/agent-wdd/cmd/CertManager.go" beforeDir="false" afterPath="$PROJECT_DIR$/agent-wdd/cmd/CertManager.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/agent-wdd/cmd/Info.go" beforeDir="false" afterPath="$PROJECT_DIR$/agent-wdd/cmd/Info.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/agent-wdd/cmd/Proxy.go" beforeDir="false" afterPath="$PROJECT_DIR$/agent-wdd/cmd/Proxy.go" afterDir="false" /> <change beforePath="$PROJECT_DIR$/agent-wdd/cmd/Proxy.go" beforeDir="false" afterPath="$PROJECT_DIR$/agent-wdd/cmd/Proxy.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/agent-wdd/config/CPU.go" beforeDir="false" /> <change beforePath="$PROJECT_DIR$/agent-wdd/cmd/Zsh.go" beforeDir="false" afterPath="$PROJECT_DIR$/agent-wdd/cmd/Zsh.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/agent-wdd/config/Config.go" beforeDir="false" /> <change beforePath="$PROJECT_DIR$/agent-wdd/cmd/root.go" beforeDir="false" afterPath="$PROJECT_DIR$/agent-wdd/cmd/root.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/agent-wdd/config/Disk.go" beforeDir="false" /> <change beforePath="$PROJECT_DIR$/agent-wdd/host_info/Config.go" beforeDir="false" afterPath="$PROJECT_DIR$/agent-wdd/host_info/Config.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/agent-wdd/config/Memory.go" beforeDir="false" /> <change beforePath="$PROJECT_DIR$/agent-wdd/log/CallerLog.go" beforeDir="false" afterPath="$PROJECT_DIR$/agent-wdd/log/CallerLog.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/agent-wdd/config/Network.go" beforeDir="false" /> <change beforePath="$PROJECT_DIR$/agent-wdd/op/Excutor.go" beforeDir="false" afterPath="$PROJECT_DIR$/agent-wdd/op/Excutor.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/agent-wdd/config/OS.go" beforeDir="false" /> <change beforePath="$PROJECT_DIR$/agent-wdd/op/PackageOperator.go" beforeDir="false" afterPath="$PROJECT_DIR$/agent-wdd/op/PackageOperator.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/agent-wdd/one-build-and-run.ps1" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/agent-wdd/test/one-click-build-run.ps1" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/agent-wdd/test/readme_help.txt" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/agent-wdd/test/run_test.sh" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/agent-wdd/test/test-shell.sh" beforeDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -59,6 +49,7 @@
</component> </component>
<component name="PropertiesComponent"><![CDATA[{ <component name="PropertiesComponent"><![CDATA[{
"keyToString": { "keyToString": {
"PowerShell.one-build-and-upload.ps1 (1).executor": "Run",
"PowerShell.one-build-and-upload.ps1.executor": "Run", "PowerShell.one-build-and-upload.ps1.executor": "Run",
"RunOnceActivity.ShowReadmeOnStart": "true", "RunOnceActivity.ShowReadmeOnStart": "true",
"RunOnceActivity.git.unshallow": "true", "RunOnceActivity.git.unshallow": "true",
@@ -74,13 +65,18 @@
"vue.rearranger.settings.migration": "true" "vue.rearranger.settings.migration": "true"
} }
}]]></component> }]]></component>
<component name="RunManager" selected="PowerShell.one-build-and-upload.ps1"> <component name="RunManager" selected="PowerShell.one-build-and-upload.ps1 (1)">
<configuration name="one-build-and-upload.ps1 (1)" type="PowerShellRunType" factoryName="PowerShell" temporary="true" scriptUrl="$PROJECT_DIR$/agent-wdd/a_run/one-build-and-upload.ps1" executablePath="$PROJECT_DIR$/../../../../../Windows/System32/WindowsPowerShell/v1.0/powershell.exe">
<envs />
<method v="2" />
</configuration>
<configuration name="one-build-and-upload.ps1" type="PowerShellRunType" factoryName="PowerShell" temporary="true" scriptUrl="$PROJECT_DIR$/agent-wdd/a_run/one-build-and-upload.ps1" executablePath="$PROJECT_DIR$/../../../../../Windows/System32/WindowsPowerShell/v1.0/powershell.exe"> <configuration name="one-build-and-upload.ps1" type="PowerShellRunType" factoryName="PowerShell" temporary="true" scriptUrl="$PROJECT_DIR$/agent-wdd/a_run/one-build-and-upload.ps1" executablePath="$PROJECT_DIR$/../../../../../Windows/System32/WindowsPowerShell/v1.0/powershell.exe">
<envs /> <envs />
<method v="2" /> <method v="2" />
</configuration> </configuration>
<recent_temporary> <recent_temporary>
<list> <list>
<item itemvalue="PowerShell.one-build-and-upload.ps1 (1)" />
<item itemvalue="PowerShell.one-build-and-upload.ps1" /> <item itemvalue="PowerShell.one-build-and-upload.ps1" />
</list> </list>
</recent_temporary> </recent_temporary>
@@ -101,7 +97,7 @@
<option name="number" value="Default" /> <option name="number" value="Default" />
<option name="presentableId" value="Default" /> <option name="presentableId" value="Default" />
<updated>1743088643405</updated> <updated>1743088643405</updated>
<workItem from="1743088645374" duration="454000" /> <workItem from="1743088645374" duration="2622000" />
</task> </task>
<servers /> <servers />
</component> </component>

View File

@@ -366,9 +366,3 @@ func createCSR(privateKey crypto.Signer, domain string) ([]byte, error) {
return csrDER, nil return csrDER, nil
} }
// pemEncode 将DER格式数据编码为PEM格式
func pemEncode(typ string, der []byte) []byte {
block := &pem.Block{Type: typ, Bytes: der}
return pem.EncodeToMemory(block)
}

View File

@@ -25,6 +25,7 @@ type CloudflareClient struct {
baseURL string baseURL string
client *http.Client client *http.Client
userAgent string userAgent string
dnsNameToIDMap map[string]string // 域名到ID的映射
} }
var ( var (
@@ -151,3 +152,14 @@ func (c *CloudflareClient) doRequest(method, url string, body interface{}) (*Res
log.Debug("Request completed successfully") log.Debug("Request completed successfully")
return &cfResp, nil return &cfResp, nil
} }
// GetDNSNameToIDMap 获取域名到ID的映射
func (c *CloudflareClient) GetDNSNameToIDMap(zoneID string) map[string]string {
// 如果dnsNameToIDMap为空则获取所有域名到ID的映射
if c.dnsNameToIDMap == nil {
c.ListDNSRecords(zoneID, nil)
}
return c.dnsNameToIDMap
}

View File

@@ -110,6 +110,12 @@ func (c *CloudflareClient) ListDNSRecords(zoneID string, filter *DNSRecordFilter
return nil, fmt.Errorf("failed to unmarshal DNS records: %w", err) return nil, fmt.Errorf("failed to unmarshal DNS records: %w", err)
} }
// 将域名和ID的映射关系存储到dnsNameToIDMap中
c.dnsNameToIDMap = make(map[string]string, len(records))
for _, record := range records {
c.dnsNameToIDMap[record.Name] = record.ID
}
log.Info("Successfully retrieved %d DNS records for zone ID: %s", len(records), zoneID) log.Info("Successfully retrieved %d DNS records for zone ID: %s", len(records), zoneID)
return records, nil return records, nil
} }

View File

@@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"net/url" "net/url"
"strings"
"agent-wdd/log" "agent-wdd/log"
) )
@@ -179,6 +180,23 @@ func (c *CloudflareClient) GetZone(identifier string) (*Zone, error) {
if isID { if isID {
endpoint = fmt.Sprintf("%s/zones/%s", c.baseURL, identifier) endpoint = fmt.Sprintf("%s/zones/%s", c.baseURL, identifier)
} else { } else {
// tc.hk.107421.xyz ipv6.t2.107421.xyz 转换为 107421.xyz
// 寻找.的个数 如果大于 从后往前找到 第二个 . 的位置
dotCount := strings.Count(identifier, ".")
if dotCount > 1 {
// 从后往前找到 第二个 . 的位置
lastDotIndex := strings.LastIndex(identifier, ".")
secondLastDotIndex := strings.LastIndex(identifier[:lastDotIndex], ".")
identifier = identifier[secondLastDotIndex+1:]
} else if dotCount == 0 {
// 没有. 报错
log.Error("未找到域名 %s 的ZoneID", identifier)
return nil, fmt.Errorf("no zone found with name: %s", identifier)
}
log.Debug("转换后的域名: %s", identifier)
// List zones with name filter // List zones with name filter
zones, err := c.ListZones(&ZoneFilter{Name: identifier}) zones, err := c.ListZones(&ZoneFilter{Name: identifier})
if err != nil { if err != nil {

View File

@@ -40,7 +40,7 @@ func addAcmeSubcommands(cmd *cobra.Command) {
"/tmp/acme.sh", "/tmp/acme.sh",
) )
if !ok { if !ok {
log.Error("下载acme.sh失败", err) log.Error("下载acme.sh失败 %v", err)
return return
} }
@@ -105,7 +105,7 @@ func addAcmeSubcommands(cmd *cobra.Command) {
// 执行命令 // 执行命令
ok, output := op.SingleLineCommandExecutor([]string{"/root/.acme.sh/acme.sh", "--list"}) ok, output := op.SingleLineCommandExecutor([]string{"/root/.acme.sh/acme.sh", "--list"})
if !ok { if !ok {
log.Error("列出acme全部的证书失败", output) log.Error("列出acme全部的证书失败 %v", output)
return return
} }

View File

@@ -2,7 +2,7 @@ package cmd
import ( import (
"agent-wdd/cmd/beans" "agent-wdd/cmd/beans"
"agent-wdd/config" "agent-wdd/host_info"
"agent-wdd/log" "agent-wdd/log"
"agent-wdd/op" "agent-wdd/op"
"agent-wdd/utils" "agent-wdd/utils"
@@ -96,13 +96,13 @@ func addBaseSubcommands(cmd *cobra.Command) {
log.Info("Selinux 关闭!") log.Info("Selinux 关闭!")
// 如果configCache的OS为空则收集OS信息 // 如果configCache的OS为空则收集OS信息
if config.ConfigCache.Agent.OS.Hostname == "" { if host_info.ConfigCache.Agent.OS.Hostname == "" {
log.Warning("ConfigCache OS is nil") log.Warning("ConfigCache OS is nil")
config.ConfigCache.Agent.OS.Gather() host_info.ConfigCache.Agent.OS.Gather()
config.ConfigCache.Agent.OS.SaveConfig() host_info.ConfigCache.Agent.OS.SaveConfig()
} }
os := config.ConfigCache.Agent.OS os := host_info.ConfigCache.Agent.OS
if os.IsUbuntuType { if os.IsUbuntuType {
log.Info("Ubuntu 系统跳过关闭selinux") log.Info("Ubuntu 系统跳过关闭selinux")
return return
@@ -234,7 +234,7 @@ func addBaseSubcommands(cmd *cobra.Command) {
log.Info("Common tool installation!") log.Info("Common tool installation!")
// Whether It can connect to internet // Whether It can connect to internet
if config.CanConnectInternet() <= 1 { if host_info.CanConnectInternet() <= 1 {
log.Error("服务器无法连接互联网无法执行tools") log.Error("服务器无法连接互联网无法执行tools")
return return
} }
@@ -244,7 +244,7 @@ func addBaseSubcommands(cmd *cobra.Command) {
packOperator := op.AgentPackOperator packOperator := op.AgentPackOperator
packOperator.PackageInit() packOperator.PackageInit()
os := config.ConfigCache.Agent.OS os := host_info.ConfigCache.Agent.OS
if os.IsUbuntuType { if os.IsUbuntuType {
packOperator.Install(ubuntuCommonTools) packOperator.Install(ubuntuCommonTools)
} else { } else {
@@ -299,7 +299,7 @@ func addHarborSubcommands(harborCmd *cobra.Command) {
utils.UnzipFile(harborLocalInstallPath, "/root/wdd/") utils.UnzipFile(harborLocalInstallPath, "/root/wdd/")
// 获取本机的内网IPv4地址 // 获取本机的内网IPv4地址
configCache := config.ConfigCache configCache := host_info.ConfigCache
if len(configCache.Agent.Network.Interfaces) == 0 { if len(configCache.Agent.Network.Interfaces) == 0 {
log.Error("没有获取到本机的ipv4地址无法安装harbor! 请执行 info all !") log.Error("没有获取到本机的ipv4地址无法安装harbor! 请执行 info all !")
} }
@@ -596,7 +596,7 @@ func addDockerSubcommands(cmd *cobra.Command) {
packOperator := op.AgentPackOperator packOperator := op.AgentPackOperator
packOperator.PackageInit() packOperator.PackageInit()
configCache := config.ConfigCache configCache := host_info.ConfigCache
if configCache.Agent.OS.IsUbuntuType { if configCache.Agent.OS.IsUbuntuType {
// 安装apt-transport-https ca-certificates curl gnupg software-properties-common 依赖部分 // 安装apt-transport-https ca-certificates curl gnupg software-properties-common 依赖部分
packOperator.Install([]string{"apt-transport-https", "ca-certificates", "curl", "gnupg", "software-properties-common"}) packOperator.Install([]string{"apt-transport-https", "ca-certificates", "curl", "gnupg", "software-properties-common"})
@@ -886,7 +886,7 @@ func addDockerSubcommands(cmd *cobra.Command) {
} }
// 获取当前内网IP // 获取当前内网IP
ip := config.ConfigCache.Agent.Network.Interfaces[0].IPv4 ip := host_info.ConfigCache.Agent.Network.Interfaces[0].IPv4
if ip == "" { if ip == "" {
log.Error("获取当前内网IP失败, 无法进行docker config配置") log.Error("获取当前内网IP失败, 无法进行docker config配置")
return return
@@ -956,7 +956,7 @@ func addDockerComposeSubcommands(cmd *cobra.Command) {
log.Info("安装 Docker Compose 版本: %s", version) log.Info("安装 Docker Compose 版本: %s", version)
// 检查是否可以连接互联网 // 检查是否可以连接互联网
if config.CanConnectInternet() <= 1 { if host_info.CanConnectInternet() <= 1 {
log.Error("服务器无法连接互联网,无法在线安装 Docker Compose") log.Error("服务器无法连接互联网,无法在线安装 Docker Compose")
return return
} }

View File

@@ -11,28 +11,17 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
var ( const (
// 证书管理命令选项 // 证书管理命令选项
cfAPIToken string cfAPIToken = "T7LxBemfe8SNGWkT9uz2XIc1e22ifAbBv_POJvDP"
certDir string certDir = "/root/wdd/cert_manager_wdd/"
emailAddr string emailAddr = "wdd@gmail.com"
caServer string caServer = "zerossl"
daysRenewal int daysRenewal = 30
) )
// 初始化证书管理配置 // 初始化证书管理配置
func initCertManagerConfig() *cert_manager_wdd.CertManager { func initCertManagerConfig() *cert_manager_wdd.CertManager {
// 如果未指定API令牌提示用户
if cfAPIToken == "" {
log.Error("未指定Cloudflare API令牌请使用--token参数设置")
os.Exit(1)
}
// 如果未指定邮箱地址,使用默认值
if emailAddr == "" {
emailAddr = "cert@example.com"
log.Warning("未指定邮箱地址,使用默认值: %s", emailAddr)
}
// 创建证书管理器 // 创建证书管理器
certManager := cert_manager_wdd.NewCertManager(certDir, cfAPIToken, emailAddr) certManager := cert_manager_wdd.NewCertManager(certDir, cfAPIToken, emailAddr)
@@ -59,12 +48,6 @@ func initCertManagerConfig() *cert_manager_wdd.CertManager {
// 添加证书管理命令 // 添加证书管理命令
func addCertManagerSubcommands(cmd *cobra.Command) { func addCertManagerSubcommands(cmd *cobra.Command) {
// 全局标志
cmd.PersistentFlags().StringVar(&cfAPIToken, "token", "", "Cloudflare API令牌")
cmd.PersistentFlags().StringVar(&certDir, "cert-dir", "", "证书保存目录")
cmd.PersistentFlags().StringVar(&emailAddr, "email", "", "申请证书使用的邮箱")
cmd.PersistentFlags().StringVar(&caServer, "ca", "letsencrypt", "CA服务器 (letsencrypt, zerossl)")
cmd.PersistentFlags().IntVar(&daysRenewal, "days", 30, "证书更新阈值天数")
// 申请证书命令 // 申请证书命令
applyCmd := &cobra.Command{ applyCmd := &cobra.Command{

723
agent-wdd/cmd/Cloudflare.go Normal file
View File

@@ -0,0 +1,723 @@
package cmd
import (
"agent-wdd/cloudflare"
"agent-wdd/log"
"bufio"
"fmt"
"os"
"strconv"
"strings"
"text/tabwriter"
"github.com/spf13/cobra"
)
const (
// Cloudflare API设置选项
cfAPITokenDefault = "T7LxBemfe8SNGWkT9uz2XIc1e22ifAbBv_POJvDP" // 默认的API令牌实际应用中应从配置文件或环境变量获取
)
// DNS记录类型常量
const (
DNSTypeA = "A"
DNSTypeAAAA = "AAAA"
DNSTypeCNAME = "CNAME"
DNSTypeTXT = "TXT"
DNSTypeMX = "MX"
DNSTypeSRV = "SRV"
)
// 初始化Cloudflare客户端
func initCloudflareClient() *cloudflare.CloudflareClient {
log.Debug("初始化Cloudflare客户端")
return cloudflare.GetInstance(cfAPITokenDefault)
}
// 询问用户确认
func askForConfirmation(prompt string) bool {
reader := bufio.NewReader(os.Stdin)
for {
fmt.Printf("%s [y/n]: ", prompt)
response, err := reader.ReadString('\n')
if err != nil {
log.Error("读取用户输入失败: %v", err)
return false
}
response = strings.ToLower(strings.TrimSpace(response))
if response == "y" || response == "yes" {
return true
} else if response == "n" || response == "no" {
return false
}
}
}
// 添加Cloudflare命令
func addCloudflareSubcommands(cmd *cobra.Command) {
// 域名管理命令
domainCmd := &cobra.Command{
Use: "domain",
Short: "Cloudflare域名管理",
Long: "管理Cloudflare上的域名查询域名列表、查看域名详情等",
}
// 域名列表命令
listDomainsCmd := &cobra.Command{
Use: "list",
Short: "列出所有域名",
Run: func(cmd *cobra.Command, args []string) {
log.Info("获取域名列表")
client := initCloudflareClient()
zones, err := client.ListZones(nil)
if err != nil {
log.Error("获取域名列表失败: %v", err)
os.Exit(1)
}
if len(zones) == 0 {
log.Info("未找到任何域名")
return
}
printDomainsList(zones)
},
}
// 查看域名详情命令
getDomainCmd := &cobra.Command{
Use: "get [域名]",
Short: "获取域名详情",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
domain := args[0]
log.Info("获取域名详情: %s", domain)
client := initCloudflareClient()
zone, err := client.GetZone(domain)
if err != nil {
log.Error("获取域名详情失败: %v", err)
os.Exit(1)
}
printDomainDetails(zone)
},
}
// DNS记录管理命令
dnsCmd := &cobra.Command{
Use: "dns",
Short: "DNS记录管理",
Long: "管理Cloudflare上的DNS记录查询、创建、更新、删除",
}
// 列出DNS记录命令
listDNSCmd := &cobra.Command{
Use: "list [域名]",
Short: "列出域名的所有DNS记录",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
domain := args[0]
log.Info("获取域名 %s 的DNS记录", domain)
client := initCloudflareClient()
// 先获取zone ID
zone, err := client.GetZone(domain)
if err != nil {
log.Error("获取域名信息失败: %v", err)
os.Exit(1)
}
records, err := client.ListDNSRecords(zone.ID, nil)
if err != nil {
log.Error("获取DNS记录失败: %v", err)
os.Exit(1)
}
if len(records) == 0 {
log.Info("未找到任何DNS记录")
return
}
printDNSRecordsList(records, domain)
},
}
// 创建DNS记录命令
createDNSCmd := &cobra.Command{
Use: "create [域名]",
Short: "创建DNS记录",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
domain := args[0]
log.Info("为域名 %s 创建DNS记录", domain)
client := initCloudflareClient()
// 先获取zone ID
zone, err := client.GetZone(domain)
if err != nil {
log.Error("获取域名信息失败: %v", err)
os.Exit(1)
}
// 交互式收集DNS记录信息
record, err := collectDNSRecordInfo(domain)
if err != nil {
log.Error("收集DNS记录信息失败: %v", err)
os.Exit(1)
}
// 确认信息
fmt.Println("\n即将创建以下DNS记录:")
fmt.Printf("名称: %s\n", record.Name)
fmt.Printf("类型: %s\n", record.Type)
fmt.Printf("内容: %s\n", record.Content)
fmt.Printf("TTL: %d\n", record.TTL)
if record.Priority > 0 {
fmt.Printf("优先级: %d\n", record.Priority)
}
fmt.Printf("代理状态: %v\n", record.Proxied)
if !askForConfirmation("确认创建此DNS记录?") {
log.Info("已取消创建DNS记录")
return
}
// 创建DNS记录
createdRecord, err := client.CreateDNSRecord(zone.ID, record)
if err != nil {
log.Error("创建DNS记录失败: %v", err)
os.Exit(1)
}
log.Info("DNS记录创建成功")
printDNSRecordDetails(createdRecord, domain)
},
}
// 更新DNS记录命令
updateDNSCmd := &cobra.Command{
Use: "update [域名]",
Short: "更新DNS记录",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
domain := args[0]
log.Info("更新域名 %s 的DNS记录", domain)
client := initCloudflareClient()
// 先获取zone ID
zone, err := client.GetZone(domain)
if err != nil {
log.Error("获取域名信息失败: %v", err)
os.Exit(1)
}
// 获取域名到ID的映射
dnsNameToIDMap := client.GetDNSNameToIDMap(zone.ID)
if len(dnsNameToIDMap) == 0 {
log.Error("未找到ZoneID %s Zone %s 的任何DNS记录", zone.ID, zone.Name)
os.Exit(1)
}
// recordID 为空则获取所有DNS记录
recordID := dnsNameToIDMap[domain]
if recordID == "" {
log.Error("未找到zoneID %s Zone %s 域名 %s 的DNS记录", zone.ID, zone.Name, domain)
os.Exit(1)
}
// 获取当前记录
currentRecord, err := client.GetDNSRecord(zone.ID, recordID)
if err != nil {
log.Error("获取DNS记录失败: %v", err)
os.Exit(1)
}
// 显示当前记录
fmt.Println("当前DNS记录:")
printDNSRecordDetails(currentRecord, domain)
// 交互式收集更新后的DNS记录信息
updatedRecord, err := updateDNSRecordInfo(*currentRecord)
if err != nil {
log.Error("收集DNS记录更新信息失败: %v", err)
os.Exit(1)
}
// 确认信息
fmt.Println("\n即将更新为以下DNS记录:")
fmt.Printf("名称: %s\n", updatedRecord.Name)
fmt.Printf("类型: %s\n", updatedRecord.Type)
fmt.Printf("内容: %s\n", updatedRecord.Content)
fmt.Printf("TTL: %d\n", updatedRecord.TTL)
if updatedRecord.Priority > 0 {
fmt.Printf("优先级: %d\n", updatedRecord.Priority)
}
fmt.Printf("代理状态: %v\n", updatedRecord.Proxied)
if !askForConfirmation("确认更新此DNS记录?") {
log.Info("已取消更新DNS记录")
return
}
// 更新DNS记录
updatedRecordResult, err := client.UpdateDNSRecord(zone.ID, recordID, updatedRecord)
if err != nil {
log.Error("更新DNS记录失败: %v", err)
os.Exit(1)
}
log.Info("DNS记录更新成功")
printDNSRecordDetails(updatedRecordResult, domain)
},
}
// 删除DNS记录命令
deleteDNSCmd := &cobra.Command{
Use: "delete [域名]",
Short: "删除DNS记录",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
domain := args[0]
log.Info("删除域名 %s 的DNS记录", domain)
client := initCloudflareClient()
// 先获取zone ID
zone, err := client.GetZone(domain)
if err != nil {
log.Error("获取域名信息失败: %v", err)
os.Exit(1)
}
// 获取域名到ID的映射
dnsNameToIDMap := client.GetDNSNameToIDMap(zone.ID)
if len(dnsNameToIDMap) == 0 {
log.Error("未找到ZoneID %s Zone %s 的任何DNS记录", zone.ID, zone.Name)
os.Exit(1)
}
// recordID 为空则获取所有DNS记录
recordID := dnsNameToIDMap[domain]
if recordID == "" {
log.Error("未找到zoneID %s Zone %s 域名 %s 的DNS记录", zone.ID, zone.Name, domain)
os.Exit(1)
}
// 获取要删除的记录信息
record, err := client.GetDNSRecord(zone.ID, recordID)
if err != nil {
log.Error("获取DNS记录信息失败: %v", err)
os.Exit(1)
}
// 显示要删除的记录
fmt.Println("即将删除以下DNS记录:")
printDNSRecordDetails(record, domain)
// 请求确认
if !askForConfirmation("确认删除此DNS记录? 此操作不可恢复!") {
log.Info("已取消删除DNS记录")
return
}
// 二次确认
fmt.Println("\n⚠ 警告: 删除DNS记录可能会影响网站访问、邮件服务等功能")
if !askForConfirmation("再次确认删除此DNS记录?") {
log.Info("已取消删除DNS记录")
return
}
// 删除DNS记录
success, err := client.DeleteDNSRecord(zone.ID, recordID)
if err != nil {
log.Error("删除DNS记录失败: %v", err)
os.Exit(1)
}
if success {
log.Info("DNS记录删除成功")
} else {
log.Error("DNS记录删除失败")
os.Exit(1)
}
},
}
// 添加域名管理子命令
domainCmd.AddCommand(listDomainsCmd, getDomainCmd)
// 添加DNS管理子命令
dnsCmd.AddCommand(listDNSCmd, createDNSCmd, updateDNSCmd, deleteDNSCmd)
// 将所有主要命令添加到父命令
cmd.AddCommand(domainCmd, dnsCmd)
}
// 打印域名列表
func printDomainsList(zones []cloudflare.Zone) {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
fmt.Fprintln(w, "域名\t状态\t名称服务器\t创建时间")
fmt.Fprintln(w, "----\t----\t---------\t--------")
for _, zone := range zones {
nameServers := strings.Join(zone.NameServers, ", ")
createdOn := zone.CreatedOn[:10] // 仅显示日期部分
status := zone.Status
if zone.Paused {
status += " (已暂停)"
}
fmt.Fprintf(w, "%s\t%s\t%s\t%s\n",
zone.Name,
status,
nameServers,
createdOn)
}
w.Flush()
}
// 打印域名详情
func printDomainDetails(zone *cloudflare.Zone) {
fmt.Printf("================== 域名详情 ==================\n")
fmt.Printf("域名: %s\n", zone.Name)
fmt.Printf("ID: %s\n", zone.ID)
fmt.Printf("状态: %s\n", zone.Status)
fmt.Printf("暂停: %v\n", zone.Paused)
fmt.Printf("类型: %s\n", zone.Type)
fmt.Printf("开发模式: %d\n", zone.DevelopmentMode)
fmt.Printf("名称服务器: %s\n", strings.Join(zone.NameServers, ", "))
fmt.Printf("原始名称服务器: %s\n", strings.Join(zone.OriginalNameServers, ", "))
fmt.Printf("修改时间: %s\n", zone.ModifiedOn)
fmt.Printf("创建时间: %s\n", zone.CreatedOn)
fmt.Printf("激活时间: %s\n", zone.ActivatedOn)
if zone.Account.Name != "" {
fmt.Printf("账户: %s (%s)\n", zone.Account.Name, zone.Account.ID)
}
fmt.Printf("==================================================\n")
}
// 打印DNS记录列表
func printDNSRecordsList(records []cloudflare.DNSRecord, domain string) {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
fmt.Fprintf(w, "域名: %s\n\n", domain)
fmt.Fprintln(w, "名称\t类型\t内容\tTTL\t代理\t优先级\t备注")
fmt.Fprintln(w, "----\t----\t----\t---\t----\t-----\t----")
for _, record := range records {
ttl := "自动"
if record.TTL > 1 {
ttl = strconv.Itoa(record.TTL)
}
priority := "-"
if record.Priority > 0 {
priority = strconv.Itoa(record.Priority)
}
proxied := "否"
if record.Proxied {
proxied = "是"
}
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
record.Name,
record.Type,
record.Content,
ttl,
proxied,
priority,
record.Comment)
}
w.Flush()
}
// 打印DNS记录详情
func printDNSRecordDetails(record *cloudflare.DNSRecord, domain string) {
fmt.Printf("================ DNS记录详情 ================\n")
fmt.Printf("域名: %s\n", domain)
fmt.Printf("ID: %s\n", record.ID)
fmt.Printf("名称: %s\n", record.Name)
fmt.Printf("类型: %s\n", record.Type)
fmt.Printf("内容: %s\n", record.Content)
ttl := "自动"
if record.TTL > 1 {
ttl = strconv.Itoa(record.TTL)
}
fmt.Printf("TTL: %s\n", ttl)
fmt.Printf("代理: %v\n", record.Proxied)
if record.Priority > 0 {
fmt.Printf("优先级: %d\n", record.Priority)
}
if record.Comment != "" {
fmt.Printf("备注: %s\n", record.Comment)
}
if record.CreatedOn != "" {
fmt.Printf("创建时间: %s\n", record.CreatedOn)
}
if record.ModifiedOn != "" {
fmt.Printf("修改时间: %s\n", record.ModifiedOn)
}
fmt.Printf("==============================================\n")
}
// 交互式收集DNS记录信息
func collectDNSRecordInfo(domain string) (cloudflare.DNSRecord, error) {
reader := bufio.NewReader(os.Stdin)
record := cloudflare.DNSRecord{
Proxied: false, // 默认不代理
TTL: 1, // 默认自动TTL
}
// 获取记录名称
fmt.Print("请输入记录名称 (例如: www): ")
name, err := reader.ReadString('\n')
if err != nil {
return record, fmt.Errorf("读取输入失败: %w", err)
}
name = strings.TrimSpace(name)
// 如果用户仅输入@,则使用根域名
if name == "@" {
record.Name = domain
} else if name != "" {
// 否则添加域名后缀
record.Name = name + "." + domain
} else {
return record, fmt.Errorf("记录名称不能为空")
}
// 获取记录类型
fmt.Printf("请选择记录类型:\n")
fmt.Printf("1) A (IPv4地址)\n")
fmt.Printf("2) AAAA (IPv6地址)\n")
fmt.Printf("3) CNAME (别名)\n")
fmt.Printf("4) TXT (文本记录)\n")
fmt.Printf("5) MX (邮件服务器)\n")
fmt.Printf("6) SRV (服务记录)\n")
fmt.Print("请输入选项 (1-6): ")
typeChoice, err := reader.ReadString('\n')
if err != nil {
return record, fmt.Errorf("读取输入失败: %w", err)
}
typeChoice = strings.TrimSpace(typeChoice)
switch typeChoice {
case "1":
record.Type = DNSTypeA
case "2":
record.Type = DNSTypeAAAA
case "3":
record.Type = DNSTypeCNAME
case "4":
record.Type = DNSTypeTXT
case "5":
record.Type = DNSTypeMX
case "6":
record.Type = DNSTypeSRV
default:
return record, fmt.Errorf("无效的记录类型选择")
}
// 获取记录内容
fmt.Printf("请输入记录内容 (%s): ", getContentHint(record.Type))
content, err := reader.ReadString('\n')
if err != nil {
return record, fmt.Errorf("读取输入失败: %w", err)
}
content = strings.TrimSpace(content)
if content == "" {
return record, fmt.Errorf("记录内容不能为空")
}
record.Content = content
// 对于MX记录获取优先级
if record.Type == DNSTypeMX {
fmt.Print("请输入优先级 (1-100默认10): ")
priorityStr, err := reader.ReadString('\n')
if err != nil {
return record, fmt.Errorf("读取输入失败: %w", err)
}
priorityStr = strings.TrimSpace(priorityStr)
priority := 10 // 默认优先级
if priorityStr != "" {
p, err := strconv.Atoi(priorityStr)
if err != nil {
return record, fmt.Errorf("无效的优先级: %w", err)
}
if p < 1 || p > 100 {
return record, fmt.Errorf("优先级必须在1到100之间")
}
priority = p
}
record.Priority = priority
}
// 获取TTL
fmt.Print("请输入TTL (1表示自动最小值120建议值1800或3600): ")
ttlStr, err := reader.ReadString('\n')
if err != nil {
return record, fmt.Errorf("读取输入失败: %w", err)
}
ttlStr = strings.TrimSpace(ttlStr)
if ttlStr != "" {
ttl, err := strconv.Atoi(ttlStr)
if err != nil {
return record, fmt.Errorf("无效的TTL: %w", err)
}
if ttl != 1 && ttl < 120 {
return record, fmt.Errorf("TTL不能小于120")
}
record.TTL = ttl
}
// 对于AAAAA或CNAME记录询问是否代理
if record.Type == DNSTypeA || record.Type == DNSTypeAAAA || record.Type == DNSTypeCNAME {
fmt.Print("是否通过Cloudflare代理 (y/n默认n): ")
proxyStr, err := reader.ReadString('\n')
if err != nil {
return record, fmt.Errorf("读取输入失败: %w", err)
}
proxyStr = strings.ToLower(strings.TrimSpace(proxyStr))
if proxyStr == "y" || proxyStr == "yes" {
record.Proxied = true
}
}
// 获取备注(可选)
fmt.Print("请输入备注 (可选): ")
comment, err := reader.ReadString('\n')
if err != nil {
return record, fmt.Errorf("读取输入失败: %w", err)
}
comment = strings.TrimSpace(comment)
if comment != "" {
record.Comment = comment
}
return record, nil
}
// 更新DNS记录信息
func updateDNSRecordInfo(currentRecord cloudflare.DNSRecord) (cloudflare.DNSRecord, error) {
reader := bufio.NewReader(os.Stdin)
updatedRecord := currentRecord
// 获取记录内容
fmt.Printf("请输入新的记录内容 (%s) [当前值: %s]: ", getContentHint(currentRecord.Type), currentRecord.Content)
content, err := reader.ReadString('\n')
if err != nil {
return updatedRecord, fmt.Errorf("读取输入失败: %w", err)
}
content = strings.TrimSpace(content)
if content != "" {
updatedRecord.Content = content
}
// 对于MX记录获取优先级
if currentRecord.Type == DNSTypeMX {
fmt.Printf("请输入新的优先级 (1-100) [当前值: %d]: ", currentRecord.Priority)
priorityStr, err := reader.ReadString('\n')
if err != nil {
return updatedRecord, fmt.Errorf("读取输入失败: %w", err)
}
priorityStr = strings.TrimSpace(priorityStr)
if priorityStr != "" {
p, err := strconv.Atoi(priorityStr)
if err != nil {
return updatedRecord, fmt.Errorf("无效的优先级: %w", err)
}
if p < 1 || p > 100 {
return updatedRecord, fmt.Errorf("优先级必须在1到100之间")
}
updatedRecord.Priority = p
}
}
// 获取TTL
ttlStr := "自动"
if currentRecord.TTL > 1 {
ttlStr = strconv.Itoa(currentRecord.TTL)
}
fmt.Printf("请输入新的TTL (1表示自动最小值120建议值1800或3600) [当前值: %s]: ", ttlStr)
newTTLStr, err := reader.ReadString('\n')
if err != nil {
return updatedRecord, fmt.Errorf("读取输入失败: %w", err)
}
newTTLStr = strings.TrimSpace(newTTLStr)
if newTTLStr != "" {
ttl, err := strconv.Atoi(newTTLStr)
if err != nil {
return updatedRecord, fmt.Errorf("无效的TTL: %w", err)
}
if ttl != 1 && ttl < 120 {
return updatedRecord, fmt.Errorf("TTL不能小于120")
}
updatedRecord.TTL = ttl
}
// 对于AAAAA或CNAME记录询问是否代理
if currentRecord.Type == DNSTypeA || currentRecord.Type == DNSTypeAAAA || currentRecord.Type == DNSTypeCNAME {
proxyStr := "n"
if currentRecord.Proxied {
proxyStr = "y"
}
fmt.Printf("是否通过Cloudflare代理 (y/n) [当前值: %s]: ", proxyStr)
newProxyStr, err := reader.ReadString('\n')
if err != nil {
return updatedRecord, fmt.Errorf("读取输入失败: %w", err)
}
newProxyStr = strings.ToLower(strings.TrimSpace(newProxyStr))
if newProxyStr != "" {
if newProxyStr == "y" || newProxyStr == "yes" {
updatedRecord.Proxied = true
} else if newProxyStr == "n" || newProxyStr == "no" {
updatedRecord.Proxied = false
}
}
}
// 获取备注(可选)
fmt.Printf("请输入新的备注 (可选) [当前值: %s]: ", currentRecord.Comment)
comment, err := reader.ReadString('\n')
if err != nil {
return updatedRecord, fmt.Errorf("读取输入失败: %w", err)
}
comment = strings.TrimSpace(comment)
if comment != "" {
updatedRecord.Comment = comment
}
return updatedRecord, nil
}
// 根据记录类型获取内容提示
func getContentHint(recordType string) string {
switch recordType {
case DNSTypeA:
return "IPv4地址例如: 192.168.1.1"
case DNSTypeAAAA:
return "IPv6地址例如: 2001:db8::1"
case DNSTypeCNAME:
return "域名,例如: example.com"
case DNSTypeTXT:
return "文本内容"
case DNSTypeMX:
return "邮件服务器域名,例如: mail.example.com"
case DNSTypeSRV:
return "SRV记录例如: 10 5 5060 sip.example.com"
default:
return "记录内容"
}
}

View File

@@ -1,7 +1,7 @@
package cmd package cmd
import ( import (
"agent-wdd/config" "agent-wdd/host_info"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@@ -13,7 +13,7 @@ func addInfoSubcommands(cmd *cobra.Command) {
Use: "os", Use: "os",
Short: "主机操作系统相关的信息", Short: "主机操作系统相关的信息",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
os := config.ConfigCache.Agent.OS os := host_info.ConfigCache.Agent.OS
os.Gather() os.Gather()
os.SaveConfig() os.SaveConfig()
@@ -25,7 +25,7 @@ func addInfoSubcommands(cmd *cobra.Command) {
Use: "network", Use: "network",
Short: "主机Network相关的信息", Short: "主机Network相关的信息",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
network := config.ConfigCache.Agent.Network network := host_info.ConfigCache.Agent.Network
network.Gather() network.Gather()
network.SaveConfig() network.SaveConfig()
}, },
@@ -36,7 +36,7 @@ func addInfoSubcommands(cmd *cobra.Command) {
Use: "cpu", Use: "cpu",
Short: "主机cpu相关的信息", Short: "主机cpu相关的信息",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
cpu := config.ConfigCache.Agent.CPU cpu := host_info.ConfigCache.Agent.CPU
cpu.Gather() cpu.Gather()
cpu.Save() cpu.Save()
}, },
@@ -47,9 +47,9 @@ func addInfoSubcommands(cmd *cobra.Command) {
Use: "mem", Use: "mem",
Short: "主机memory相关的信息", Short: "主机memory相关的信息",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
mem := config.ConfigCache.Agent.Mem mem := host_info.ConfigCache.Agent.Mem
mem.Gather() mem.Gather()
swap := config.ConfigCache.Agent.Swap swap := host_info.ConfigCache.Agent.Swap
swap.Gather() swap.Gather()
mem.SaveConfig() mem.SaveConfig()
@@ -63,10 +63,10 @@ func addInfoSubcommands(cmd *cobra.Command) {
Use: "disk", Use: "disk",
Short: "主机disk相关的信息", Short: "主机disk相关的信息",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
//disks := config.ConfigCache.Agent.Disks //disks := host_info.ConfigCache.Agent.Disks
config.DiskListGather() host_info.DiskListGather()
config.DiskListSaveConfig() host_info.DiskListSaveConfig()
}, },
} }
@@ -83,7 +83,7 @@ func addInfoSubcommands(cmd *cobra.Command) {
disk.Run(cmd, args) disk.Run(cmd, args)
// 归一化 // 归一化
config.ConfigCache.NormalizeConfig() host_info.ConfigCache.NormalizeConfig()
}, },
} }

View File

@@ -2,7 +2,7 @@ package cmd
import ( import (
"agent-wdd/cmd/xray" "agent-wdd/cmd/xray"
"agent-wdd/config" "agent-wdd/host_info"
"agent-wdd/log" "agent-wdd/log"
"agent-wdd/op" "agent-wdd/op"
"agent-wdd/utils" "agent-wdd/utils"
@@ -229,7 +229,7 @@ func installVmess(port string) (bool, []string) {
result.Reset() // 清空全局buffer以备后续使用 result.Reset() // 清空全局buffer以备后续使用
// 输出 client的配置 // 输出 client的配置
configCache := config.ConfigCache configCache := host_info.ConfigCache
// 获取服务器节点名称 // 获取服务器节点名称
serverNodeName := configCache.Agent.OS.Hostname serverNodeName := configCache.Agent.OS.Hostname

View File

@@ -1,7 +1,7 @@
package cmd package cmd
import ( import (
"agent-wdd/config" "agent-wdd/host_info"
"agent-wdd/log" "agent-wdd/log"
"agent-wdd/op" "agent-wdd/op"
"agent-wdd/utils" "agent-wdd/utils"
@@ -16,14 +16,14 @@ func addZshSubcommands(cmd *cobra.Command) {
// 初始化安装命令 // 初始化安装命令
utils.CreateFolder("/root/wdd") utils.CreateFolder("/root/wdd")
if config.CanConnectInternet() <= 1 { if host_info.CanConnectInternet() <= 1 {
log.Error("无法连接互联网无法安装zsh") log.Error("无法连接互联网无法安装zsh")
return return
} }
// 判定config // 判定config
if config.ConfigCache.Agent.Network.Public.IPv4 == "" { if host_info.ConfigCache.Agent.Network.Public.IPv4 == "" {
network := config.ConfigCache.Agent.Network network := host_info.ConfigCache.Agent.Network
network.Gather() network.Gather()
network.SaveConfig() network.SaveConfig()
} }
@@ -41,7 +41,7 @@ func addZshSubcommands(cmd *cobra.Command) {
ohMyZshInstallUrl := "" ohMyZshInstallUrl := ""
if config.ConfigCache.Agent.Network.Internet == 7 { if host_info.ConfigCache.Agent.Network.Internet == 7 {
ohMyZshInstallUrl = "https://gitea.107421.xyz/zeaslity/ohmyzsh/raw/branch/master/tools/install.sh" ohMyZshInstallUrl = "https://gitea.107421.xyz/zeaslity/ohmyzsh/raw/branch/master/tools/install.sh"
} else { } else {
ohMyZshInstallUrl = "https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh" ohMyZshInstallUrl = "https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh"
@@ -65,7 +65,7 @@ func addZshSubcommands(cmd *cobra.Command) {
"/root/wdd/zsh-install.sh", "/root/wdd/zsh-install.sh",
} }
if config.ConfigCache.Agent.Network.Internet == 7 { if host_info.ConfigCache.Agent.Network.Internet == 7 {
op.SingleLineCommandExecutor([]string{ op.SingleLineCommandExecutor([]string{
"export", "export",
"REMOTE=https://gitea.107421.xyz/zeaslity/ohmyzsh.git", "REMOTE=https://gitea.107421.xyz/zeaslity/ohmyzsh.git",
@@ -106,7 +106,7 @@ func addZshSubcommands(cmd *cobra.Command) {
} }
// 下载插件 // 下载插件
if config.ConfigCache.Agent.Network.Internet == 7 { if host_info.ConfigCache.Agent.Network.Internet == 7 {
// 执行硬编码命令, 安装插件 // 执行硬编码命令, 安装插件
for _, command := range pluginsHardCodeUrl { for _, command := range pluginsHardCodeUrl {
op.SingleLineCommandExecutor([]string{"git", "clone", command[0], command[1]}) op.SingleLineCommandExecutor([]string{"git", "clone", command[0], command[1]})

View File

@@ -1,7 +1,7 @@
package cmd package cmd
import ( import (
"agent-wdd/config" "agent-wdd/host_info"
"fmt" "fmt"
"io" "io"
"os" "os"
@@ -26,7 +26,7 @@ var rootCmd = &cobra.Command{
func init() { func init() {
// 初始化配置 // 初始化配置
cobra.OnInitialize(config.InitConfig) cobra.OnInitialize(host_info.InitConfig)
} }
func Execute() { func Execute() {
@@ -111,6 +111,9 @@ func Execute() {
} }
addCertManagerSubcommands(certCmd) addCertManagerSubcommands(certCmd)
// 添加Cloudflare命令
addCloudflareSubcommands(rootCmd)
helpCmd := &cobra.Command{ helpCmd := &cobra.Command{
Use: "help", Use: "help",
Short: "帮助信息", Short: "帮助信息",

View File

@@ -127,13 +127,13 @@ func InitConfig() {
v.SetConfigType("yaml") v.SetConfigType("yaml")
if err := v.ReadInConfig(); err != nil { if err := v.ReadInConfig(); err != nil {
log.Error("读取配置文件失败: %w", err) log.Error("读取配置文件失败: %v", err)
panic(err) panic(err)
} }
if err := v.Unmarshal(&ConfigCache); err != nil { if err := v.Unmarshal(&ConfigCache); err != nil {
log.Error("解析配置失败: %w", err) log.Error("解析配置失败: %v", err)
panic(err) panic(err)
} }
@@ -150,11 +150,11 @@ func SaveConfig() {
data, err := yaml.Marshal(&ConfigCache) data, err := yaml.Marshal(&ConfigCache)
if err != nil { if err != nil {
log.Error("YAML序列化失败: %w", err) log.Error("YAML序列化失败: %v", err)
} }
if err := os.WriteFile(WddConfigFilePath, data, 0644); err != nil { if err := os.WriteFile(WddConfigFilePath, data, 0644); err != nil {
log.Error("写入文件失败: %w", err) log.Error("写入文件失败: %v", err)
} }
} }

View File

@@ -8,6 +8,10 @@ import (
"time" "time"
) )
var (
DebugMode = true
)
const ( const (
colorReset = "\033[0m" colorReset = "\033[0m"
colorRed = "\033[31m" colorRed = "\033[31m"
@@ -16,16 +20,11 @@ const (
colorBlue = "\033[34m" colorBlue = "\033[34m"
) )
func main() {
Debug("Debug message: %s", "connection established")
Info("System %s", "started successfully")
Warning("Disk space at %d%%", 85)
Error("Failed to %s", "load config")
}
func Debug(format string, args ...interface{}) { func Debug(format string, args ...interface{}) {
if DebugMode {
log("DEBUG", colorBlue, format, args...) log("DEBUG", colorBlue, format, args...)
} }
}
func Info(format string, args ...interface{}) { func Info(format string, args ...interface{}) {
log("INFO", colorGreen, format, args...) log("INFO", colorGreen, format, args...)

View File

@@ -213,45 +213,3 @@ func RealTimeCommandExecutor(realTimeCommand []string) (ok bool, resultLog []str
return true, output return true, output
} }
func main() {
// 成功案例
success, output := SingleLineCommandExecutor([]string{"ls", "-l"})
fmt.Println("执行成功:", success)
fmt.Println("输出内容:", output)
// 失败案例(命令存在但参数错误)
success, output = SingleLineCommandExecutor([]string{"ls", "/nonexistent"})
fmt.Println("执行成功:", success)
fmt.Println("输出内容:", output)
// 失败案例(命令不存在)
success, output = SingleLineCommandExecutor([]string{"invalid_command"})
fmt.Println("执行成功:", success)
fmt.Println("输出内容:", output)
// 成功案例(三阶管道)
success, output = PipeLineCommandExecutor([][]string{
{"ps", "aux"},
{"grep", "nginx"},
{"wc", "-l"},
})
fmt.Println("执行结果:", success)
fmt.Println("合并输出:", output)
// 失败案例(命令不存在)
success, output = PipeLineCommandExecutor([][]string{
{"invalid_cmd"},
{"wc", "-l"},
})
fmt.Println("执行结果:", success)
fmt.Println("合并输出:", output)
// 失败案例(参数错误)
success, output = PipeLineCommandExecutor([][]string{
{"ls", "/nonexistent"},
{"grep", "test"},
})
fmt.Println("执行结果:", success)
fmt.Println("合并输出:", output)
}

View File

@@ -1,7 +1,7 @@
package op package op
import ( import (
"agent-wdd/config" "agent-wdd/host_info"
"agent-wdd/log" "agent-wdd/log"
"encoding/json" "encoding/json"
"fmt" "fmt"
@@ -72,10 +72,10 @@ func (op *PackageOperator) Install(tools []string) bool {
func (op *PackageOperator) PackageInit() bool { func (op *PackageOperator) PackageInit() bool {
log.Info("PackageInit !") log.Info("PackageInit !")
// beautifulPrintListWithTitle(config.ConfigCache) // beautifulPrintListWithTitle(host_info.ConfigCache)
// package init // package init
os := config.ConfigCache.Agent.OS os := host_info.ConfigCache.Agent.OS
if os.PackInit { if os.PackInit {
log.Info("PackageInit already done! skip!") log.Info("PackageInit already done! skip!")
@@ -106,7 +106,7 @@ func (op *PackageOperator) PackageInitForce() bool {
log.Info("PackageInitForce !") log.Info("PackageInitForce !")
os := config.ConfigCache.Agent.OS os := host_info.ConfigCache.Agent.OS
if os.IsUbuntuType { if os.IsUbuntuType {
ok, resultLog := SingleLineCommandExecutor(aptPackageOperator.initCommand) ok, resultLog := SingleLineCommandExecutor(aptPackageOperator.initCommand)
@@ -143,13 +143,13 @@ func generatePackageOperator() bool {
} }
// 检查是否可以连接互联网 // 检查是否可以连接互联网
if config.CanConnectInternet() <= 1 { if host_info.CanConnectInternet() <= 1 {
log.Error("服务器无法连接互联网,无法初始化包管理器") log.Error("服务器无法连接互联网,无法初始化包管理器")
return false return false
} }
// 检查本机是否存在OS的信息 // 检查本机是否存在OS的信息
os := config.ConfigCache.Agent.OS os := host_info.ConfigCache.Agent.OS
if os.Hostname == "" { if os.Hostname == "" {
os.Gather() os.Gather()
os.SaveConfig() os.SaveConfig()
@@ -169,7 +169,7 @@ func generatePackageOperator() bool {
// GetLatestGithubReleaseVersion 获取GitHub仓库的最新版本 // GetLatestGithubReleaseVersion 获取GitHub仓库的最新版本
func GetLatestGithubReleaseVersion(repoOwner, repoName string) (string, error) { func GetLatestGithubReleaseVersion(repoOwner, repoName string) (string, error) {
// 检查是否可以连接互联网 // 检查是否可以连接互联网
if config.CanConnectInternet() <= 1 { if host_info.CanConnectInternet() <= 1 {
return "", fmt.Errorf("服务器无法连接互联网无法获取GitHub最新版本") return "", fmt.Errorf("服务器无法连接互联网无法获取GitHub最新版本")
} }