[ Cmii ] [ Octopus ] - reformat agent-go - 1
This commit is contained in:
1114
agent-go/a_executor/AppFunction.go
Normal file
1114
agent-go/a_executor/AppFunction.go
Normal file
File diff suppressed because it is too large
Load Diff
2416
agent-go/a_executor/BaseFunction.go
Normal file
2416
agent-go/a_executor/BaseFunction.go
Normal file
File diff suppressed because it is too large
Load Diff
80
agent-go/a_executor/BaseFunction_test.go
Normal file
80
agent-go/a_executor/BaseFunction_test.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package a_executor
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"wdd.io/agent-common/assert"
|
||||
"wdd.io/agent-go/a_agent"
|
||||
)
|
||||
|
||||
var agentOP = &AgentOsOperator{
|
||||
InstallCommandPrefix: []string{
|
||||
"yum", "install", "-y",
|
||||
},
|
||||
RemoveCommandPrefix: []string{"yum", "remove", "-y"},
|
||||
CanAccessInternet: true,
|
||||
IsOsTypeUbuntu: false,
|
||||
IsOsTypeCentOS: true,
|
||||
IsOsTypeEuler: true,
|
||||
IsAgentInnerWall: true,
|
||||
AgentArch: "amd64",
|
||||
AgentOSReleaseCode: "focal",
|
||||
AgentServerInfo: &a_agent.AgentServerInfo{
|
||||
ServerName: "",
|
||||
ServerIPPbV4: "",
|
||||
ServerIPInV4: "10.250.0.100",
|
||||
ServerIPPbV6: "",
|
||||
ServerIPInV6: "",
|
||||
Location: "",
|
||||
Provider: "",
|
||||
ManagePort: "",
|
||||
CPUCore: "",
|
||||
CPUBrand: "",
|
||||
OSInfo: "",
|
||||
OSKernelInfo: "",
|
||||
TCPControl: "",
|
||||
Virtualization: "",
|
||||
IoSpeed: "",
|
||||
MemoryTotal: "",
|
||||
DiskTotal: "",
|
||||
DiskUsage: "",
|
||||
Comment: "",
|
||||
MachineID: "",
|
||||
AgentVersion: "",
|
||||
TopicName: "",
|
||||
},
|
||||
OssOfflinePrefix: "http://10.250.0.100:9000/octopus/",
|
||||
}
|
||||
|
||||
func TestBaseFunc(t *testing.T) {
|
||||
|
||||
//command := "DISABLE_SELINUX"
|
||||
//command := "installDocker"
|
||||
//command := "installDockerCompose"
|
||||
command := "installHarbor"
|
||||
|
||||
funcArgs := []string{
|
||||
"10.250.0.147",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
}
|
||||
|
||||
//agentOP.Exec("shutdownFirewall")
|
||||
//agentOP.Exec("modifyHostname")
|
||||
//agentOP.Exec("disableSwap")
|
||||
//agentOP.Exec("enableSwap")
|
||||
//agentOP.Exec("removeDocker")
|
||||
//agentOP.Exec("installDocker", "20")
|
||||
//agentOP.Exec("removeDockerCompose")
|
||||
//agentOP.Exec("installDockerCompose")
|
||||
//agentOP.Exec("installHelm")
|
||||
//agentOP.Exec("installHarbor")
|
||||
//agentOP.Exec("chronyToMaster", "192.168.0.8")
|
||||
//agentOP.Exec("installZSH")
|
||||
//agentOP.Exec("ok")
|
||||
|
||||
exec, strings := agentOP.Exec(command, funcArgs...)
|
||||
assert.Equal(t, exec, true, "exec should be true!")
|
||||
t.Logf("[%s] exec result are %s", command, strings)
|
||||
|
||||
}
|
||||
683
agent-go/a_executor/BasicFunction.go
Normal file
683
agent-go/a_executor/BasicFunction.go
Normal file
@@ -0,0 +1,683 @@
|
||||
package a_executor
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var RemoveForcePrefix = []string{"rm", "-rf"}
|
||||
|
||||
// BasicCommandExists 判定命令是否存在
|
||||
func BasicCommandExists(commandName string) bool {
|
||||
|
||||
cmd := exec.Command("command", "-v", commandName)
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
log.DebugF("指令 %s 不存在 => %s", commandName, err.Error())
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// BasicCommandExistsBatch 判定批量命令是否存在
|
||||
func BasicCommandExistsBatch(commandNameList []string) (bool, string) {
|
||||
|
||||
for _, commandName := range commandNameList {
|
||||
if !BasicCommandExists(commandName) {
|
||||
return false, commandName
|
||||
}
|
||||
}
|
||||
|
||||
return true, ""
|
||||
}
|
||||
|
||||
// BasicCommandExistByPath 根据路径判定 命令是否存在
|
||||
func BasicCommandExistByPath(commandName string) bool {
|
||||
|
||||
if BasicFileExistInFolder(commandName, "/usr/local/sbin", "/usr/local/bin", "/usr/sbin", "/usr/bin", "/sbin", "bin", "/snap/bin") {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// BasicFileExistInFolder 查询fileName是否存在于目录folderList中,如果存在返回true,不存在返回false
|
||||
func BasicFileExistInFolder(fileName string, folderList ...string) bool {
|
||||
|
||||
for _, folder := range folderList {
|
||||
if BasicFolderExists(folder) {
|
||||
// is folder
|
||||
ok, _ := PipelineCommandExecutor([][]string{
|
||||
{
|
||||
"ls",
|
||||
folder,
|
||||
},
|
||||
{
|
||||
"grep",
|
||||
"-c",
|
||||
fileName,
|
||||
},
|
||||
})
|
||||
if ok {
|
||||
return true
|
||||
}
|
||||
|
||||
} else {
|
||||
// it's a file
|
||||
ok, _ := PipelineCommandExecutor([][]string{
|
||||
{
|
||||
"echo",
|
||||
folder,
|
||||
},
|
||||
{
|
||||
"grep",
|
||||
"-c",
|
||||
fileName,
|
||||
},
|
||||
})
|
||||
if ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func BasicGrepItemInFile(item string, fileName string) bool {
|
||||
|
||||
if !BasicFileExistAndNotNull(fileName) {
|
||||
log.ErrorF("[BasicGrepItemInFile] - fileName [ %s ] not exits !", fileName)
|
||||
return false
|
||||
}
|
||||
|
||||
ok, _ := PipelineCommandExecutor([][]string{
|
||||
{
|
||||
"cat",
|
||||
fileName,
|
||||
},
|
||||
{
|
||||
"grep",
|
||||
"-q",
|
||||
item,
|
||||
},
|
||||
})
|
||||
|
||||
if ok {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func BasicFindContentInFile(content string, fileName string) bool {
|
||||
// Open the file
|
||||
file, err := os.Open(fileName)
|
||||
if err != nil {
|
||||
log.ErrorF("[BasicFindContentInFile] - file not exits !")
|
||||
return false
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// Create a scanner to read the file line by line
|
||||
scanner := bufio.NewScanner(file)
|
||||
|
||||
// Set the split function for the scanner
|
||||
scanner.Split(bufio.ScanLines)
|
||||
|
||||
// Iterate over the lines of the file
|
||||
for scanner.Scan() {
|
||||
// Get the current line
|
||||
line := scanner.Text()
|
||||
|
||||
// Check if the current line contains the search term
|
||||
if strings.Contains(line, content) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Check for any errors that occurred during scanning
|
||||
if err := scanner.Err(); err != nil {
|
||||
log.ErrorF("[BasicFindContentInFile] - scanner error ! %s", err.Error())
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func BasicFindAndDeleteContendLineInFile(content string, fileName string) bool {
|
||||
|
||||
// Open the file
|
||||
file, err := os.Open(fileName)
|
||||
if err != nil {
|
||||
log.ErrorF("[FindDeleteContendLineInFile] - file not exits !")
|
||||
return false
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// Create a scanner to read the file line by line
|
||||
scanner := bufio.NewScanner(file)
|
||||
|
||||
// Set the split function for the scanner
|
||||
scanner.Split(bufio.ScanLines)
|
||||
|
||||
// 创建一个新的文件内容变量
|
||||
var newContent string
|
||||
|
||||
// Iterate over the lines of the file
|
||||
for scanner.Scan() {
|
||||
// Get the current line
|
||||
line := scanner.Text()
|
||||
|
||||
// Check if the current line contains the search term
|
||||
if !strings.Contains(line, content) {
|
||||
newContent += line + "\n"
|
||||
}
|
||||
}
|
||||
|
||||
// Check for any errors that occurred during scanning
|
||||
if err := scanner.Err(); err != nil {
|
||||
log.ErrorF("[BasicFindContentInFile] - scanner error ! %s", err.Error())
|
||||
return false
|
||||
}
|
||||
|
||||
// 将修改后的内容写回文件
|
||||
err = os.WriteFile(fileName, []byte(newContent), os.ModePerm)
|
||||
if err != nil {
|
||||
log.ErrorF("[FindDeleteContendLineInFile] - write file %s error with contend %s", fileName, newContent)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func BasicFindContentInCommandOutput(hardCodeCommand string, content string) (bool, []string) {
|
||||
ok, resultLog := HardCodeCommandExecutor(hardCodeCommand)
|
||||
if !ok {
|
||||
log.ErrorF("[BasicFindContentInCommandOutput] - command error ! => %v", resultLog)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return BasicFindContentInList(content, resultLog), resultLog
|
||||
}
|
||||
|
||||
func BasicFindContentInList(content string, list []string) bool {
|
||||
for _, item := range list {
|
||||
if strings.Contains(item, content) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func BasicDockerImageExistByFullName(imageFullName string) bool {
|
||||
|
||||
var imageVersion string
|
||||
|
||||
split := strings.Split(imageFullName, ":")
|
||||
imageVersion = split[len(split)-1]
|
||||
|
||||
imageFullName = strings.TrimSuffix(imageFullName, ":"+imageVersion)
|
||||
|
||||
//log.DebugF("[BasicDockerImageExistByFullName] -- %s %s", imageFullName, imageVersion)
|
||||
return BasicDockerImageExists(imageFullName, imageVersion)
|
||||
}
|
||||
|
||||
func BasicDockerImageExists(imageName, imageVersion string) bool {
|
||||
|
||||
if !BasicCommandExistByPath("docker") {
|
||||
return false
|
||||
}
|
||||
|
||||
ok, _ := PipelineCommandExecutor([][]string{
|
||||
{
|
||||
"docker",
|
||||
"image",
|
||||
"ls",
|
||||
},
|
||||
{
|
||||
"grep",
|
||||
imageName,
|
||||
},
|
||||
{
|
||||
"grep",
|
||||
"-q",
|
||||
imageVersion,
|
||||
},
|
||||
})
|
||||
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func BasicInstallSoftwares(installPrefix []string, isStrict bool, softwares ...string) (bool, []string) {
|
||||
|
||||
var installLog []string
|
||||
|
||||
for _, software := range softwares {
|
||||
log.DebugF("[BasicInstallSoftwares] - going to install [ %s ]", software)
|
||||
|
||||
if !PureResultSingleExecute(append(installPrefix, software)) {
|
||||
|
||||
failedInstall := fmt.Sprintf("[BasicInstallSoftwares] - software of [ %s ] install failed !", software)
|
||||
installLog = append(installLog, failedInstall)
|
||||
|
||||
if isStrict {
|
||||
return false, installLog
|
||||
}
|
||||
}
|
||||
|
||||
successInstall := fmt.Sprintf("[BasicInstallSoftwares] - software of [ %s ] install success !", software)
|
||||
installLog = append(installLog, successInstall)
|
||||
}
|
||||
|
||||
return true, installLog
|
||||
}
|
||||
|
||||
// BasicReplace 基础替换命令
|
||||
func BasicReplace(filename string, origin string, replace string) bool {
|
||||
|
||||
// 暂不添加
|
||||
//if !BasicFileExistAndNotNull(filename) {
|
||||
// log.DebugF("文件替换")
|
||||
//}
|
||||
|
||||
cmd := exec.Command("sed", "-i", "s/"+origin+"/"+replace+"/g", filename)
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
log.DebugF("替换文件 %s ,从 [%s] => [%s] 错误!", filename, origin, replace)
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func BasicRemoveFolderComplete(folderName string) bool {
|
||||
|
||||
if !BasicFileExists(folderName) || !BasicFolderExists(folderName) {
|
||||
log.DebugF("[BasicRemoveFolderComplete] - file or folder of [%s] not exists !", folderName)
|
||||
return true
|
||||
}
|
||||
|
||||
cmd := exec.Command("rm", "-rf", folderName)
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
log.DebugF("删除 %s 失败!", folderName)
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// BasicFileExists 检测文件是否存在
|
||||
func BasicFileExists(filename string) bool {
|
||||
|
||||
cmd := exec.Command("test", "-f", filename)
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
log.DebugF("文件 %s 不存在!", filename)
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// BasicFileExistAndNotNull 文件不为空返回true 文件为空返回false
|
||||
func BasicFileExistAndNotNull(filename string) bool {
|
||||
|
||||
cmd := exec.Command("test", "-s", filename)
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
log.DebugF("文件 %s 为空!", filename)
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func BasicFolderExists(folderName string) bool {
|
||||
|
||||
cmd := exec.Command("test", "-d", folderName)
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
log.DebugF("目录 %s 不存在!", folderName)
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func BasicCreateFolder(folderName string) bool {
|
||||
// 检查目录是否存在
|
||||
if _, err := os.Stat(folderName); os.IsNotExist(err) {
|
||||
// 目录不存在,创建目录
|
||||
err := os.MkdirAll(folderName, os.ModePerm)
|
||||
if err != nil {
|
||||
// 如果创建目录失败,返回false
|
||||
return false
|
||||
}
|
||||
}
|
||||
// 目录存在或者成功创建,返回true
|
||||
return true
|
||||
}
|
||||
|
||||
func BasicRemoveFileOrFolder(folderName string) bool {
|
||||
// Check if the folder exists
|
||||
if _, err := os.Stat(folderName); os.IsNotExist(err) {
|
||||
return true // folder does not exist
|
||||
}
|
||||
|
||||
// Folder exists, remove it
|
||||
err := os.Remove(folderName)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
return false
|
||||
}
|
||||
|
||||
return true // folder was removed
|
||||
}
|
||||
|
||||
// BasicPrettyPrint 打印执行结果
|
||||
func BasicPrettyPrint(resultOk bool, resultLog []string) {
|
||||
fmt.Printf("resultOK is => %#v\n", resultOk)
|
||||
if resultLog == nil || len(resultLog) == 0 {
|
||||
return
|
||||
}
|
||||
for _, s := range resultLog {
|
||||
fmt.Println(s)
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
// BasicSystemdShutdown 使用Systemd关闭服务,会判定服务器是否存在
|
||||
func BasicSystemdShutdown(serviceName string) (ok bool, resultLog []string) {
|
||||
|
||||
if !strings.HasSuffix(serviceName, ".service") {
|
||||
serviceName = serviceName + ".service"
|
||||
}
|
||||
|
||||
// 检查是否存在
|
||||
existService := BasicFileExistInFolder(serviceName, "/lib/systemd/system/",
|
||||
"/etc/systemd/system")
|
||||
if !existService {
|
||||
return true, []string{
|
||||
serviceName,
|
||||
"该服务不存在!",
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭
|
||||
var shutDownCommand = [][]string{
|
||||
{
|
||||
"systemctl",
|
||||
"stop",
|
||||
serviceName,
|
||||
},
|
||||
{
|
||||
"sleep",
|
||||
"1",
|
||||
},
|
||||
{
|
||||
"systemctl",
|
||||
"disable",
|
||||
serviceName,
|
||||
},
|
||||
}
|
||||
|
||||
resultOK := PureResultSingleExecuteBatch(shutDownCommand)
|
||||
|
||||
return resultOK, resultLog
|
||||
}
|
||||
|
||||
// BasicSystemdUp 使用Systemd启动服务,会判定服务器是否存在
|
||||
func BasicSystemdUp(serviceName string) (ok bool, resultLog []string) {
|
||||
|
||||
if !strings.HasSuffix(serviceName, ".service") {
|
||||
serviceName = serviceName + ".service"
|
||||
}
|
||||
// 检查是否存在
|
||||
existService := BasicFileExistInFolder(serviceName, "/lib/systemd/system/",
|
||||
"/etc/systemd/system")
|
||||
if !existService {
|
||||
return true, []string{
|
||||
serviceName,
|
||||
"该服务不存在!",
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭
|
||||
var shutDownCommand = [][]string{
|
||||
{
|
||||
"systemctl",
|
||||
"start",
|
||||
serviceName,
|
||||
},
|
||||
{
|
||||
"sleep",
|
||||
"1",
|
||||
},
|
||||
{
|
||||
"systemctl",
|
||||
"enable",
|
||||
serviceName,
|
||||
},
|
||||
}
|
||||
|
||||
resultOK := PureResultSingleExecuteBatch(shutDownCommand)
|
||||
|
||||
return resultOK, resultLog
|
||||
}
|
||||
|
||||
// BasicTransPipelineCommand 转换手写的管道命令为可执行的形式
|
||||
func BasicTransPipelineCommand(pipelineString string) (pipelineCommand [][]string) {
|
||||
|
||||
var pipelineCommandC [][]string
|
||||
split := strings.Split(pipelineString, "|")
|
||||
if len(split) == 0 {
|
||||
log.WarnF("输入的pipelineString有误! %s", pipelineString)
|
||||
return pipelineCommandC
|
||||
}
|
||||
|
||||
for _, s := range split {
|
||||
// 去除掉无效的空行
|
||||
singleCommand := strings.Split(s, " ")
|
||||
var realSingleCommand []string
|
||||
|
||||
for i := range singleCommand {
|
||||
if singleCommand[i] != "" {
|
||||
realSingleCommand = append(realSingleCommand, singleCommand[i])
|
||||
}
|
||||
}
|
||||
pipelineCommandC = append(pipelineCommandC, realSingleCommand)
|
||||
}
|
||||
|
||||
return pipelineCommandC
|
||||
}
|
||||
|
||||
func BasicConvertBufferToSlice(outputBuffer bytes.Buffer) (resultLog []string) {
|
||||
|
||||
s := outputBuffer.String()
|
||||
split := strings.Split(s, "\n")
|
||||
|
||||
return split
|
||||
|
||||
}
|
||||
|
||||
// BasicDownloadFile 从目标地址下载文件到目的地,并检测文件是否下载成功
|
||||
func BasicDownloadFile(downloadUrl, desFile string) (downloadOk bool, resultLog []string) {
|
||||
|
||||
// wget or curl download
|
||||
var ok bool
|
||||
if BasicCommandExistByPath("wget") {
|
||||
|
||||
ok, resultLog = AllCommandExecutor([]string{
|
||||
"wget",
|
||||
"--no-check-certificate",
|
||||
"--timeout=5",
|
||||
downloadUrl,
|
||||
"-qO",
|
||||
desFile,
|
||||
})
|
||||
|
||||
} else if BasicCommandExistByPath("curl") {
|
||||
ok, resultLog = AllCommandExecutor([]string{
|
||||
"curl",
|
||||
"-o",
|
||||
desFile,
|
||||
"--insecure",
|
||||
"--max-time",
|
||||
"5",
|
||||
downloadUrl,
|
||||
})
|
||||
|
||||
} else {
|
||||
sprintf := fmt.Sprintf("[BasicDownloadFile] - neither wget or curl exists ! can't download file [ %s ] from [ %s ]", desFile, downloadUrl)
|
||||
log.Error(sprintf)
|
||||
return false, []string{
|
||||
sprintf,
|
||||
}
|
||||
}
|
||||
|
||||
errLog := fmt.Sprintf("[BasicDownloadFile] - download file [ %s ] from [ %s ] failed !", desFile, downloadUrl)
|
||||
if !ok {
|
||||
log.Error(errLog)
|
||||
return false, []string{
|
||||
errLog,
|
||||
}
|
||||
}
|
||||
// check file exists
|
||||
existAndNotNull := BasicFileExistAndNotNull(desFile)
|
||||
if !existAndNotNull {
|
||||
return false, []string{
|
||||
errLog,
|
||||
"[BasicDownloadFile] - file not exist !",
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func BasicDownloadFileWithProxy(downloadUrl, proxyUrl, desFile string) (downloadOk bool, resultLog []string) {
|
||||
|
||||
var ok bool
|
||||
if !BasicCommandExistByPath("curl") {
|
||||
return false, []string{
|
||||
"curl not exits!",
|
||||
}
|
||||
}
|
||||
|
||||
ok, resultLog = AllCommandExecutor([]string{
|
||||
"curl",
|
||||
"-x",
|
||||
proxyUrl,
|
||||
"-o",
|
||||
desFile,
|
||||
"--insecure",
|
||||
"--max-time",
|
||||
"5",
|
||||
downloadUrl,
|
||||
})
|
||||
|
||||
errLog := fmt.Sprintf("[BasicDownloadFileWithProxy] - download file [ %s ] with proxy [ %s ] from [ %s ] failed !", desFile, proxyUrl, downloadUrl)
|
||||
if !ok {
|
||||
log.Error(errLog)
|
||||
return false, []string{
|
||||
errLog,
|
||||
}
|
||||
}
|
||||
// check file exists
|
||||
existAndNotNull := BasicFileExistAndNotNull(desFile)
|
||||
if !existAndNotNull {
|
||||
return false, []string{
|
||||
errLog,
|
||||
"[BasicDownloadFile] - file not exist !",
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// BasicAppendSourceToFile 将源文件的内容添加到目标文件,使用golang标准库完成,跨平台、安全性更强
|
||||
func BasicAppendSourceToFile(sourceFile, targetFile string) bool {
|
||||
|
||||
// 打开源文件
|
||||
source, err := os.Open(sourceFile)
|
||||
if err != nil {
|
||||
log.ErrorF("[BasicAppendSourceToFile] - error open source file => %s, error is %s", sourceFile, err.Error())
|
||||
return false
|
||||
}
|
||||
defer source.Close()
|
||||
|
||||
// 打开目标文件,如果不存在则创建,如果存在则在末尾追加
|
||||
target, err := os.OpenFile(targetFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
log.ErrorF("[BasicAppendSourceToFile] - error open target file => %s, error is %s", sourceFile, err.Error())
|
||||
return false
|
||||
}
|
||||
defer target.Close()
|
||||
|
||||
// 将源文件内容复制到目标文件
|
||||
_, err = io.Copy(target, source)
|
||||
if err != nil {
|
||||
log.ErrorF("[BasicAppendSourceToFile] - Error appending to target file: %s", err.Error())
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// BasicAppendContentToFile 向目标文件中追加写入一些内容
|
||||
func BasicAppendContentToFile(content string, targetFile string) bool {
|
||||
|
||||
// 打开文件用于追加。如果文件不存在,将会创建一个新文件。
|
||||
file, err := os.OpenFile(targetFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
log.ErrorF("[BasicAppendContentToFile] - Error opening file: %s , error is %s", targetFile, err.Error())
|
||||
return false
|
||||
}
|
||||
defer file.Close() // 确保文件最终被关闭
|
||||
|
||||
// 写入内容到文件
|
||||
if _, err := file.WriteString(content); err != nil {
|
||||
log.ErrorF("[BasicAppendContentToFile] - Error writing to file: %s , error is %s", targetFile, err.Error())
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// BasicAppendNullToFile 清空一个文件
|
||||
func BasicAppendNullToFile(targetFile string) bool {
|
||||
|
||||
// 使用os.O_TRUNC清空文件内容
|
||||
file, err := os.OpenFile(targetFile, os.O_TRUNC|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
log.ErrorF("[BasicAppendNullToFile] - Error opening file: %s, error is %s", targetFile, err.Error())
|
||||
return false
|
||||
}
|
||||
defer file.Close() // 确保在函数退出前关闭文件
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func BasicWordSpaceCompletion(source string, totalLength int) string {
|
||||
sourceLength := len(source)
|
||||
|
||||
if sourceLength >= totalLength {
|
||||
return source
|
||||
}
|
||||
|
||||
for i := 0; i < totalLength-sourceLength; i++ {
|
||||
source += " "
|
||||
}
|
||||
|
||||
return source
|
||||
}
|
||||
108
agent-go/a_executor/BasicFunction_test.go
Normal file
108
agent-go/a_executor/BasicFunction_test.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package a_executor
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
"wdd.io/agent-common/assert"
|
||||
)
|
||||
|
||||
var emptyFilePath = "/home/wdd/IdeaProjects/ProjectOctopus/agent-go/executor/script/123"
|
||||
var noExistFilePath = "/home/wdd/IdeaProjects/ProjectOctopus/agent-go/executor/script/456"
|
||||
|
||||
func TestBasicFileExistAndNotNull(t *testing.T) {
|
||||
|
||||
resultOK := BasicFileExistAndNotNull(emptyFilePath)
|
||||
|
||||
assert.Equal(t, resultOK, false, "判定为空文件返回false!")
|
||||
|
||||
}
|
||||
|
||||
func TestBasicReplaceFileNotExists(t *testing.T) {
|
||||
|
||||
replace := BasicReplace(noExistFilePath, "123", "123")
|
||||
|
||||
t.Logf("replace no exists file result are => %#v", replace)
|
||||
|
||||
}
|
||||
|
||||
func TestBasicFileExists(t *testing.T) {
|
||||
|
||||
exists := BasicFileExists(emptyFilePath)
|
||||
|
||||
assert.Equal(t, exists, true, "文件存在,但是为空,应该返回true!")
|
||||
}
|
||||
|
||||
func TestBasicFileExistFalse(t *testing.T) {
|
||||
|
||||
exists := BasicFileExists(noExistFilePath)
|
||||
|
||||
assert.Equal(t, exists, false, "文件不存在,应该返回false!")
|
||||
}
|
||||
|
||||
func TestBasicSystemdShutdown(t *testing.T) {
|
||||
|
||||
ok, resultLog := BasicSystemdShutdown("docker.service")
|
||||
//ok, resultLog := BasicSystemdShutdown("docker")
|
||||
//ok, resultLog := BasicSystemdShutdown("fwd")
|
||||
|
||||
t.Logf("result ok is %v resultLog is %v", ok, resultLog)
|
||||
|
||||
}
|
||||
|
||||
func TestBasicSystemdUp(t *testing.T) {
|
||||
|
||||
//ok, resultLog := BasicSystemdUp("docker.service")
|
||||
//ok, resultLog := BasicSystemdUp("docker")
|
||||
ok, resultLog := BasicSystemdUp("fwd")
|
||||
|
||||
t.Logf("result ok is %v resultLog is %v", ok, resultLog)
|
||||
|
||||
}
|
||||
|
||||
func TestBasicCommandExists(t *testing.T) {
|
||||
|
||||
exists := BasicCommandExists("docker-compose")
|
||||
|
||||
t.Logf("command exists is => %s", strconv.FormatBool(exists))
|
||||
|
||||
}
|
||||
|
||||
func TestBasicDockerImageExistByFullName(t *testing.T) {
|
||||
|
||||
// Test cases
|
||||
testCases := []struct {
|
||||
name string
|
||||
imageFullName string
|
||||
expectedResult bool
|
||||
}{
|
||||
{
|
||||
name: "Image exists with full name and version",
|
||||
imageFullName: "harbor.cdcyy.com.cn/cmii/busybox:0326",
|
||||
expectedResult: true,
|
||||
},
|
||||
{
|
||||
name: "Image does not exist with full name and version",
|
||||
imageFullName: "nonexistentImage:latest",
|
||||
expectedResult: false,
|
||||
},
|
||||
{
|
||||
name: "Image exists with full name but no version",
|
||||
imageFullName: "harbor.cdcyy.com.cn/cmii/busybox",
|
||||
expectedResult: true,
|
||||
},
|
||||
{
|
||||
name: "Image does not exist with full name but no version",
|
||||
imageFullName: "nonexistentImage",
|
||||
expectedResult: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
result := BasicDockerImageExistByFullName(tc.imageFullName)
|
||||
if result != tc.expectedResult {
|
||||
t.Errorf("Expected %t for imageFullName %s, but got %t", tc.expectedResult, tc.imageFullName, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
213
agent-go/a_executor/CommandExecutor.go
Normal file
213
agent-go/a_executor/CommandExecutor.go
Normal file
@@ -0,0 +1,213 @@
|
||||
package a_executor
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"wdd.io/agent-common/logger"
|
||||
)
|
||||
|
||||
type ExecutionMessage struct {
|
||||
NeedResultReplay bool `json:"needResultReplay"`
|
||||
DurationTask bool `json:"durationTask,default:false"`
|
||||
ExecutionType string `json:"executionType"`
|
||||
FuncContent []string `json:"funcContent"`
|
||||
SingleLineCommand []string `json:"singleLineCommand"`
|
||||
MultiLineCommand [][]string `json:"multiLineCommand"`
|
||||
PipeLineCommand [][]string `json:"pipeLineCommand"`
|
||||
ResultKey string `json:"resultKey"`
|
||||
}
|
||||
|
||||
var log = logger.Log
|
||||
|
||||
var AgentOsOperatorCache = &AgentOsOperator{}
|
||||
|
||||
func Activate() {
|
||||
log.Info("Module [ EXECUTOR ] activated !")
|
||||
|
||||
//// 转换类型
|
||||
//executionMsgString := octopusMessage.Content.(string)
|
||||
//
|
||||
//// 解析 ExecutionMessage
|
||||
//var executionMessage *a_executor.ExecutionMessage
|
||||
//err := json.Unmarshal([]byte(executionMsgString), &executionMessage)
|
||||
//if err != nil {
|
||||
// log.Error(fmt.Sprintf("execution message convert to json is wrong! msg is => %s", executionMsgString))
|
||||
// return
|
||||
//}
|
||||
//
|
||||
//// 执行命令
|
||||
//ok, resultLog := a_executor.Execute(executionMessage)
|
||||
//if ok {
|
||||
// octopusMessage.ResultCode = "200"
|
||||
//} else {
|
||||
// octopusMessage.ResultCode = "300"
|
||||
//}
|
||||
//
|
||||
//// 返回结果
|
||||
//if executionMessage.NeedResultReplay {
|
||||
// // send back the result log
|
||||
// octopusMessage.Result = resultLog
|
||||
//}
|
||||
//// 返回时间
|
||||
//octopusMessage.ACTime = utils.ParseDateTimeTime()
|
||||
//
|
||||
//// 返回结果
|
||||
//octopusMessage.SendToOctopusServer()
|
||||
}
|
||||
|
||||
func Execute(em *ExecutionMessage) (bool, []string) {
|
||||
|
||||
var resultLog []string
|
||||
var err error
|
||||
ok := true
|
||||
executionContent := em.ExecutionType + " == " + strings.Join(em.FuncContent, " - ")
|
||||
|
||||
log.DebugF("em message is => %#v", em)
|
||||
|
||||
if strings.HasPrefix(em.ExecutionType, "BASE") {
|
||||
// base function
|
||||
if len(em.FuncContent) > 1 {
|
||||
ok, resultLog = AgentOsOperatorCache.Exec(em.FuncContent[0], em.FuncContent[1:]...)
|
||||
} else {
|
||||
ok, resultLog = AgentOsOperatorCache.Exec(em.FuncContent[0])
|
||||
}
|
||||
|
||||
} else if strings.HasPrefix(em.ExecutionType, "APP") {
|
||||
// app function
|
||||
if len(em.FuncContent) > 1 {
|
||||
ok, resultLog = AgentOsOperatorCache.Deploy(em.FuncContent[0], em.FuncContent[1:]...)
|
||||
} else {
|
||||
ok, resultLog = AgentOsOperatorCache.Deploy(em.FuncContent[0])
|
||||
}
|
||||
|
||||
} else if strings.HasPrefix(em.ExecutionType, "HARBOR") {
|
||||
// harbor function
|
||||
if em.FuncContent == nil || len(em.FuncContent) <= 1 {
|
||||
ok = false
|
||||
resultLog = []string{
|
||||
"[Harbor Execute] - functions args is wrong!",
|
||||
}
|
||||
}
|
||||
// Harbor Execute
|
||||
ok, resultLog = HarborOperatorCache.Exec(em.FuncContent[0], em.FuncContent[1:]...)
|
||||
|
||||
} else if strings.HasPrefix(em.ExecutionType, "IMAGE") {
|
||||
// image function
|
||||
if em.FuncContent == nil || len(em.FuncContent) <= 1 {
|
||||
ok = false
|
||||
resultLog = []string{
|
||||
"[Harbor Execute] - functions args is wrong!",
|
||||
}
|
||||
}
|
||||
// Harbor Execute
|
||||
ok, resultLog = AgentOsOperatorCache.Sync(em.FuncContent[0], em.FuncContent[1:]...)
|
||||
} else {
|
||||
// deprecated
|
||||
// shell command
|
||||
if em.PipeLineCommand != nil && len(em.PipeLineCommand) != 0 {
|
||||
// 管道命令
|
||||
resultLog, err = PipeLineCommandExecutor(em.PipeLineCommand)
|
||||
executionContent = fmt.Sprintf("%v", em.PipeLineCommand)
|
||||
} else if em.MultiLineCommand != nil && len(em.MultiLineCommand) != 0 {
|
||||
// 多行命令
|
||||
resultLog, err = MultiLineCommandExecutor(em.MultiLineCommand)
|
||||
executionContent = fmt.Sprintf("%v", em.MultiLineCommand)
|
||||
} else {
|
||||
// 单行命令
|
||||
resultLog, err = FormatAllCommandExecutor(em.SingleLineCommand)
|
||||
executionContent = fmt.Sprintf("%v", em.SingleLineCommand)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 归一化错误和日志
|
||||
if err != nil {
|
||||
resultLog = append(resultLog, " 命令执行错误如下 ", err.Error())
|
||||
}
|
||||
resultLog = append(resultLog, fmt.Sprintf("命令 %v 执行结果为 %s", executionContent, strconv.FormatBool(ok)))
|
||||
// debug
|
||||
log.DebugF("%v", resultLog)
|
||||
|
||||
return ok, resultLog
|
||||
}
|
||||
|
||||
func PipeLineCommandExecutor(pipeLineCommand [][]string) ([]string, error) {
|
||||
|
||||
var resultSlice []string
|
||||
var output []byte
|
||||
var err error
|
||||
|
||||
tmp := make([]string, len(pipeLineCommand))
|
||||
for index, pipe := range pipeLineCommand {
|
||||
tmp[index] = strings.Join(pipe, " ")
|
||||
}
|
||||
pipelineCommandString := strings.Join(tmp, " | ")
|
||||
|
||||
resultSlice = append(resultSlice, fmt.Sprintf(" ========= 命令为 ====> %s", pipelineCommandString))
|
||||
|
||||
for _, pipeCommand := range pipeLineCommand {
|
||||
if len(pipeCommand) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
command := exec.Command(pipeCommand[0], pipeCommand[1:]...)
|
||||
if len(output) > 0 {
|
||||
command.Stdin = bytes.NewBuffer(output)
|
||||
}
|
||||
|
||||
output, err = command.CombinedOutput()
|
||||
if err != nil {
|
||||
log.ErrorF("Pipeline Command Command Error => %v", err.Error())
|
||||
|
||||
// 收集错误的信息
|
||||
resultSlice = append(resultSlice, "↓↓↓ 命令 错误 如下 ↓↓↓", string(output))
|
||||
return resultSlice, err
|
||||
}
|
||||
}
|
||||
|
||||
// 正常的输出
|
||||
resultSlice = append(resultSlice, "↓↓↓ 命令 输出 如下 ↓↓↓", string(output))
|
||||
return resultSlice, err
|
||||
}
|
||||
|
||||
func MultiLineCommandExecutor(multiLineCommandExecutor [][]string) ([]string, error) {
|
||||
|
||||
var res []string
|
||||
for _, singleLineCommand := range multiLineCommandExecutor {
|
||||
singleLogs, err := FormatAllCommandExecutor(singleLineCommand)
|
||||
res = append(res, singleLogs...)
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("Execution error ! command is %v, error is %v", singleLineCommand, err))
|
||||
return res, err
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// SingleLineCommandExecutor 执行单行命令
|
||||
func SingleLineCommandExecutor(singleLineCommand []string) ([]string, error) {
|
||||
|
||||
cmd := exec.Command(singleLineCommand[0], singleLineCommand[1:]...)
|
||||
var out bytes.Buffer
|
||||
cmd.Stdout = &out
|
||||
cmd.Stderr = &out
|
||||
|
||||
err := cmd.Run()
|
||||
|
||||
scanner := bufio.NewScanner(&out)
|
||||
var result []string
|
||||
for scanner.Scan() {
|
||||
result = append(result, scanner.Text())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
270
agent-go/a_executor/FunctionalExecutor.go
Normal file
270
agent-go/a_executor/FunctionalExecutor.go
Normal file
@@ -0,0 +1,270 @@
|
||||
package a_executor
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// AllCommandExecutor 正确或者错误的信息全部收集,共同返回
|
||||
func AllCommandExecutor(singleLineCommand []string) (resultOk bool, resultLog []string) {
|
||||
// result
|
||||
var resultSlice []string
|
||||
resultOk = true
|
||||
|
||||
cmd := exec.Command(singleLineCommand[0], singleLineCommand[1:]...)
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
log.DebugF("command %v stdout error => %v", singleLineCommand, err)
|
||||
resultOk = false
|
||||
}
|
||||
stderr, err := cmd.StderrPipe()
|
||||
if err != nil {
|
||||
log.DebugF("command %v stderr error => %v", singleLineCommand, err)
|
||||
resultOk = false
|
||||
}
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
log.DebugF("command %v runtime error => %v", singleLineCommand, err)
|
||||
resultOk = false
|
||||
}
|
||||
|
||||
// 收集错误或者
|
||||
resultSlice = collectOutput(stdout, resultSlice)
|
||||
resultSlice = collectOutput(stderr, resultSlice)
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
log.DebugF("command %v result error => %v", singleLineCommand, err)
|
||||
resultOk = false
|
||||
}
|
||||
|
||||
log.DebugF("all command of %v result are => %v", singleLineCommand, resultSlice)
|
||||
|
||||
return resultOk, resultSlice
|
||||
}
|
||||
|
||||
// AllCompleteExecutor 多行命令的执行函数,返回执行正确与否和执行结果
|
||||
func AllCompleteExecutor(multiCommand [][]string) (resultOk bool, resultLog []string) {
|
||||
|
||||
var result []string
|
||||
resultOk = true
|
||||
|
||||
for _, singleLineCommand := range multiCommand {
|
||||
ok, resultLog := AllCommandExecutor(singleLineCommand)
|
||||
if !ok {
|
||||
// 执行出错
|
||||
resultOk = false
|
||||
}
|
||||
result = append(result, resultLog...)
|
||||
}
|
||||
|
||||
return resultOk, result
|
||||
}
|
||||
|
||||
// FormatAllCommandExecutor 收集全部执行结果、错误并且返回
|
||||
func FormatAllCommandExecutor(singleLineCommand []string) ([]string, error) {
|
||||
|
||||
// result
|
||||
var resultSlice []string
|
||||
var resultError error
|
||||
var cmd *exec.Cmd
|
||||
|
||||
if len(singleLineCommand) > 1 {
|
||||
cmd = exec.Command(singleLineCommand[0], singleLineCommand[1:]...)
|
||||
} else {
|
||||
cmd = exec.Command(singleLineCommand[0])
|
||||
}
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
log.ErrorF("command %v stdout error => %v", singleLineCommand, err)
|
||||
resultError = err
|
||||
}
|
||||
stderr, err := cmd.StderrPipe()
|
||||
if err != nil {
|
||||
log.ErrorF("command %v stderr error => %v", singleLineCommand, err)
|
||||
resultError = err
|
||||
}
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
log.ErrorF("command %v runtime error => %v", singleLineCommand, err)
|
||||
}
|
||||
|
||||
resultSlice = append(resultSlice, fmt.Sprintf(" 开始执行命令 ====> %s", singleLineCommand), "↓↓↓ 命令 输出 如下 ↓↓↓")
|
||||
resultSlice = collectOutput(stdout, resultSlice)
|
||||
resultSlice = append(resultSlice, "↓↓↓ 命令 错误 如下 ↓↓↓")
|
||||
resultSlice = collectOutput(stderr, resultSlice)
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
log.ErrorF("command %v result error => %v", singleLineCommand, err)
|
||||
resultError = err
|
||||
}
|
||||
|
||||
log.DebugF("real time exec result are %v", resultSlice)
|
||||
|
||||
return resultSlice, resultError
|
||||
}
|
||||
|
||||
func PipelineCommandExecutor(pipelineCommand [][]string) (resultOk bool, resultLog []string) {
|
||||
if len(pipelineCommand) == 0 {
|
||||
return true, nil
|
||||
} else if len(pipelineCommand) == 1 {
|
||||
log.Debug("输入的PipelineCommand长度有误!")
|
||||
return AllCommandExecutor(pipelineCommand[0])
|
||||
}
|
||||
|
||||
var c []string
|
||||
cmd1 := exec.Command(pipelineCommand[0][0], pipelineCommand[0][1:]...)
|
||||
var outputBuf1 bytes.Buffer
|
||||
cmd1.Stdout = &outputBuf1
|
||||
if err := cmd1.Start(); err != nil {
|
||||
sprintf := fmt.Sprintf("Error: The first command can not be startup %s", err)
|
||||
return false, append(c, sprintf)
|
||||
}
|
||||
if err := cmd1.Wait(); err != nil {
|
||||
sprintf := fmt.Sprintf("Error: Couldn't wait for the first command: %s", err)
|
||||
return false, append(c, sprintf)
|
||||
}
|
||||
|
||||
for i := 1; i < len(pipelineCommand); i++ {
|
||||
|
||||
cmd2 := exec.Command(pipelineCommand[i][0], pipelineCommand[i][1:]...)
|
||||
sprintf := fmt.Sprintf("current command is %s", pipelineCommand[i])
|
||||
c = append(c, sprintf)
|
||||
|
||||
cmd2.Stdin = &outputBuf1
|
||||
var outputBuf2 bytes.Buffer
|
||||
cmd2.Stdout = &outputBuf2
|
||||
if err := cmd2.Start(); err != nil {
|
||||
sprintf := fmt.Sprintf("Error: The second command can not be startup: %s", err)
|
||||
return false, append(c, sprintf)
|
||||
}
|
||||
if err := cmd2.Wait(); err != nil {
|
||||
sprintf := fmt.Sprintf("Error: Couldn't wait for the second command: %s", err)
|
||||
return false, append(c, sprintf)
|
||||
}
|
||||
|
||||
// change
|
||||
outputBuf1 = outputBuf2
|
||||
}
|
||||
|
||||
s := outputBuf1.String()
|
||||
split := strings.Split(s, "\n")
|
||||
|
||||
return true, split
|
||||
}
|
||||
|
||||
// PureResultSingleExecute 执行单行命令,忽略输出,只对执行成功与否负责
|
||||
func PureResultSingleExecute(singleCommand []string) (resultOK bool) {
|
||||
|
||||
cmd := exec.Command(singleCommand[0], singleCommand[1:]...)
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
log.ErrorF("指令 %s 执行 错误, 错误内容为 %s", singleCommand, err.Error())
|
||||
return false
|
||||
} else {
|
||||
log.DebugF("指令 %s 执行 成功", singleCommand)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// PureResultSingleExecuteBatch 批量 执行单行命令,忽略输出,只对执行成功与否负责
|
||||
func PureResultSingleExecuteBatch(singleCommandList [][]string) (resultOK bool) {
|
||||
|
||||
result := true
|
||||
|
||||
for _, singleCommand := range singleCommandList {
|
||||
if !PureResultSingleExecute(singleCommand) {
|
||||
result = false
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// ReadTimeCommandExecutor 执行命令,并且实时返回结果
|
||||
func ReadTimeCommandExecutor(singleLineCommand []string) bool {
|
||||
cmd := exec.Command(singleLineCommand[0], singleLineCommand[1:]...)
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
log.ErrorF("command %v stdout error => %v", singleLineCommand, err)
|
||||
}
|
||||
stderr, err := cmd.StderrPipe()
|
||||
if err != nil {
|
||||
log.ErrorF("command %v stderr error => %v", singleLineCommand, err)
|
||||
}
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
log.ErrorF("command %v runtime error => %v", singleLineCommand, err)
|
||||
}
|
||||
|
||||
go realTimeOutput(stdout)
|
||||
go realTimeOutput(stderr)
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
log.ErrorF("command %v result error => %v", singleLineCommand, err)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func realTimeOutput(r io.Reader) {
|
||||
scanner := bufio.NewScanner(r)
|
||||
for scanner.Scan() {
|
||||
fmt.Println(scanner.Text())
|
||||
}
|
||||
}
|
||||
|
||||
func collectOutput(r io.Reader, resultSlice []string) []string {
|
||||
scanner := bufio.NewScanner(r)
|
||||
for scanner.Scan() {
|
||||
resultLine := scanner.Text()
|
||||
|
||||
resultSlice = append(resultSlice, resultLine)
|
||||
// debug usage
|
||||
//fmt.Println(resultLine)
|
||||
}
|
||||
|
||||
return resultSlice
|
||||
}
|
||||
|
||||
// HardCodeCommandExecutor 执行硬编码的shell命令,如 echo sda > sdasd ; rpcinfo -p localhost 等
|
||||
func HardCodeCommandExecutor(hardCodeCommand string) (ok bool, resultLog []string) {
|
||||
|
||||
// result
|
||||
var resultSlice []string
|
||||
resultOk := true
|
||||
|
||||
cmd := exec.Command("sh", "-c", hardCodeCommand)
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
log.DebugF("hard code command %v stdout error => %s", hardCodeCommand, err)
|
||||
resultOk = false
|
||||
}
|
||||
stderr, err := cmd.StderrPipe()
|
||||
if err != nil {
|
||||
log.DebugF("hard code command %v stderr error => %s", hardCodeCommand, err)
|
||||
resultOk = false
|
||||
}
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
log.DebugF("hard code command %v runtime error => %v", hardCodeCommand, err)
|
||||
resultOk = false
|
||||
}
|
||||
|
||||
// 收集错误或者
|
||||
resultSlice = collectOutput(stdout, resultSlice)
|
||||
resultSlice = collectOutput(stderr, resultSlice)
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
log.DebugF("hard code command %v result error => %v", hardCodeCommand, err)
|
||||
resultOk = false
|
||||
}
|
||||
|
||||
//log.DebugF("hard code command of [ %s ] result are => %v", hardCodeCommand, resultSlice)
|
||||
|
||||
return resultOk, resultSlice
|
||||
}
|
||||
224
agent-go/a_executor/FunctionalExecutor_test.go
Normal file
224
agent-go/a_executor/FunctionalExecutor_test.go
Normal file
@@ -0,0 +1,224 @@
|
||||
package a_executor
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var closeSELinux = []string{
|
||||
"sed",
|
||||
"-i",
|
||||
"s/SELINUX=enforcing/SELINUX=disabled/g",
|
||||
"/etc/selinux/config",
|
||||
}
|
||||
|
||||
var callShellScript = []string{
|
||||
"/bin/bash",
|
||||
"/root/IdeaProjects/ProjectOctopus/agent-go/tmp/simple.sh",
|
||||
}
|
||||
|
||||
var shutdownFirewalld = []string{
|
||||
// wrong usage of &&
|
||||
"systemctl", "stop", "firewalld", "&&", "systemctl", "disable", "firewalld",
|
||||
}
|
||||
|
||||
var wgetCommand = []string{
|
||||
"wget",
|
||||
"--timeout=10",
|
||||
"https://oss-s1.107421.xyz/octopus_ssh_banner",
|
||||
"-O",
|
||||
"/home/wdd/IdeaProjects/ProjectOctopus/agent-go/executor/script/123",
|
||||
}
|
||||
|
||||
var echoPathCommand = []string{
|
||||
"echo",
|
||||
"$PATH",
|
||||
}
|
||||
|
||||
var pipelineCommandFalse = []string{
|
||||
"ls",
|
||||
"/etc",
|
||||
"|",
|
||||
"grep",
|
||||
"passwd",
|
||||
}
|
||||
|
||||
var pipelineCommand = [][]string{
|
||||
{
|
||||
"cat",
|
||||
"/home/wdd/IdeaProjects/ProjectOctopus/agent-go/executor/script/123",
|
||||
},
|
||||
{
|
||||
"grep",
|
||||
"passwd",
|
||||
},
|
||||
}
|
||||
|
||||
var pipelineCommandMore = "apt-cache madison docker-ce | awk {print$3} | cut -d: -f2"
|
||||
var pipelineCommandSecond = "systemctl status -q docker.service | grep found."
|
||||
var pipelineCommandThird = "ls /etc/ | grep passwd | head -2"
|
||||
var pipelineCommandFourth = "echo dsadsad | tee /home/wdd/IdeaProjects/ProjectOctopus/agent-go/executor/script/123"
|
||||
|
||||
var ifconfigCommand = []string{"ifconfig"}
|
||||
|
||||
func TestReadTimeOutput(t *testing.T) {
|
||||
|
||||
ReadTimeCommandExecutor(ifconfigCommand)
|
||||
|
||||
}
|
||||
|
||||
func TestAllCommandExecutor(t *testing.T) {
|
||||
ok, result := AllCommandExecutor(echoPathCommand)
|
||||
|
||||
t.Logf("执行结果为 => %#v", ok)
|
||||
t.Logf("执行日志为 => %#v", result)
|
||||
|
||||
}
|
||||
|
||||
func TestPureResultSingleExecute(t *testing.T) {
|
||||
|
||||
PureResultSingleExecute(closeSELinux)
|
||||
|
||||
}
|
||||
|
||||
func TestPipelineCommandExecutorSingle(t *testing.T) {
|
||||
|
||||
cmd1 := exec.Command("ls", "/etc/")
|
||||
cmd2 := exec.Command("grep", "passwd")
|
||||
|
||||
var outputBuf1 bytes.Buffer
|
||||
cmd1.Stdout = &outputBuf1
|
||||
if err := cmd1.Start(); err != nil {
|
||||
fmt.Printf("Error: The first command can not be startup %s\n", err)
|
||||
return
|
||||
}
|
||||
if err := cmd1.Wait(); err != nil {
|
||||
fmt.Printf("Error: Couldn't wait for the first command: %s\n", err)
|
||||
return
|
||||
}
|
||||
cmd2.Stdin = &outputBuf1
|
||||
var outputBuf2 bytes.Buffer
|
||||
cmd2.Stdout = &outputBuf2
|
||||
if err := cmd2.Start(); err != nil {
|
||||
fmt.Printf("Error: The second command can not be startup: %s\n", err)
|
||||
return
|
||||
}
|
||||
if err := cmd2.Wait(); err != nil {
|
||||
fmt.Printf("Error: Couldn't wait for the second command: %s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
s := outputBuf2.String()
|
||||
split := strings.Split(s, "\n")
|
||||
|
||||
BasicPrettyPrint(true, split)
|
||||
|
||||
}
|
||||
|
||||
func TestPipelineCommandExecutor(t *testing.T) {
|
||||
|
||||
//PipelineCommandExecutor(pipelineCommand)
|
||||
pipelineStringToCommand := BasicTransPipelineCommand(pipelineCommandSecond)
|
||||
|
||||
t.Logf("pipelineCommmand are => %#v", pipelineStringToCommand)
|
||||
|
||||
ok, resultLog := PipelineCommandExecutor(pipelineStringToCommand)
|
||||
|
||||
t.Logf("command execute ok is => %#v", ok)
|
||||
t.Logf("command result are 下 \n")
|
||||
BasicPrettyPrint(ok, resultLog)
|
||||
}
|
||||
|
||||
func TestPipelineCommandExecutor2(t *testing.T) {
|
||||
// Test case 1: Empty pipeline
|
||||
pipelineCommand := [][]string{}
|
||||
ok, log := PipelineCommandExecutor(pipelineCommand)
|
||||
if !ok {
|
||||
t.Errorf("Expected success, got failure")
|
||||
}
|
||||
if len(log) != 0 {
|
||||
t.Errorf("Expected no log, got %v", log)
|
||||
}
|
||||
|
||||
// Test case 2: Single command in pipeline
|
||||
pipelineCommand = [][]string{
|
||||
{"echo", "Hello, world!"},
|
||||
}
|
||||
ok, log = PipelineCommandExecutor(pipelineCommand)
|
||||
if !ok {
|
||||
t.Errorf("Expected success, got failure")
|
||||
}
|
||||
expectedLog := []string{"Hello, world!"}
|
||||
if !reflect.DeepEqual(log, expectedLog) {
|
||||
t.Errorf("Expected log %v, got %v", expectedLog, log)
|
||||
}
|
||||
|
||||
// Test case 3: Multiple commands in pipeline
|
||||
pipelineCommand = [][]string{
|
||||
{"echo", "Hello"},
|
||||
{"echo", "world!"},
|
||||
}
|
||||
ok, log = PipelineCommandExecutor(pipelineCommand)
|
||||
if !ok {
|
||||
t.Errorf("Expected success, got failure")
|
||||
}
|
||||
expectedLog = []string{"Hello", "world!"}
|
||||
if !reflect.DeepEqual(log, expectedLog) {
|
||||
t.Errorf("Expected log %v, got %v", expectedLog, log)
|
||||
}
|
||||
|
||||
// Add more test cases as needed...
|
||||
}
|
||||
|
||||
func TestSimple(t *testing.T) {
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
var output bytes.Buffer
|
||||
|
||||
fmt.Printf("output address is => %p \n", &output)
|
||||
|
||||
}
|
||||
fmt.Println()
|
||||
var output bytes.Buffer
|
||||
fmt.Printf("out is => %#v\n", output)
|
||||
|
||||
command := exec.Command("ls")
|
||||
command.StdoutPipe()
|
||||
|
||||
}
|
||||
|
||||
func TestFileBasedPipe(t *testing.T) {
|
||||
reader, writer, err := os.Pipe()
|
||||
if err != nil {
|
||||
fmt.Printf("Error: Couldn't create the named pipe: %s\n", err)
|
||||
}
|
||||
go func() {
|
||||
|
||||
output := make([]byte, 100)
|
||||
n, err := reader.Read(output)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: Couldn't read data from the named pipe: %s\n", err)
|
||||
}
|
||||
fmt.Printf("Read %d byte(s). [file-based pipe]\n", n)
|
||||
|
||||
fmt.Printf("Read content are => %s\n", string(output))
|
||||
|
||||
}()
|
||||
|
||||
input := make([]byte, 26)
|
||||
for i := 65; i <= 90; i++ {
|
||||
input[i-65] = byte(i)
|
||||
}
|
||||
n, err := writer.Write(input)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: Couldn't write data to the named pipe: %s\n", err)
|
||||
}
|
||||
fmt.Printf("Written %d byte(s). [file-based pipe]\n", n)
|
||||
//time.Sleep(200 * time.Millisecond)
|
||||
|
||||
}
|
||||
420
agent-go/a_executor/HarborExecutor.go
Normal file
420
agent-go/a_executor/HarborExecutor.go
Normal file
@@ -0,0 +1,420 @@
|
||||
package a_executor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/mittwald/goharbor-client/v5/apiv2"
|
||||
"github.com/mittwald/goharbor-client/v5/apiv2/model"
|
||||
)
|
||||
|
||||
type HarborOperator struct {
|
||||
SourceHarborHost string `json:"sourceHarborHost,omitempty"`
|
||||
|
||||
TargetHarborHost string `json:"targetHarborHost,omitempty"`
|
||||
|
||||
HarborPort string `json:"harborPort,omitempty"`
|
||||
|
||||
HarborAdminUser string `json:"harborAdminUser,omitempty"`
|
||||
|
||||
HarborAdminPass string `json:"harborAdminPass,omitempty"`
|
||||
|
||||
TargetHarborClient *apiv2.RESTClient
|
||||
|
||||
SourceHarborClient *apiv2.RESTClient
|
||||
}
|
||||
|
||||
// NewHarborOperator 返回一个带有默认HarborAdminPass的HarborOperator实例
|
||||
func NewHarborOperator() *HarborOperator {
|
||||
return &HarborOperator{
|
||||
HarborPort: "8033",
|
||||
HarborAdminUser: "admin", // 设置默认值
|
||||
HarborAdminPass: "V2ryStr@ngPss", // 设置默认值
|
||||
}
|
||||
}
|
||||
|
||||
// HarborOperatorCache 饿汉式单例
|
||||
var HarborOperatorCache = NewHarborOperator()
|
||||
var OctopusReplicationPolicyName = "octopus-sync-replication"
|
||||
|
||||
func (hOp *HarborOperator) Exec(baseFuncName string, funcArgs ...string) (bool, []string) {
|
||||
// 参见 HarborFunctionEnum
|
||||
|
||||
resultOk := true
|
||||
var resultLog []string
|
||||
|
||||
switch baseFuncName {
|
||||
case "CREATE_PROJECT":
|
||||
resultOk, resultLog = hOp.CreateProjectExec(funcArgs)
|
||||
break
|
||||
case "LIST_PROJECT":
|
||||
resultOk, resultLog = hOp.ListProjectExec(funcArgs)
|
||||
break
|
||||
case "SYNC_PROJECT_BETWEEN_HARBOR":
|
||||
resultOk, resultLog = hOp.SyncProjectExec(funcArgs)
|
||||
break
|
||||
case "SYNC_STATUS_HARBOR":
|
||||
resultOk, resultLog = hOp.SyncStatusExec(funcArgs)
|
||||
break
|
||||
}
|
||||
|
||||
return resultOk, resultLog
|
||||
}
|
||||
|
||||
func (hOp *HarborOperator) CreateProjectExec(funcArgs []string) (bool, []string) {
|
||||
|
||||
if hOp.TargetHarborClient == nil {
|
||||
|
||||
ok, createClient := hOp.CheckAndBuildHarborClient(funcArgs[0], "", true)
|
||||
if !ok {
|
||||
return false, []string{
|
||||
"[Harbor Create Project] - Error !",
|
||||
}
|
||||
}
|
||||
hOp.TargetHarborClient = createClient
|
||||
}
|
||||
client := hOp.TargetHarborClient
|
||||
|
||||
// create project
|
||||
// 定义你想要创建的仓库(项目)的详细信息
|
||||
|
||||
log.Debug("[Harbor Create Project] - create project !")
|
||||
needToCreateProjectNameList := []string{"cmii", "rancher"}
|
||||
// 使用客户端创建项目
|
||||
ctx := context.Background()
|
||||
for _, projectName := range needToCreateProjectNameList {
|
||||
|
||||
log.DebugF("start to create proect => %s", projectName)
|
||||
projectReq := &model.ProjectReq{
|
||||
ProjectName: projectName, // 仓库名称
|
||||
Metadata: &model.ProjectMetadata{
|
||||
Public: "true", // 是否是公开的
|
||||
},
|
||||
}
|
||||
|
||||
exists, _ := client.ProjectExists(ctx, projectName)
|
||||
if !exists {
|
||||
|
||||
err := client.NewProject(ctx, projectReq)
|
||||
if err != nil {
|
||||
errorLog := fmt.Sprintf("Error creating project %s: %s\n", projectName, err.Error())
|
||||
return false, []string{errorLog}
|
||||
}
|
||||
}
|
||||
|
||||
log.DebugF("[Harbor Create Project] - Project %s already exists ! continue ", projectName)
|
||||
|
||||
}
|
||||
|
||||
successLog := "[Harbor CreateProjectExec] - Project Create Success !"
|
||||
log.Info(successLog)
|
||||
|
||||
return true, []string{successLog}
|
||||
}
|
||||
|
||||
func (hOp *HarborOperator) CheckAndBuildHarborClient(targetHarborHost string, targetHarborPort string, isTarget bool) (bool, *apiv2.RESTClient) {
|
||||
|
||||
log.InfoF("[Harbor Client Create] - start to create harbor client %s", targetHarborHost)
|
||||
|
||||
parseIP := net.ParseIP(targetHarborHost)
|
||||
if parseIP == nil {
|
||||
log.Error(
|
||||
fmt.Sprintf("[Harbor Client Create] - ip format is wrong! parseIP is => %s ", parseIP),
|
||||
)
|
||||
return false, nil
|
||||
}
|
||||
if targetHarborPort == "" {
|
||||
targetHarborPort = hOp.HarborPort
|
||||
}
|
||||
|
||||
if isTarget {
|
||||
hOp.TargetHarborHost = "http://" + targetHarborHost + ":" + targetHarborPort + "/api/"
|
||||
log.DebugF("[Harbor Client Create] - harbor host is => %s", hOp.TargetHarborHost)
|
||||
} else {
|
||||
hOp.SourceHarborHost = "http://" + targetHarborHost + ":" + targetHarborPort + "/api/"
|
||||
log.DebugF("[Harbor Client Create] - harbor host is => %s", hOp.SourceHarborHost)
|
||||
}
|
||||
|
||||
// check connection
|
||||
var client *apiv2.RESTClient
|
||||
var err error
|
||||
if isTarget {
|
||||
client, err = apiv2.NewRESTClientForHost(hOp.TargetHarborHost, hOp.HarborAdminUser, hOp.HarborAdminPass, nil)
|
||||
} else {
|
||||
client, err = apiv2.NewRESTClientForHost(hOp.SourceHarborHost, hOp.HarborAdminUser, hOp.HarborAdminPass, nil)
|
||||
}
|
||||
if err != nil {
|
||||
errorLog := fmt.Sprintf("Error creating REST client: %s\n", err.Error())
|
||||
log.Error(errorLog)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, client
|
||||
}
|
||||
|
||||
func (hOp *HarborOperator) ListProjectExec(funcArgs []string) (bool, []string) {
|
||||
|
||||
if hOp.TargetHarborClient == nil {
|
||||
ok, createClient := hOp.CheckAndBuildHarborClient(funcArgs[0], "", true)
|
||||
if !ok {
|
||||
return false, []string{
|
||||
"[Harbor Create Project ] - Error !",
|
||||
}
|
||||
}
|
||||
hOp.TargetHarborClient = createClient
|
||||
}
|
||||
client := hOp.TargetHarborClient
|
||||
|
||||
// 使用客户端列出所有项目
|
||||
ctx := context.Background()
|
||||
projects, err := client.ListProjects(ctx, "")
|
||||
if err != nil {
|
||||
fmt.Printf("Error listing projects: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// 打印所有项目的信息
|
||||
for _, project := range projects {
|
||||
fmt.Printf("Project ID: %d, Name: %s, Public: %v\n", project.ProjectID, project.Name, project.Metadata.Public)
|
||||
}
|
||||
|
||||
marshal, _ := json.Marshal(projects)
|
||||
|
||||
return true, []string{
|
||||
fmt.Sprintf("List Projects of %s ", hOp.TargetHarborHost),
|
||||
string(marshal),
|
||||
}
|
||||
}
|
||||
|
||||
func (hOp *HarborOperator) SyncProjectExec(funcArgs []string) (bool, []string) {
|
||||
|
||||
if hOp.TargetHarborClient == nil {
|
||||
ok, createClient := hOp.CheckAndBuildHarborClient(funcArgs[0], "", true)
|
||||
if !ok {
|
||||
return false, []string{
|
||||
"[Harbor Sync Project ] - Error !",
|
||||
}
|
||||
}
|
||||
hOp.TargetHarborClient = createClient
|
||||
}
|
||||
targetClient := hOp.TargetHarborClient
|
||||
|
||||
if hOp.SourceHarborClient == nil {
|
||||
realHost := funcArgs[1]
|
||||
realPort := ""
|
||||
if strings.Contains(funcArgs[1], ":") {
|
||||
split := strings.Split(funcArgs[1], ":")
|
||||
realHost = split[0]
|
||||
realPort = split[1]
|
||||
}
|
||||
ok, createClient := hOp.CheckAndBuildHarborClient(realHost, realPort, false)
|
||||
if !ok {
|
||||
return false, []string{
|
||||
"[Harbor Sync Project ] - Error !",
|
||||
}
|
||||
}
|
||||
hOp.SourceHarborClient = createClient
|
||||
}
|
||||
|
||||
needToSynchronizedProject := funcArgs[2]
|
||||
log.InfoF("[Harbor Sync Project ] - start to sync harbor project => %s", needToSynchronizedProject)
|
||||
|
||||
log.DebugF("[Harbor Sync Project ] - start to check projects all exists!")
|
||||
ctx := context.Background()
|
||||
|
||||
// check both source and target harbor project exists
|
||||
needToCreateProjectNameList := []string{"rancher", "cmii"}
|
||||
|
||||
for _, projectName := range needToCreateProjectNameList {
|
||||
syncNotExistHarborProjectError := []string{
|
||||
"[Harbor Sync Project ] - project not exists !",
|
||||
}
|
||||
exists, _ := targetClient.ProjectExists(ctx, projectName)
|
||||
if !exists {
|
||||
return false, append(syncNotExistHarborProjectError, "targetClient")
|
||||
}
|
||||
}
|
||||
|
||||
OctopusSourceHarborName := "octopus-source"
|
||||
|
||||
// add source registry to destination harbor
|
||||
log.InfoF("[Harbor Sync Project ] - start to create source harbor endpoints => %s", hOp.SourceHarborHost)
|
||||
|
||||
log.Debug("[Harbor Sync Project ] - start to delete exist replication policy !")
|
||||
policies, _ := targetClient.ListReplicationPolicies(ctx)
|
||||
if policies != nil {
|
||||
for _, policy := range policies {
|
||||
if policy.Name == OctopusReplicationPolicyName {
|
||||
err := targetClient.DeleteReplicationPolicyByID(ctx, policy.ID)
|
||||
if err != nil {
|
||||
log.ErrorF("[Harbor Sync Project ] - delete exists replication policy failed ! => %v ", policy)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Debug("[Harbor Sync Project ] - start to delete exist exist harbor endpoints !")
|
||||
exitRegistry, _ := targetClient.GetRegistryByName(ctx, OctopusSourceHarborName)
|
||||
if exitRegistry != nil {
|
||||
log.Debug("[Harbor Sync Project ] - source endpoints already exists ! delete it !")
|
||||
err := targetClient.DeleteRegistryByID(ctx, exitRegistry.ID)
|
||||
if err != nil {
|
||||
log.ErrorF("[Harbor Sync Project ] - source endpoints delete failed ! => %v ", exitRegistry)
|
||||
}
|
||||
}
|
||||
|
||||
// todo cqga failed
|
||||
octopusSourceRegistry := &model.Registry{
|
||||
Credential: &model.RegistryCredential{
|
||||
AccessKey: "admin",
|
||||
AccessSecret: "V2ryStr@ngPss",
|
||||
Type: "basic",
|
||||
},
|
||||
Insecure: true,
|
||||
Name: OctopusSourceHarborName, // 源 Harbor 实例的注册表 ID,通常为 0
|
||||
Type: "harbor",
|
||||
URL: strings.Split(hOp.SourceHarborHost, "/api")[0],
|
||||
}
|
||||
err := targetClient.NewRegistry(ctx, octopusSourceRegistry)
|
||||
if err != nil {
|
||||
sprintf := fmt.Sprintf("[SyncProjectExec] - source endpoints create failed ! => %s", err.Error())
|
||||
log.Error(sprintf)
|
||||
return false, []string{sprintf}
|
||||
}
|
||||
|
||||
// get the real one for it's ID
|
||||
realOctopusSourceRegistry, err := targetClient.GetRegistryByName(ctx, OctopusSourceHarborName)
|
||||
if err != nil {
|
||||
sprintf := fmt.Sprintf("[SyncProjectExec] - get target registry id failed ! => %s", err.Error())
|
||||
log.Error(sprintf)
|
||||
return false, []string{sprintf}
|
||||
}
|
||||
|
||||
// 创建复制策略
|
||||
octopusReplicationPolicy := &model.ReplicationPolicy{
|
||||
CopyByChunk: nil,
|
||||
Deletion: false,
|
||||
Description: "",
|
||||
DestNamespace: "", // 可以指定目标 Harbor 中的特定项目,如果为空,则使用源项目名称
|
||||
DestNamespaceReplaceCount: nil,
|
||||
SrcRegistry: &model.Registry{
|
||||
ID: realOctopusSourceRegistry.ID,
|
||||
},
|
||||
DestRegistry: &model.Registry{
|
||||
ID: 0,
|
||||
},
|
||||
Enabled: true,
|
||||
Filters: []*model.ReplicationFilter{
|
||||
{
|
||||
Type: "name",
|
||||
Value: needToSynchronizedProject + "/**",
|
||||
},
|
||||
},
|
||||
ID: 0,
|
||||
Name: OctopusReplicationPolicyName,
|
||||
Override: true,
|
||||
ReplicateDeletion: false,
|
||||
Speed: nil,
|
||||
Trigger: &model.ReplicationTrigger{
|
||||
Type: "manual", // 可以是 "manual", "scheduled", 或 "event_based"
|
||||
// 如果是 "scheduled",还需要设置 Cron 表达式
|
||||
// TriggerSettings: &model.TriggerSettings{Cron: "0 * * * *"},
|
||||
},
|
||||
}
|
||||
|
||||
// 在源 Harbor 中创建复制策略
|
||||
log.InfoF("[Harbor Sync Project ] - Start To Sync Project => %s !", needToSynchronizedProject)
|
||||
|
||||
err = targetClient.NewReplicationPolicy(ctx, octopusReplicationPolicy.DestRegistry, octopusReplicationPolicy.SrcRegistry, octopusReplicationPolicy.Deletion, octopusReplicationPolicy.Override, octopusReplicationPolicy.Enabled, octopusReplicationPolicy.Filters, octopusReplicationPolicy.Trigger, octopusReplicationPolicy.DestNamespace, octopusReplicationPolicy.Name, octopusReplicationPolicy.Name)
|
||||
|
||||
if err != nil {
|
||||
syncErrorMessage := fmt.Sprintf("[Harbor Sync Project ] - Sync Project [ %s ] Failed ! Error is => %s\n", needToSynchronizedProject, err.Error())
|
||||
log.Error(syncErrorMessage)
|
||||
return false, []string{
|
||||
syncErrorMessage,
|
||||
}
|
||||
}
|
||||
|
||||
realOctopusReplicationPolicy, err := targetClient.GetReplicationPolicyByName(ctx, OctopusReplicationPolicyName)
|
||||
if err != nil {
|
||||
return false, []string{
|
||||
"[Harbor Sync Project ] - failed to get the realOctopusReplicationPolicy!",
|
||||
err.Error(),
|
||||
}
|
||||
}
|
||||
|
||||
err = targetClient.TriggerReplicationExecution(ctx, &model.StartReplicationExecution{
|
||||
PolicyID: realOctopusReplicationPolicy.ID,
|
||||
})
|
||||
if err != nil {
|
||||
return false, []string{
|
||||
"[ Harbor Sync Project ] - failed to start the harbor sync execution !",
|
||||
err.Error(),
|
||||
}
|
||||
}
|
||||
|
||||
return true, []string{
|
||||
fmt.Sprintf("[ Harbor Sync Project ] - sync project [ %s ] started !", needToSynchronizedProject),
|
||||
}
|
||||
}
|
||||
|
||||
func (hOp *HarborOperator) SyncStatusExec(funcArgs []string) (bool, []string) {
|
||||
|
||||
if hOp.TargetHarborClient == nil {
|
||||
ok, createClient := hOp.CheckAndBuildHarborClient(funcArgs[0], "", true)
|
||||
if !ok {
|
||||
return false, []string{
|
||||
"[ Sync Status ] - Error !",
|
||||
}
|
||||
}
|
||||
hOp.TargetHarborClient = createClient
|
||||
}
|
||||
targetClient := hOp.TargetHarborClient
|
||||
|
||||
ctx := context.Background()
|
||||
// check replication policy exists
|
||||
|
||||
replicationPolicy, err := targetClient.GetReplicationPolicyByName(ctx, OctopusReplicationPolicyName)
|
||||
if err != nil {
|
||||
return false, []string{
|
||||
"[ Sync Status ] - get replication error !",
|
||||
err.Error(),
|
||||
}
|
||||
}
|
||||
|
||||
// list execution status
|
||||
replicationExecutions, err := targetClient.ListReplicationExecutions(ctx, &replicationPolicy.ID, nil, nil)
|
||||
if err != nil {
|
||||
return false, []string{
|
||||
"[ Sync Status ] - replication has no sync work !",
|
||||
err.Error(),
|
||||
}
|
||||
}
|
||||
|
||||
// find the newest one only have one here
|
||||
for _, execution := range replicationExecutions {
|
||||
if !strings.HasPrefix(execution.Status, "Succeed") {
|
||||
bytes, _ := json.Marshal(execution)
|
||||
log.InfoF("[sync status]- status are => %v", string(bytes))
|
||||
// report status
|
||||
return false, []string{
|
||||
fmt.Sprintf("[sync status] - not complete ! progress is => %s %%",
|
||||
strconv.FormatFloat(float64(execution.Succeed)/float64(execution.Total)*100, 'f', 2, 64)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true, []string{
|
||||
"[sync status]- sync completed !",
|
||||
}
|
||||
}
|
||||
|
||||
func (hOp *HarborOperator) Command(baseFuncName string, funcArgs ...string) []string {
|
||||
|
||||
return nil
|
||||
}
|
||||
298
agent-go/a_executor/ImageFunction.go
Normal file
298
agent-go/a_executor/ImageFunction.go
Normal file
@@ -0,0 +1,298 @@
|
||||
package a_executor
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"wdd.io/agent-common/image"
|
||||
)
|
||||
|
||||
var LocalGzipImageFolderPrefix = "/var/lib/docker/image_sync/"
|
||||
|
||||
func (op *AgentOsOperator) Sync(baseFuncName string, funcArgs ...string) (bool, []string) {
|
||||
resultOk := false
|
||||
var errorLog []string
|
||||
|
||||
switch baseFuncName {
|
||||
|
||||
case "DOWNLOAD_DOCKER_IMAGE":
|
||||
resultOk, errorLog = op.downloadDockerImage(funcArgs)
|
||||
break
|
||||
case "COMPRESS_IMAGE_TO_GZIP":
|
||||
resultOk, errorLog = op.compressImageToGzip(funcArgs)
|
||||
break
|
||||
case "UPLOAD_GZIP_TO_OSS":
|
||||
resultOk, errorLog = op.uploadGzipFileToOss(funcArgs)
|
||||
break
|
||||
case "DOWNLOAD_GZIP_IMAGE_FILE":
|
||||
resultOk, errorLog = op.downloadGzipImageFile(funcArgs)
|
||||
break
|
||||
case "LOAD_DOCKER_IMAGE_FROM_GZIP":
|
||||
resultOk, errorLog = op.loadDockerImageFromGzip(funcArgs)
|
||||
break
|
||||
case "PUSH_IMAGE_TO_TARGET_HARBOR":
|
||||
resultOk, errorLog = op.pushImageToTargetHarbor(funcArgs)
|
||||
break
|
||||
case "UPDATE_IMAGE_TAG":
|
||||
resultOk, errorLog = op.updateImageTag(funcArgs)
|
||||
break
|
||||
default:
|
||||
resultOk, errorLog = op.okExec(funcArgs)
|
||||
}
|
||||
|
||||
return resultOk, errorLog
|
||||
}
|
||||
|
||||
func (op *AgentOsOperator) downloadDockerImage(funcArgs []string) (bool, []string) {
|
||||
// funcArgs are imageFullName gzipFolderPrefix gzipFileName ossUrlPrefix namespace newImageTag
|
||||
|
||||
if !BasicCommandExistByPath("docker") {
|
||||
return false, []string{
|
||||
"docker not exits !",
|
||||
}
|
||||
}
|
||||
imageFullName := funcArgs[0]
|
||||
log.InfoF("[downloadDockerImage]- start to pull docker image %s", imageFullName)
|
||||
|
||||
// login
|
||||
if strings.HasPrefix(imageFullName, image.CmiiHarborPrefix) {
|
||||
HardCodeCommandExecutor("docker login -u rad02_drone -p Drone@1234 harbor.cdcyy.com.cn")
|
||||
}
|
||||
|
||||
if !PureResultSingleExecute([]string{
|
||||
"docker",
|
||||
"pull",
|
||||
imageFullName,
|
||||
}) {
|
||||
return false, []string{
|
||||
"docker pull failed of " + imageFullName,
|
||||
}
|
||||
}
|
||||
|
||||
if !BasicDockerImageExistByFullName(funcArgs[0]) {
|
||||
return false, []string{
|
||||
"image not exits ! unknown error happened!",
|
||||
}
|
||||
}
|
||||
return true, []string{
|
||||
imageFullName,
|
||||
}
|
||||
}
|
||||
|
||||
func (op *AgentOsOperator) compressImageToGzip(funcArgs []string) (bool, []string) {
|
||||
if !BasicCommandExistByPath("docker") {
|
||||
return false, []string{
|
||||
"docker not exits !",
|
||||
}
|
||||
}
|
||||
if !BasicCommandExistByPath("gzip") {
|
||||
return false, []string{
|
||||
"gzip not exits !",
|
||||
}
|
||||
}
|
||||
|
||||
gzipFolderPrefix := funcArgs[1]
|
||||
if !BasicFolderExists(gzipFolderPrefix) {
|
||||
BasicCreateFolder(gzipFolderPrefix)
|
||||
}
|
||||
|
||||
imageFullName := funcArgs[0]
|
||||
if !BasicDockerImageExistByFullName(imageFullName) {
|
||||
return false, []string{
|
||||
"image not exits !",
|
||||
}
|
||||
}
|
||||
|
||||
if !strings.HasSuffix(gzipFolderPrefix, "/") {
|
||||
gzipFolderPrefix += "/"
|
||||
}
|
||||
|
||||
gzipImageFromFullName := image.ImageFullNameToGzipFileName(imageFullName)
|
||||
dockerSaveCommand := "docker save " + imageFullName + " | gzip > " + gzipFolderPrefix + gzipImageFromFullName
|
||||
|
||||
executor, i := HardCodeCommandExecutor(dockerSaveCommand)
|
||||
if !executor {
|
||||
return false, i
|
||||
}
|
||||
|
||||
if !BasicFileExistAndNotNull(gzipFolderPrefix + gzipImageFromFullName) {
|
||||
return false, []string{
|
||||
"gzip of ile error ",
|
||||
}
|
||||
}
|
||||
|
||||
return true, []string{
|
||||
gzipImageFromFullName,
|
||||
}
|
||||
}
|
||||
|
||||
func (op *AgentOsOperator) uploadGzipFileToOss(funcArgs []string) (bool, []string) {
|
||||
|
||||
if !BasicCommandExistByPath("mc") {
|
||||
return false, []string{
|
||||
"mc not exits!",
|
||||
}
|
||||
}
|
||||
|
||||
gzipFolderPrefix := funcArgs[1]
|
||||
gzipImageFromFullName := funcArgs[2]
|
||||
|
||||
ok, resultLog := HardCodeCommandExecutor("mc --insecure alias set demo https://oss.ig-demo.uavcmlc.com cmii B#923fC7mk")
|
||||
//ok, resultLog = HardCodeCommandExecutor("mc alias list")
|
||||
|
||||
PureResultSingleExecute([]string{
|
||||
"mc",
|
||||
"rm",
|
||||
"demo/cmlc-installation/tmp/" + gzipImageFromFullName,
|
||||
})
|
||||
|
||||
ok, resultLog = AllCommandExecutor([]string{
|
||||
"mc",
|
||||
"cp",
|
||||
gzipFolderPrefix + gzipImageFromFullName,
|
||||
"demo/cmlc-installation/tmp/" + gzipImageFromFullName,
|
||||
})
|
||||
if !ok {
|
||||
return false, resultLog
|
||||
}
|
||||
|
||||
find, _ := BasicFindContentInCommandOutput("mc ls demo/cmlc-installation/tmp/", gzipImageFromFullName)
|
||||
if !find {
|
||||
return false, []string{
|
||||
"demo oss can't find gzip file !",
|
||||
}
|
||||
}
|
||||
|
||||
return true, []string{
|
||||
gzipImageFromFullName,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (op *AgentOsOperator) downloadGzipImageFile(funcArgs []string) (bool, []string) {
|
||||
|
||||
ossUrlPrefix := funcArgs[3]
|
||||
gzipImageFromFullName := funcArgs[2]
|
||||
proxyUrl := funcArgs[4]
|
||||
|
||||
// create folder
|
||||
BasicCreateFolder(LocalGzipImageFolderPrefix)
|
||||
|
||||
// remove file
|
||||
desFile := LocalGzipImageFolderPrefix + gzipImageFromFullName
|
||||
|
||||
if !BasicRemoveFileOrFolder(desFile) {
|
||||
return false, []string{
|
||||
"file already exits ! can't remove it!",
|
||||
}
|
||||
}
|
||||
|
||||
var download bool
|
||||
var downloadLog []string
|
||||
if proxyUrl == "" {
|
||||
download, downloadLog = BasicDownloadFile(ossUrlPrefix+gzipImageFromFullName, desFile)
|
||||
} else {
|
||||
download, downloadLog = BasicDownloadFileWithProxy(ossUrlPrefix+gzipImageFromFullName, proxyUrl, desFile)
|
||||
}
|
||||
|
||||
if !download {
|
||||
return false, downloadLog
|
||||
}
|
||||
|
||||
return true, []string{
|
||||
desFile,
|
||||
}
|
||||
}
|
||||
|
||||
func (op *AgentOsOperator) loadDockerImageFromGzip(funcArgs []string) (bool, []string) {
|
||||
gzipImageFromFullName := funcArgs[2]
|
||||
|
||||
if !BasicFileExistAndNotNull(LocalGzipImageFolderPrefix + gzipImageFromFullName) {
|
||||
return false, []string{
|
||||
LocalGzipImageFolderPrefix + gzipImageFromFullName,
|
||||
"local gzip file not exits!",
|
||||
}
|
||||
}
|
||||
|
||||
hardCodeCommand := "docker load < " + LocalGzipImageFolderPrefix + gzipImageFromFullName
|
||||
executor, i := HardCodeCommandExecutor(hardCodeCommand)
|
||||
if !executor {
|
||||
return false, i
|
||||
}
|
||||
|
||||
if !BasicDockerImageExistByFullName(funcArgs[0]) {
|
||||
return false, []string{
|
||||
"docker load from gzip file error ! image not exits!",
|
||||
funcArgs[0],
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
func (op *AgentOsOperator) pushImageToTargetHarbor(funcArgs []string) (bool, []string) {
|
||||
|
||||
targetHarborHost := funcArgs[5]
|
||||
imageFullName := funcArgs[0]
|
||||
|
||||
if !strings.Contains(targetHarborHost, "8033") {
|
||||
targetHarborHost += ":8033"
|
||||
}
|
||||
|
||||
targetImageFullName := image.ImageFullNameToTargetImageFullName(imageFullName, targetHarborHost)
|
||||
|
||||
if !PureResultSingleExecute([]string{
|
||||
"docker",
|
||||
"tag",
|
||||
imageFullName,
|
||||
targetImageFullName,
|
||||
}) {
|
||||
return false, []string{
|
||||
"docker tag error!",
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(targetImageFullName, image.CmiiHarborPrefix) {
|
||||
HardCodeCommandExecutor("docker login -u rad02_drone -p Drone@1234 harbor.cdcyy.com.cn")
|
||||
} else {
|
||||
HardCodeCommandExecutor("docker login -u admin -p V2ryStr@ngPss " + targetHarborHost)
|
||||
}
|
||||
|
||||
ok, resultLog := AllCommandExecutor([]string{
|
||||
"docker",
|
||||
"push",
|
||||
targetImageFullName,
|
||||
})
|
||||
if !ok {
|
||||
return false, resultLog
|
||||
}
|
||||
|
||||
return true, []string{
|
||||
targetImageFullName,
|
||||
}
|
||||
}
|
||||
func (op *AgentOsOperator) updateImageTag(funcArgs []string) (bool, []string) {
|
||||
namespace := funcArgs[6]
|
||||
targetImageFullName := funcArgs[7]
|
||||
if !BasicCommandExistByPath("kubectl") {
|
||||
return false, []string{
|
||||
"kubectl not exits !",
|
||||
}
|
||||
}
|
||||
imageFullName := funcArgs[0]
|
||||
if !strings.HasPrefix(imageFullName, image.CmiiHarborPrefix) {
|
||||
return false, []string{
|
||||
"cant update this image !",
|
||||
}
|
||||
}
|
||||
|
||||
appName := image.ImageFullNameToAppName(imageFullName)
|
||||
|
||||
updateCommand := "kubectl -n " + namespace + " patch deployment " + appName + "-p \"{\"spec\":{\"template\":{\"spec\":{\"containers\":[{\"name\": " + appName + ",\"image\": " + targetImageFullName + "}]}}}}"
|
||||
executor, i := HardCodeCommandExecutor(updateCommand)
|
||||
if !executor {
|
||||
return false, i
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
//func BuildGzipImageFromFullName(imageFullName string) string {
|
||||
//
|
||||
//}
|
||||
25
agent-go/a_executor/ImageFunction_test.go
Normal file
25
agent-go/a_executor/ImageFunction_test.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package a_executor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
"wdd.io/agent-common/utils"
|
||||
)
|
||||
|
||||
func TestAgentOsOperator_Sync(t *testing.T) {
|
||||
|
||||
// imageFullName gzipFolderPrefix gzipFileName ossUrlPrefix proxyUrl targetHarborHost namespace targetImageFullName
|
||||
funcArgs := []string{
|
||||
"harbor.cdcyy.com.cn/cmii/busybox:0326",
|
||||
"/var/lib/docker/octopus_image/",
|
||||
"cmlc=cmii=busybox=0326.tar.gz",
|
||||
"https://oss.demo.uavcmlc.com:18000/cmlc-installation/tmp/",
|
||||
"",
|
||||
"10.250.0.100",
|
||||
"",
|
||||
}
|
||||
sync, strings := agentOP.Sync("PUSH_IMAGE_TO_TARGET_HARBOR", funcArgs...)
|
||||
fmt.Println("func result are => " + strconv.FormatBool(sync))
|
||||
utils.BeautifulPrint(strings)
|
||||
}
|
||||
197
agent-go/a_executor/InitFunction.go
Normal file
197
agent-go/a_executor/InitFunction.go
Normal file
@@ -0,0 +1,197 @@
|
||||
package a_executor
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
"wdd.io/agent-go/a_status"
|
||||
)
|
||||
|
||||
func BuildAgentOsOperator(agentInfo *a_status.AgentInfo, ossOfflinePrefix string) *AgentOsOperator {
|
||||
|
||||
AgentOsOperatorCache = &AgentOsOperator{
|
||||
InstallCommandPrefix: []string{
|
||||
"apt-get", "install", "--allow-downgrades", "-y",
|
||||
},
|
||||
RemoveCommandPrefix: []string{"apt", "remove", "-y"},
|
||||
CanAccessInternet: true,
|
||||
IsOsTypeUbuntu: true,
|
||||
IsOsTypeCentOS: false,
|
||||
IsOsTypeEuler: false,
|
||||
IsAgentInnerWall: false,
|
||||
AgentArch: "amd64",
|
||||
AgentOSReleaseCode: "focal",
|
||||
AgentServerInfo: nil,
|
||||
OssOfflinePrefix: ossOfflinePrefix,
|
||||
}
|
||||
|
||||
// os type
|
||||
detectByAgentStatusInfo(agentInfo, AgentOsOperatorCache)
|
||||
|
||||
// internet
|
||||
detectByInternet(AgentOsOperatorCache)
|
||||
|
||||
return AgentOsOperatorCache
|
||||
}
|
||||
|
||||
func detectByAgentStatusInfo(agentInfo *a_status.AgentInfo, os *AgentOsOperator) {
|
||||
if agentInfo == nil {
|
||||
log.WarnF("[detectByAgentStatusInfo] - agentInfo from status module is nil, roll back to traditional way!")
|
||||
// detectByOsType()
|
||||
}
|
||||
|
||||
bytes, _ := json.Marshal(agentInfo)
|
||||
log.DebugF("[detectByAgentStatusInfo] - agent info is => %s", string(bytes))
|
||||
|
||||
if strings.Contains(agentInfo.HostInfo.Platform, "openeuler") || strings.Contains(agentInfo.HostInfo.PlatformFamily, "rehl") {
|
||||
// centos
|
||||
os.IsOsTypeUbuntu = false
|
||||
os.IsOsTypeCentOS = true
|
||||
if strings.Contains(agentInfo.HostInfo.Platform, "openeuler") {
|
||||
os.IsOsTypeEuler = true
|
||||
}
|
||||
os.InstallCommandPrefix = []string{
|
||||
"yum", "install", "-y",
|
||||
}
|
||||
os.RemoveCommandPrefix = []string{
|
||||
"yum", "remove", "-y",
|
||||
}
|
||||
|
||||
} else if strings.Contains(agentInfo.HostInfo.PlatformFamily, "debian") {
|
||||
// ubuntu
|
||||
os.IsOsTypeUbuntu = true
|
||||
os.IsOsTypeCentOS = false
|
||||
os.IsOsTypeEuler = false
|
||||
os.RemoveCommandPrefix = []string{"apt", "remove", "-y"}
|
||||
os.InstallCommandPrefix = []string{
|
||||
"apt-get", "install", "--allow-downgrades", "-y",
|
||||
}
|
||||
|
||||
// os release code
|
||||
os.AgentOSReleaseCode = judgeUbuntuReleaseFromOsVersion(agentInfo.HostInfo.PlatformVersion)
|
||||
}
|
||||
|
||||
// agent cpu arch
|
||||
os.AgentArch = judgeAgentCpuArchByKernelArch(agentInfo.HostInfo.KernelArch)
|
||||
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
||||
func judgeAgentCpuArchByKernelArch(kernelArch string) string {
|
||||
switch kernelArch {
|
||||
case "x86_64":
|
||||
return "amd64"
|
||||
case "aarch64":
|
||||
return "arm64"
|
||||
case "armv8":
|
||||
return "arm64"
|
||||
case "armv6":
|
||||
return "arm6"
|
||||
case "armv7":
|
||||
return "arm7"
|
||||
case "i32":
|
||||
return "386"
|
||||
case "i86":
|
||||
return "386"
|
||||
default:
|
||||
return "cpu-unknown"
|
||||
}
|
||||
}
|
||||
|
||||
func detectByInternet(os *AgentOsOperator) {
|
||||
|
||||
outsideTestUrl := "www.google.com"
|
||||
innerTestUrl := "www.baidu.com"
|
||||
|
||||
testInternetCommand := []string{
|
||||
"curl",
|
||||
"-o",
|
||||
"/dev/null",
|
||||
"-m",
|
||||
"5",
|
||||
"-s",
|
||||
}
|
||||
|
||||
if PureResultSingleExecute(append(testInternetCommand, outsideTestUrl)) {
|
||||
os.CanAccessInternet = true
|
||||
os.IsAgentInnerWall = false
|
||||
} else if PureResultSingleExecute(append(testInternetCommand, innerTestUrl)) {
|
||||
os.CanAccessInternet = true
|
||||
os.IsAgentInnerWall = true
|
||||
} else {
|
||||
os.CanAccessInternet = false
|
||||
os.IsAgentInnerWall = true
|
||||
}
|
||||
|
||||
log.InfoF("[Agent Network Status] - Can Access Internet => %s Inner CN => %s", strconv.FormatBool(os.CanAccessInternet), strconv.FormatBool(os.IsAgentInnerWall))
|
||||
|
||||
}
|
||||
|
||||
func detectByOsType(os *AgentOsOperator, osInfo string) {
|
||||
|
||||
ubuntuOsReleaseCode := [][]string{
|
||||
{
|
||||
"cat",
|
||||
"/etc/os-release",
|
||||
},
|
||||
{
|
||||
"grep",
|
||||
"CODE",
|
||||
},
|
||||
{
|
||||
"head",
|
||||
"-1",
|
||||
},
|
||||
{
|
||||
"cut",
|
||||
"-d",
|
||||
"=",
|
||||
"-f",
|
||||
"2",
|
||||
},
|
||||
}
|
||||
|
||||
if strings.HasPrefix(osInfo, "Ce") {
|
||||
// centos
|
||||
os.IsOsTypeUbuntu = false
|
||||
os.InstallCommandPrefix = []string{
|
||||
"yum", "install", "-y",
|
||||
}
|
||||
os.RemoveCommandPrefix = []string{
|
||||
"yum", "remove",
|
||||
}
|
||||
|
||||
} else {
|
||||
// ubuntu
|
||||
os.IsOsTypeUbuntu = true
|
||||
os.RemoveCommandPrefix = []string{"apt", "remove", "-y"}
|
||||
os.InstallCommandPrefix = []string{
|
||||
"apt-get", "install", "--allow-downgrades", "-y",
|
||||
}
|
||||
|
||||
// os release code
|
||||
ok, resultLog := PipelineCommandExecutor(ubuntuOsReleaseCode)
|
||||
if ok {
|
||||
os.AgentOSReleaseCode = resultLog[0]
|
||||
} else {
|
||||
os.AgentOSReleaseCode = "UNKNOWN"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
365
agent-go/a_executor/K8sFunction.go
Normal file
365
agent-go/a_executor/K8sFunction.go
Normal file
@@ -0,0 +1,365 @@
|
||||
package a_executor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"context"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
var k8sConfigFilePath = "/root/wdd/kube_config_cluster.yml"
|
||||
var k8sClient = newK8sClientInstance()
|
||||
|
||||
func newK8sClientInstance() *kubernetes.Clientset {
|
||||
once := sync.Once{}
|
||||
|
||||
if !BasicFileExistAndNotNull(k8sConfigFilePath) {
|
||||
log.WarnF("[newK8sClientInstance] - k8s config %s does not exist ! ", k8sConfigFilePath)
|
||||
return nil
|
||||
}
|
||||
|
||||
var client *kubernetes.Clientset
|
||||
once.Do(func() {
|
||||
// 使用kubeconfig文件初始化客户端
|
||||
config, err := clientcmd.BuildConfigFromFlags("", k8sConfigFilePath)
|
||||
if err != nil {
|
||||
log.ErrorF("[newK8sClientInstance] - load from %s error !", k8sConfigFilePath)
|
||||
|
||||
}
|
||||
|
||||
client, err = kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Error("[newK8sClientInstance] - create k8s client error !")
|
||||
}
|
||||
})
|
||||
|
||||
return client
|
||||
}
|
||||
|
||||
func K8sCheckPodStatusTimeout(specificPod string, supreme string, waitTimeOut int) bool {
|
||||
|
||||
if k8sClient == nil {
|
||||
// this should be the first call of k8s function
|
||||
k8sClient = newK8sClientInstance()
|
||||
if k8sClient == nil {
|
||||
log.ErrorF("k8s client is nil, run k8s function error !")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 设置超时时间和时间间隔
|
||||
timeout := time.After(time.Duration(waitTimeOut) * time.Second)
|
||||
tick := time.Tick(5 * time.Second)
|
||||
|
||||
// 监控Pod状态
|
||||
for {
|
||||
select {
|
||||
case <-timeout:
|
||||
log.ErrorF("[K8sCheckPodStatusTimeout] - 命名空间: [%s], Pod名称: [%s], 状态: 失败!", supreme, specificPod)
|
||||
return false
|
||||
case <-tick:
|
||||
pod, err := k8sClient.CoreV1().Pods(supreme).Get(context.TODO(), specificPod, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.ErrorF("[K8sCheckPodStatusTimeout] - 命名空间: [%s], Pod名称: [%s], 获取Pod信息失败 !", supreme, err.Error())
|
||||
} else {
|
||||
log.DebugF("[K8sCheckPodStatusTimeout] - 命名空间: [%s], Pod名称: [%s], 状态: [%s]", supreme, pod.Name, pod.Status.Phase)
|
||||
if pod.Status.Phase == corev1.PodRunning || pod.Status.Phase == corev1.PodSucceeded {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func K8sCheckDeploymentStatusTimeout(specificDeployment string, supreme string, waitTimeOut int) bool {
|
||||
|
||||
if k8sClient == nil {
|
||||
// this should be the first call of k8s function
|
||||
k8sClient = newK8sClientInstance()
|
||||
if k8sClient == nil {
|
||||
log.ErrorF("k8s client is nil, run k8s function error !")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 设置超时时间和时间间隔
|
||||
timeout := time.After(time.Duration(waitTimeOut) * time.Second)
|
||||
tick := time.Tick(5 * time.Second)
|
||||
|
||||
// 监控Pod状态
|
||||
for {
|
||||
select {
|
||||
case <-timeout:
|
||||
log.ErrorF("[K8sCheckDeploymentStatusTimeout] - 命名空间: %s, Deployment名称: %s, 状态: 失败!\n", supreme, specificDeployment)
|
||||
return false
|
||||
case <-tick:
|
||||
deployment, err := k8sClient.AppsV1().Deployments(supreme).Get(context.TODO(), specificDeployment, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.ErrorF("[K8sCheckDeploymentStatusTimeout] - 命名空间: [%s], Deployment 名称: [%s], 获取Deployment信息失败 !", supreme, err.Error())
|
||||
} else {
|
||||
log.DebugF("[K8sCheckDeploymentStatusTimeout] - 命名空间: [ %s ], Deployment: [ %s ] 还有Pods未处于Running状态 (Ready: %d, Total: %d)\n", supreme, deployment.Name, deployment.Status.ReadyReplicas, deployment.Status.Replicas)
|
||||
|
||||
if deployment.Status.ReadyReplicas == deployment.Status.Replicas {
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func K8sListPVCInNamespace(supreme string) (bool, []string) {
|
||||
|
||||
if k8sClient == nil {
|
||||
// this should be the first call of k8s function
|
||||
k8sClient = newK8sClientInstance()
|
||||
if k8sClient == nil {
|
||||
log.ErrorF("k8s client is nil, run k8s function error !")
|
||||
return false, []string{
|
||||
"[K8sListPVCInNamespace] - k8s client not exits !",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pvcs, err := k8sClient.CoreV1().PersistentVolumeClaims(supreme).List(context.TODO(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
log.ErrorF("[K8sListPVCInNamespace] - error list pvc list in namespace %s", supreme)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
var pvcList []string
|
||||
for _, pvc := range pvcs.Items {
|
||||
pvcList = append(pvcList, pvc.Name)
|
||||
}
|
||||
|
||||
log.DebugF("K8sListPVCInNamespace - all pvc in namespace of [ %s ] are %v", supreme, pvcList)
|
||||
return true, pvcList
|
||||
}
|
||||
|
||||
func K8sCheckPVCStatusTimeOut(specificPvcName string, supreme string, waitTimeOut int) bool {
|
||||
|
||||
if k8sClient == nil {
|
||||
// this should be the first call of k8s function
|
||||
k8sClient = newK8sClientInstance()
|
||||
if k8sClient == nil {
|
||||
log.ErrorF("k8s client is nil, run k8s function error !")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 设置超时时间和时间间隔
|
||||
timeout := time.After(time.Duration(waitTimeOut) * time.Second)
|
||||
tick := time.Tick(5 * time.Second)
|
||||
|
||||
// 监控Pod状态
|
||||
for {
|
||||
select {
|
||||
case <-timeout:
|
||||
log.ErrorF("[K8sCheckPVCStatusTimeOut] - 命名空间: %s, PVC 名称: %s, 状态: 失败! ", supreme, specificPvcName)
|
||||
return false
|
||||
case <-tick:
|
||||
pvc, err := k8sClient.CoreV1().PersistentVolumeClaims(supreme).Get(context.TODO(), specificPvcName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.ErrorF("[K8sCheckPVCStatusTimeOut] - 命名空间: [ %s ], 获取 PVC [%s] 信息失败: %s ", supreme, specificPvcName, err.Error())
|
||||
}
|
||||
|
||||
if pvc.Status.Phase == corev1.ClaimBound {
|
||||
log.DebugF("[K8sCheckPVCStatusTimeOut] - PVC %s in namespace %s is running", specificPvcName, supreme)
|
||||
return true
|
||||
} else {
|
||||
log.WarnF("[K8sCheckPVCStatusTimeOut] - PVC %s in namespace %s run failed !", specificPvcName, supreme)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func KubectlCheckPodStatus(specific string, supreme string) bool {
|
||||
|
||||
if !BasicCommandExists("kubectl") {
|
||||
log.Error("kubectl命令不存在,无法查看Pod状态,请查看!")
|
||||
}
|
||||
|
||||
ok, resultLog := AllCommandExecutor([]string{
|
||||
"kubectl", "-n", supreme, "get", "pod", specific, "-o", "jsonpath='{.status.phase}'",
|
||||
})
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, resultLine := range resultLog {
|
||||
if strings.HasPrefix(resultLine, "Running") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func KubectlApplyExec(resourcesYamlFile string) (bool, []string) {
|
||||
|
||||
// check kubectl
|
||||
if !BasicCommandExistByPath("kubectl") {
|
||||
return false, []string{
|
||||
"[KubectlApplyExec] - kubectl command not exist !",
|
||||
}
|
||||
}
|
||||
|
||||
// check resourcesYamlFile
|
||||
if !BasicFileExistAndNotNull(resourcesYamlFile) {
|
||||
return false, []string{
|
||||
fmt.Sprintf("[KubectlApplyExec] - wrong resourcesYamlFile %s not exist !", resourcesYamlFile),
|
||||
}
|
||||
}
|
||||
|
||||
// apply -f
|
||||
ok, resultLog := AllCommandExecutor([]string{
|
||||
"/usr/local/bin/kubectl",
|
||||
"apply",
|
||||
"-f",
|
||||
resourcesYamlFile,
|
||||
})
|
||||
if !ok {
|
||||
return false, resultLog
|
||||
}
|
||||
|
||||
return true, append(resultLog,
|
||||
fmt.Sprintf("[KubectlApplyExec] - %s apply success!", resourcesYamlFile))
|
||||
}
|
||||
|
||||
func KubectlDeleteExec(resourcesYamlFile string) (bool, []string) {
|
||||
|
||||
// check kubectl
|
||||
if !BasicCommandExistByPath("kubectl") {
|
||||
return false, []string{
|
||||
"[KubectlDeleteExec] - kubectl command not exist !",
|
||||
}
|
||||
}
|
||||
|
||||
// check resourcesYamlFile
|
||||
if !BasicFileExistAndNotNull(resourcesYamlFile) {
|
||||
return false, []string{
|
||||
fmt.Sprintf("[KubectlDeleteExec] - wrong resourcesYamlFile %s not exist !", resourcesYamlFile),
|
||||
}
|
||||
}
|
||||
|
||||
// apply -f
|
||||
ok, resultLog := AllCommandExecutor([]string{
|
||||
"/usr/local/bin/kubectl",
|
||||
"delete",
|
||||
"-f",
|
||||
resourcesYamlFile,
|
||||
})
|
||||
if !ok {
|
||||
return false, resultLog
|
||||
}
|
||||
|
||||
return true, append(resultLog,
|
||||
fmt.Sprintf("[KubectlDeleteExec] - %s delete success!", resourcesYamlFile))
|
||||
}
|
||||
|
||||
func K8sCreateNamespace(namespaceName string) bool {
|
||||
if k8sClient == nil {
|
||||
// this should be the first call of k8s function
|
||||
k8sClient = newK8sClientInstance()
|
||||
if k8sClient == nil {
|
||||
log.ErrorF("k8s client is nil, run k8s function error !")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
namespace, err := k8sClient.CoreV1().Namespaces().Get(context.TODO(), namespaceName, metav1.GetOptions{})
|
||||
if err == nil {
|
||||
log.InfoF("[K8sCreateNamespace] - namespace of [%s] already exists!", namespaceName)
|
||||
return true
|
||||
}
|
||||
|
||||
// create namespace
|
||||
// 创建命名空间对象
|
||||
namespace = &corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: namespaceName,
|
||||
},
|
||||
}
|
||||
// 使用客户端创建命名空间
|
||||
namespace, err = k8sClient.CoreV1().Namespaces().Create(context.TODO(), namespace, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
log.ErrorF("Error getting namespace: %s ", err.Error())
|
||||
return false
|
||||
}
|
||||
|
||||
// check namespace exists
|
||||
// 尝试获取名为 "xxg" 的命名空间
|
||||
namespace, err = k8sClient.CoreV1().Namespaces().Get(context.TODO(), namespaceName, metav1.GetOptions{})
|
||||
// 如果返回错误,需要判断是因为命名空间不存在还是其他错误
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
log.ErrorF("Namespace %s cant be got !", namespaceName)
|
||||
return false
|
||||
} else {
|
||||
log.ErrorF("Error retrieving namespace: %s\n", err.Error())
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
log.DebugF("Namespace %s create successful !", namespaceName)
|
||||
return true
|
||||
}
|
||||
|
||||
func K8sGetDashBoardAuthKey() bool {
|
||||
|
||||
if k8sClient == nil {
|
||||
// this should be the first call of k8s function
|
||||
k8sClient = newK8sClientInstance()
|
||||
if k8sClient == nil {
|
||||
log.ErrorF("k8s client is nil, run k8s function error !")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 获取 kube-system 命名空间的 secrets 列表
|
||||
secrets, err := k8sClient.CoreV1().Secrets("kube-system").List(context.TODO(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
fmt.Printf("Error retrieving secrets from kube-system namespace: %s\n", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// 过滤出名为 admin-user 的 secret
|
||||
var adminUserSecretName string
|
||||
for _, secret := range secrets.Items {
|
||||
if strings.Contains(secret.Name, "admin-user") {
|
||||
adminUserSecretName = secret.Name
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if adminUserSecretName == "" {
|
||||
fmt.Println("No admin-user secret found")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// 获取并打印特定的 secret 描述信息
|
||||
secret, err := k8sClient.CoreV1().Secrets("kube-system").Get(context.TODO(), adminUserSecretName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
fmt.Printf("Error retrieving secret %s: %s\n", adminUserSecretName, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// 打印 secret 的详细信息,根据需要格式化输出
|
||||
fmt.Printf("Name: %s\nNamespace: %s\nData:\n", secret.Name, secret.Namespace)
|
||||
for key, value := range secret.Data {
|
||||
fmt.Printf("%s: %s\n", key, value)
|
||||
}
|
||||
|
||||
return false
|
||||
|
||||
}
|
||||
183
agent-go/a_executor/MySqlFunction.go
Normal file
183
agent-go/a_executor/MySqlFunction.go
Normal file
@@ -0,0 +1,183 @@
|
||||
package a_executor
|
||||
|
||||
//import (
|
||||
// _ "github.com/go-sql-driver/mysql"
|
||||
//)
|
||||
|
||||
//func MysqlSqlFileLoad(jackeyLoveIp string, jackeyLoveFileList []string) (bool, []string) {
|
||||
//
|
||||
// dsn := "root:QzfXQhd3bQ@tcp(" + jackeyLoveIp + ":33306)/"
|
||||
// db, err := sql.Open("mysql", dsn)
|
||||
// if err != nil {
|
||||
// errConnect := fmt.Sprintf("[MysqlSqlFileLoad]- mysql connection error ! please check ! => %s error is %s ", dsn, err.Error())
|
||||
// log.Error(errConnect)
|
||||
// return false, []string{
|
||||
// errConnect,
|
||||
// }
|
||||
// }
|
||||
// defer db.Close()
|
||||
//
|
||||
// // 确保数据库连接是有效的
|
||||
// if err := db.Ping(); err != nil {
|
||||
// errConnect := "[MysqlSqlFileLoad]- mysql ping error ! please check !"
|
||||
// log.Error(errConnect)
|
||||
// return false, []string{
|
||||
// errConnect,
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// for _, jackeyLoveFile := range jackeyLoveFileList {
|
||||
//
|
||||
// // 打开 SQL 文件
|
||||
// jackeyLove, err := os.Open(jackeyLoveFile)
|
||||
// if err != nil {
|
||||
// log.ErrorF("[MysqlSqlFileLoad] - failed to load jackeyLoveFile => %s", jackeyLove.Name())
|
||||
// }
|
||||
// defer jackeyLove.Close()
|
||||
//
|
||||
// // 逐行读取 SQL 文件并执行
|
||||
// query := ""
|
||||
// delimiterSwitched := false
|
||||
// scanner := bufio.NewScanner(jackeyLove)
|
||||
// for scanner.Scan() {
|
||||
// sqlStatement := scanner.Text()
|
||||
//
|
||||
// if strings.HasPrefix(strings.TrimSpace(sqlStatement), "DELIMITER") {
|
||||
// delimiterSwitched = true
|
||||
// continue
|
||||
// }
|
||||
// if delimiterSwitched {
|
||||
// if strings.TrimSpace(sqlStatement) == "" || strings.TrimSpace(sqlStatement) == ";" {
|
||||
// delimiterSwitched = false
|
||||
// // 替换自定义分隔符为 ;
|
||||
// sqlStatement = strings.ReplaceAll(sqlStatement, ";;", ";")
|
||||
// } else {
|
||||
// // 忽略自定义分隔符行
|
||||
// continue
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 这里可以添加逻辑来忽略空行或注释行
|
||||
// if sqlStatement == "" || sqlStatement[:2] == "--" || sqlStatement[:2] == "/*" {
|
||||
// continue
|
||||
// }
|
||||
//
|
||||
// query += sqlStatement
|
||||
//
|
||||
// if strings.HasSuffix(strings.TrimSpace(sqlStatement), ";") {
|
||||
//
|
||||
// fmt.Printf("%s -> %s", jackeyLoveFile, query)
|
||||
//
|
||||
// _, err := db.Exec(query)
|
||||
// if err != nil {
|
||||
// executeError := fmt.Sprintf("[MysqlSqlFileLoad] - jackeyLoveFile %s 执行出错: %s, 错误信息: %s", jackeyLove.Name(), sqlStatement, err.Error())
|
||||
// log.Error(executeError)
|
||||
// return false, []string{
|
||||
// executeError,
|
||||
// }
|
||||
// }
|
||||
// query = ""
|
||||
// } else {
|
||||
// query += " " // 添加空格以便连接多行语句
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 检查扫描过程中是否有错误
|
||||
// if err := scanner.Err(); err != nil {
|
||||
// executeError := fmt.Sprintf("[MysqlSqlFileLoad] - jackeyLoveFile %s 文件加载错误! 错误信息: %s", jackeyLove.Name(), err.Error())
|
||||
// log.Error(executeError)
|
||||
// return false, []string{
|
||||
// executeError,
|
||||
// }
|
||||
// }
|
||||
// log.DebugF("[MysqlSqlFileLoad] - jackeyLoveFile %s execute success !", jackeyLove.Name())
|
||||
// }
|
||||
//
|
||||
// return true, append(jackeyLoveFileList, "[MysqlSqlFileLoad] all file loaded !")
|
||||
//}
|
||||
|
||||
//func MySqlParseSQLFile(sqlFilePath string) []string {
|
||||
//
|
||||
// var result []string
|
||||
//
|
||||
// // 打开 SQL 文件
|
||||
// jackeyLove, err := os.Open(sqlFilePath)
|
||||
// if err != nil {
|
||||
// log.ErrorF("[MySqlParseSQLFile] - failed to load jackeyLoveFile => %s", jackeyLove.Name())
|
||||
// }
|
||||
// defer jackeyLove.Close()
|
||||
//
|
||||
// // 逐行读取 SQL 文件并执行
|
||||
// query := ""
|
||||
// delimiterSwitched := false
|
||||
// scanner := bufio.NewScanner(jackeyLove)
|
||||
// for scanner.Scan() {
|
||||
// sqlStatement := scanner.Text()
|
||||
//
|
||||
// if strings.HasPrefix(strings.TrimSpace(sqlStatement), "DELIMITER") {
|
||||
// delimiterSwitched = true
|
||||
// continue
|
||||
// }
|
||||
// if delimiterSwitched {
|
||||
// if strings.TrimSpace(sqlStatement) == "" || strings.TrimSpace(sqlStatement) == ";" {
|
||||
// delimiterSwitched = false
|
||||
// // 替换自定义分隔符为 ;
|
||||
// sqlStatement = strings.ReplaceAll(sqlStatement, ";;", ";")
|
||||
// } else {
|
||||
// // 忽略自定义分隔符行
|
||||
// continue
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 这里可以添加逻辑来忽略空行或注释行
|
||||
// if sqlStatement == "" || sqlStatement[:2] == "--" || sqlStatement[:2] == "/*" {
|
||||
// continue
|
||||
// }
|
||||
//
|
||||
// query += sqlStatement
|
||||
//
|
||||
// if strings.HasSuffix(strings.TrimSpace(sqlStatement), ";") {
|
||||
//
|
||||
// result = append(result, query)
|
||||
//
|
||||
// query = ""
|
||||
// } else {
|
||||
// query += "" // 添加空格以便连接多行语句
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 检查扫描过程中是否有错误
|
||||
// if err := scanner.Err(); err != nil {
|
||||
// executeError := fmt.Sprintf("[MysqlSqlFileLoad] - jackeyLoveFile %s 文件加载错误! 错误信息: %s", jackeyLove.Name(), err.Error())
|
||||
// log.Error(executeError)
|
||||
//
|
||||
//
|
||||
// }
|
||||
//
|
||||
// return result
|
||||
//}
|
||||
//
|
||||
//func MySqlConnection(jackeyLoveIp string, jackeyLovePort string) (bool, []string) {
|
||||
//
|
||||
// dsn := "root:QzfXQhd3bQ@tcp(" + jackeyLoveIp + ":33306)/"
|
||||
// db, err := sql.Open("mysql", dsn)
|
||||
// if err != nil {
|
||||
// errConnect := fmt.Sprintf("[MysqlSqlFileLoad]- mysql connection error ! please check ! => %s error is %s ", dsn, err.Error())
|
||||
// log.Error(errConnect)
|
||||
// return false, []string{
|
||||
// errConnect,
|
||||
// }
|
||||
// }
|
||||
// defer db.Close()
|
||||
//
|
||||
// // 确保数据库连接是有效的
|
||||
// if err := db.Ping(); err != nil {
|
||||
// errConnect := "[MysqlSqlFileLoad]- mysql ping error ! please check !"
|
||||
// log.Error(errConnect)
|
||||
// return false, []string{
|
||||
// errConnect,
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return true, nil
|
||||
//}
|
||||
18
agent-go/a_executor/MySqlFunction_test.go
Normal file
18
agent-go/a_executor/MySqlFunction_test.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package a_executor
|
||||
|
||||
//func TestMySqlConnection(t *testing.T) {
|
||||
//
|
||||
// connection, strings := MySqlConnection("10.250.0.126", "33306")
|
||||
// if !connection {
|
||||
// t.Error(strings)
|
||||
// }
|
||||
//
|
||||
// println("success!")
|
||||
//}
|
||||
//
|
||||
//func TestMySqlParseSQLFile(t *testing.T) {
|
||||
//
|
||||
// parseSQLFile := MySqlParseSQLFile("C:\\Users\\wdd\\Documents\\4.1.6-部署\\init_5.1.0\\1_all_tables_demo_5.1.0.sql")
|
||||
//
|
||||
// BasicPrettyPrint(true, parseSQLFile)
|
||||
//}
|
||||
53
agent-go/a_executor/WindowsFunction.go
Normal file
53
agent-go/a_executor/WindowsFunction.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package a_executor
|
||||
|
||||
//import (
|
||||
// "fmt"
|
||||
// "os/exec"
|
||||
// "strings"
|
||||
// "syscall"
|
||||
// "unsafe"
|
||||
//)
|
||||
//
|
||||
//var (
|
||||
// user32DLL = syscall.NewLazyDLL("user32.dll")
|
||||
//
|
||||
// messageBox = user32DLL.NewProc("MessageBoxW")
|
||||
//)
|
||||
//
|
||||
//func FindPublicIpAddress() {
|
||||
//
|
||||
// cmd := exec.Command("curl", "ifconfig.io")
|
||||
// output, err := cmd.Output()
|
||||
// if err != nil {
|
||||
// fmt.Println("无法获取公网IP地址:", err)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// ip := strings.TrimSpace(string(output))
|
||||
// fmt.Println("公网IP地址:", ip)
|
||||
//
|
||||
// fmt.Println("")
|
||||
//}
|
||||
//
|
||||
//func CallAgent() {
|
||||
// var (
|
||||
// hWnd uintptr
|
||||
// text = "Hello, World!"
|
||||
// caption = "Golang Win32API"
|
||||
// flags = uint(0x00000001) // MB_OK
|
||||
// )
|
||||
//
|
||||
// ret, _, err := messageBox.Call(
|
||||
// hWnd,
|
||||
// uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))),
|
||||
// uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(caption))),
|
||||
// uintptr(flags),
|
||||
// )
|
||||
// if ret == 0 {
|
||||
// fmt.Println("MessageBox failed:", err)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// fmt.Println("MessageBox returned:", ret)
|
||||
//
|
||||
//}
|
||||
8
agent-go/a_executor/WindowsFunction_test.go
Normal file
8
agent-go/a_executor/WindowsFunction_test.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package a_executor
|
||||
|
||||
//import "testing"
|
||||
//
|
||||
//func TestCallAgent(t *testing.T) {
|
||||
//
|
||||
// FindPublicIpAddress()
|
||||
//}
|
||||
25
agent-go/a_executor/script/123
Normal file
25
agent-go/a_executor/script/123
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
______ __ ______ __
|
||||
/ \ | \ / \ | \
|
||||
| $$$$$$\ _______ _| $$_ ______ ______ __ __ _______ | $$$$$$\ ______ ______ _______ _| $$_
|
||||
| $$ | $$/ | $$ \ / \ / \| \ | \/ \ | $$__| $$/ \ / \| | $$ \
|
||||
| $$ | $| $$$$$$$\$$$$$$ | $$$$$$| $$$$$$| $$ | $| $$$$$$$ | $$ $| $$$$$$| $$$$$$| $$$$$$$\$$$$$$
|
||||
| $$ | $| $$ | $$ __| $$ | $| $$ | $| $$ | $$\$$ \ | $$$$$$$| $$ | $| $$ $| $$ | $$| $$ __
|
||||
| $$__/ $| $$_____ | $$| | $$__/ $| $$__/ $| $$__/ $$_\$$$$$$\ | $$ | $| $$__| $| $$$$$$$| $$ | $$| $$| \
|
||||
\$$ $$\$$ \ \$$ $$\$$ $| $$ $$\$$ $| $$ | $$ | $$\$$ $$\$$ | $$ | $$ \$$ $$
|
||||
\$$$$$$ \$$$$$$$ \$$$$ \$$$$$$| $$$$$$$ \$$$$$$ \$$$$$$$ \$$ \$$_\$$$$$$$ \$$$$$$$\$$ \$$ \$$$$
|
||||
| $$ | \__| $$
|
||||
| $$ \$$ $$
|
||||
\$$ \$$$$$$
|
||||
__ __
|
||||
| \ | \
|
||||
____| $$ ______ ____| $$ ______ __ __ __ ______ _______ ______
|
||||
______ ______ ______ / $$| \ / $$| \ | \ | \ | \| \| \ / \
|
||||
| | | \ | $$$$$$$ \$$$$$$| $$$$$$$ \$$$$$$\ | $$ | $$ | $$ \$$$$$$| $$$$$$$| $$$$$$\
|
||||
\$$$$$$\$$$$$$\$$$$$$ | $$ | $$/ $| $$ | $$/ $$ | $$ | $$ | $$/ $| $$ | $| $$ | $$
|
||||
| $$__| $| $$$$$$| $$__| $| $$$$$$$ | $$_/ $$_/ $| $$$$$$| $$ | $| $$__| $$
|
||||
\$$ $$\$$ $$\$$ $$\$$ $$ \$$ $$ $$\$$ $| $$ | $$\$$ $$
|
||||
\$$$$$$$ \$$$$$$$ \$$$$$$$ \$$$$$$$ \$$$$$\$$$$ \$$$$$$$\$$ \$$_\$$$$$$$
|
||||
| \__| $$
|
||||
\$$ $$
|
||||
\$$$$$$
|
||||
2016
agent-go/a_executor/script/1_node_important.sh
Normal file
2016
agent-go/a_executor/script/1_node_important.sh
Normal file
File diff suppressed because it is too large
Load Diff
12
agent-go/a_executor/script/install_golang_on_host.sh
Normal file
12
agent-go/a_executor/script/install_golang_on_host.sh
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
rm -rf go1.21.6.linux-amd64.tar.gz
|
||||
wget http://10.250.0.100:9000/octopus/go1.21.6.linux-amd64.tar.gz -O go1.21.6.linux-amd64.tar.gz
|
||||
|
||||
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.21.6.linux-amd64.tar.gz
|
||||
sed -i "$ a export PATH=\$PATH:/usr/local/go/bin" /root/.bashrc
|
||||
source /root/.bashrc
|
||||
|
||||
go version
|
||||
go env -w GO111MODULE=on
|
||||
go env -w GOPROXY=https://goproxy.cn,direct
|
||||
2
agent-go/a_executor/script/shutdownFirewall.txt
Normal file
2
agent-go/a_executor/script/shutdownFirewall.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
systemctl stop firewalld
|
||||
systemctl disable firewalld
|
||||
Reference in New Issue
Block a user