[ Agent ] [ Executor ] 初步完成部署的函数功能

This commit is contained in:
zeaslity
2023-08-08 14:25:01 +08:00
parent 8e2eacfa47
commit e5af31bb38
8 changed files with 872 additions and 4 deletions

View File

@@ -197,8 +197,11 @@ func parseAgentServerInfo(agentServerInfoConf string) *register.AgentServerInfo
func BuildAgentOsOperator(agentServerInfo *register.AgentServerInfo) { func BuildAgentOsOperator(agentServerInfo *register.AgentServerInfo) {
// 2023年8月4日 passthrough some key information
ossOfflinePrefix := g.G.AgentConfig.GetString("octopus.agent.executor.ossOfflinePrefix")
// call the init exec function // call the init exec function
agentOsOperator := executor.BuildAgentOsOperator(agentServerInfo.OSInfo) agentOsOperator := executor.BuildAgentOsOperator(agentServerInfo.OSInfo, ossOfflinePrefix)
// assign the agentServerInfo // assign the agentServerInfo
agentOsOperator.AgentServerInfo = agentServerInfo agentOsOperator.AgentServerInfo = agentServerInfo

View File

@@ -0,0 +1,804 @@
package executor
import (
"os/exec"
"time"
)
type AppFunc interface {
Deploy(appFuncName string, funcArgs ...string) []string
}
var AppExecuteErrorLogPrefix = []string{"App指令执行错误 => "}
func (op *AgentOsOperator) Deploy(appFuncName string, funcArgs ...string) (bool, []string) {
var resultOK bool
var result []string
switch appFuncName {
case "deployMinio":
resultOK, result = op.deployMinio(funcArgs)
break
case "deployNFS":
resultOK, result = op.deployNFS(funcArgs)
break
case "testNFS":
resultOK, result = op.testNFS(funcArgs)
break
case "deployPVC":
resultOK, result = op.deployPVC(funcArgs)
break
case "deploySC":
break
case "deployMySQL":
resultOK, result = op.deployMySQL(funcArgs)
break
case "checkMySQL":
resultOK, result = op.checkMySQL(funcArgs)
break
case "deployMiddlewares":
resultOK, result = op.deployMiddlewares(funcArgs)
break
case "deployRedis":
resultOK, result = op.deployRedis(funcArgs)
break
case "deployIngress":
resultOK, result = op.deployIngress(funcArgs)
break
case "deployFront":
resultOK, result = op.deployFront(funcArgs)
break
case "initMinio":
resultOK, result = op.initMinio(funcArgs)
break
case "deploySRS":
resultOK, result = op.deploySRS(funcArgs)
break
case "deployGDR":
resultOK, result = op.deployGDR(funcArgs)
break
case "modifyNacos":
resultOK, result = op.modifyNacos(funcArgs)
break
case "deployBackend":
resultOK, result = op.deployBackend(funcArgs)
break
default:
op.ok(funcArgs)
}
// debug
log.DebugF("app deploy of %s result is %v", appFuncName, result)
return resultOK, result
}
// 通用命令脚本
// BaseCommandExists 判定命令是否存在
func BaseCommandExists(commandName string) bool {
cmd := exec.Command("command", "-v", commandName)
err := cmd.Run()
if err != nil {
log.DebugF("指令 %s 不存在", commandName)
return false
} else {
return true
}
}
// BaseCommandExistsBatch 判定批量命令是否存在
func BaseCommandExistsBatch(commandNameList []string) (bool, string) {
for _, commandName := range commandNameList {
if !BaseCommandExists(commandName) {
return false, commandName
}
}
return true, ""
}
// BaseReplace 基础替换命令
func BaseReplace(filename string, origin string, replace string) bool {
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 BaseFileExists(filename string) bool {
cmd := exec.Command("test", "-f", filename)
err := cmd.Run()
if err != nil {
log.DebugF("文件 %s 不存在!", filename)
return false
} else {
return true
}
}
// 通用命令脚本
func (op *AgentOsOperator) deployMinio(funcArgs []string) (bool, []string) {
minioTemplateFileName := "minio-docker-compose.yaml"
result := append(AppExecuteErrorLogPrefix, "部署MINIO")
// 逻辑为接收执行,但是会报错
// 环境判定
commandExist, commandName := BaseCommandExistsBatch([]string{
"docker-compose",
})
if !commandExist {
result = append(result, "命令不存在", commandName)
return false, result
}
// 磁盘空间足够
// 目录存在
// 下载模板文件
if !PureResultSingleExecute([]string{
"wget",
"-q",
op.OssOfflinePrefix + "/" + minioTemplateFileName,
}) {
result = append(result, "下载模板文件")
return false, result
}
// 根据参数 A1C2IP 替换
if !BaseReplace(minioTemplateFileName, "A1C2IP", funcArgs[0]) {
result = append(result, "替换IP信息")
return false, result
}
// 启动服务
if !PureResultSingleExecute([]string{
"docker-compose",
"-f",
minioTemplateFileName,
"up",
"-d",
}) {
result = append(result, "启动minio失败!")
return false, result
}
// 成功启动
return true, []string{
"MINIO安装成功!",
"输入如下命令查看启动情况: ",
"docker-compose logs minio1",
}
}
func (op *AgentOsOperator) deployNFS(funcArgs []string) (bool, []string) {
nfsTemplateFile := "nfs-template.yaml"
result := append(AppExecuteErrorLogPrefix, "部署NFS")
nfsDataPath := "/nfsdata"
// 环境判定
commandExist, commandName := BaseCommandExistsBatch([]string{
"kubectl",
})
if !commandExist {
result = append(result, "命令不存在", commandName)
return false, result
}
// 创建目录修改权限
if !PureResultSingleExecuteBatch([][]string{
{"mkdir", "-p", nfsDataPath},
{"chmod", "777", nfsDataPath},
}) {
result = append(result, "目录不存在", nfsDataPath)
return false, result
}
// 下载模板文件
if !PureResultSingleExecute([]string{
"wget",
"-q",
op.OssOfflinePrefix + "/" + nfsTemplateFile,
}) {
result = append(result, "下载模板文件")
return false, result
}
// 根据参数 A1C2IP 替换
if !BaseReplace(nfsTemplateFile, "N1C2IP", funcArgs[0]) {
result = append(result, "替换IP信息")
return false, result
}
// 启动服务
if !PureResultSingleExecute([]string{
"kubectl",
"apply",
"-f",
nfsTemplateFile,
}) {
result = append(result, "启动NFS失败!")
return false, result
}
// 成功启动
return true, []string{
"NFS部署成功!",
}
}
func (op *AgentOsOperator) testNFS(funcArgs []string) (bool, []string) {
nfsTemplateFile := "nfs-test-template.yaml"
result := append(AppExecuteErrorLogPrefix, "测试NFS部署")
// 环境判定
commandExist, commandName := BaseCommandExistsBatch([]string{
"kubectl",
})
if !commandExist {
result = append(result, "命令不存在", commandName)
return false, result
}
// 下载模板文件
if !PureResultSingleExecute([]string{
"wget",
"-q",
op.OssOfflinePrefix + "/" + nfsTemplateFile,
}) {
result = append(result, "下载模板文件")
return false, result
}
// 根据参数 A1C2IP 替换
if !BaseReplace(nfsTemplateFile, "N1C2IP", funcArgs[0]) {
result = append(result, "替换IP信息")
return false, result
}
// 启动服务
if !PureResultSingleExecute([]string{
"kubectl",
"apply",
"-f",
nfsTemplateFile,
}) {
result = append(result, "启动NFS-TEST失败!")
return false, result
}
// 测试文件是否存在
if !BaseFileExists("/nfsdata/test-pod*/NFS-CREATE-SUCCESS") {
result = append(result, "NFS 测试功能 异常!!")
return false, result
}
// 成功启动
return true, []string{
"NFS 测试功能正常!",
}
}
func (op *AgentOsOperator) deployPVC(funcArgs []string) (bool, []string) {
pvcTemplateFile := "pvc-template.yaml"
result := append(AppExecuteErrorLogPrefix, "部署PVC")
// 环境判定
commandExist, commandName := BaseCommandExistsBatch([]string{
"kubectl",
})
if !commandExist {
result = append(result, "命令不存在", commandName)
return false, result
}
// 下载模板文件
if !PureResultSingleExecute([]string{
"wget",
"-q",
op.OssOfflinePrefix + "/" + pvcTemplateFile,
}) {
result = append(result, "下载模板文件")
return false, result
}
// 根据参数 A1C2IP 替换
if !BaseReplace(pvcTemplateFile, "SUPREME", funcArgs[0]) {
result = append(result, "替换SUPREME信息")
return false, result
}
// 启动服务
if !PureResultSingleExecute([]string{
"kubectl",
"apply",
"-f",
pvcTemplateFile,
}) {
result = append(result, "创建PVC失败!")
return false, result
}
// 成功启动
return true, []string{
"PVC部署成功",
}
}
func (op *AgentOsOperator) deployMySQL(funcArgs []string) (bool, []string) {
mysqlTemplate := "mysql-template.yaml"
result := append(AppExecuteErrorLogPrefix, "部署 MySQL !")
// 环境判定
commandExist, commandName := BaseCommandExistsBatch([]string{
"kubectl",
})
if !commandExist {
result = append(result, "命令不存在", commandName)
return false, result
}
// 下载模板文件
if !PureResultSingleExecute([]string{
"wget",
"-q",
op.OssOfflinePrefix + "/" + mysqlTemplate,
}) {
result = append(result, "下载模板文件")
return false, result
}
// 根据参数 A1C2IP 替换
if !BaseReplace(mysqlTemplate, "SUPREME", funcArgs[0]) {
result = append(result, "替换SUPREME信息")
return false, result
}
if !BaseReplace(mysqlTemplate, "A1C2IP", funcArgs[1]) {
result = append(result, "替换A1C2IP信息")
return false, result
}
// 启动服务
if !PureResultSingleExecute([]string{
"kubectl",
"apply",
"-f",
mysqlTemplate,
}) {
result = append(result, "创建MySQL失败!")
return false, result
}
// 成功启动
return true, []string{
"MySQL部署成功",
}
}
func (op *AgentOsOperator) checkMySQL(funcArgs []string) (bool, []string) {
// 设置超时时间为 120 秒
timeout := time.After(120 * time.Second)
for {
select {
case <-timeout:
msg := "检查MySQL时间Pod的运行状态超时! 120s"
log.Error(msg)
return false, []string{msg}
default:
msg := "MySQL Pod已经启动!"
if CheckPodStatus("helm-mysql-0", funcArgs[0]) {
log.Info(msg)
return true, []string{msg}
}
}
// 每隔5s检查一次
time.Sleep(5 * time.Second)
}
}
func (op *AgentOsOperator) deployMiddlewares(funcArgs []string) (bool, []string) {
middlewaresTemplate := "middleware-template.yaml"
result := append(AppExecuteErrorLogPrefix, "部署 所有的中间件 !")
// 环境判定
commandExist, commandName := BaseCommandExistsBatch([]string{
"kubectl",
})
if !commandExist {
result = append(result, "命令不存在", commandName)
return false, result
}
// 下载模板文件
if !PureResultSingleExecute([]string{
"wget",
"-q",
op.OssOfflinePrefix + "/" + middlewaresTemplate,
}) {
result = append(result, "下载模板文件")
return false, result
}
// 根据参数 A1C2IP 替换
if !BaseReplace(middlewaresTemplate, "SUPREME", funcArgs[0]) {
result = append(result, "替换SUPREME信息")
return false, result
}
if !BaseReplace(middlewaresTemplate, "A1C2IP", funcArgs[1]) {
result = append(result, "替换A1C2IP信息")
return false, result
}
// 启动服务
if !PureResultSingleExecute([]string{
"kubectl",
"apply",
"-f",
middlewaresTemplate,
}) {
result = append(result, "创建 中间件 失败!")
return false, result
}
// 成功启动
return true, []string{
"中间件部署成功!",
}
}
func (op *AgentOsOperator) deployRedis(funcArgs []string) (bool, []string) {
redisTemplate := "redis-template.yaml"
result := append(AppExecuteErrorLogPrefix, "部署 redis !")
// 环境判定
commandExist, commandName := BaseCommandExistsBatch([]string{
"kubectl",
})
if !commandExist {
result = append(result, "命令不存在", commandName)
return false, result
}
// 下载模板文件
if !PureResultSingleExecute([]string{
"wget",
"-q",
op.OssOfflinePrefix + "/" + redisTemplate,
}) {
result = append(result, "下载模板文件")
return false, result
}
// 根据参数 A1C2IP 替换
if !BaseReplace(redisTemplate, "SUPREME", funcArgs[0]) {
result = append(result, "替换SUPREME信息")
return false, result
}
if !BaseReplace(redisTemplate, "A1C2IP", funcArgs[1]) {
result = append(result, "替换A1C2IP信息")
return false, result
}
// 启动服务
if !PureResultSingleExecute([]string{
"kubectl",
"apply",
"-f",
redisTemplate,
}) {
result = append(result, "创建 Redis 失败!")
return false, result
}
// 成功启动
return true, []string{
"Redis 部署成功!",
}
}
func (op *AgentOsOperator) deployIngress(funcArgs []string) (bool, []string) {
ingressTemplate := "ingress-template.yaml"
result := append(AppExecuteErrorLogPrefix, "部署 Ingress !")
// 环境判定
commandExist, commandName := BaseCommandExistsBatch([]string{
"kubectl",
})
if !commandExist {
result = append(result, "命令不存在", commandName)
return false, result
}
// 下载模板文件
if !PureResultSingleExecute([]string{
"wget",
"-q",
op.OssOfflinePrefix + "/" + ingressTemplate,
}) {
result = append(result, "下载模板文件")
return false, result
}
// 根据参数 A1C2IP 替换
if !BaseReplace(ingressTemplate, "SUPREME", funcArgs[0]) {
result = append(result, "替换SUPREME信息")
return false, result
}
if !BaseReplace(ingressTemplate, "A1C2IP", funcArgs[1]) {
result = append(result, "替换A1C2IP信息")
return false, result
}
if !BaseReplace(ingressTemplate, "A1C1JS", funcArgs[1]) {
result = append(result, "替换A1C1JS信息")
return false, result
}
// 启动服务
if !PureResultSingleExecute([]string{
"kubectl",
"apply",
"-f",
ingressTemplate,
}) {
result = append(result, "创建 Ingress 失败!")
return false, result
}
// 成功启动
return true, []string{
"Ingress 部署成功!",
}
}
func (op *AgentOsOperator) deployFront(funcArgs []string) (bool, []string) {
fontTemplate := "front-template.yaml"
result := append(AppExecuteErrorLogPrefix, "部署 前端服务 !")
// 环境判定
commandExist, commandName := BaseCommandExistsBatch([]string{
"kubectl",
})
if !commandExist {
result = append(result, "命令不存在", commandName)
return false, result
}
// 下载模板文件
if !PureResultSingleExecute([]string{
"wget",
"-q",
op.OssOfflinePrefix + "/" + fontTemplate,
}) {
result = append(result, "下载模板文件")
return false, result
}
// 根据参数 A1C2IP 替换
if !BaseReplace(fontTemplate, "SUPREME", funcArgs[0]) {
result = append(result, "替换SUPREME信息")
return false, result
}
if !BaseReplace(fontTemplate, "A1C2IP", funcArgs[1]) {
result = append(result, "替换A1C2IP信息")
return false, result
}
// 启动服务
if !PureResultSingleExecute([]string{
"kubectl",
"apply",
"-f",
fontTemplate,
}) {
result = append(result, "创建 前端服务 失败!")
return false, result
}
// 成功启动
return true, []string{
"前端服务 部署成功!",
}
}
func (op *AgentOsOperator) initMinio(funcArgs []string) (bool, []string) {
initMinioTemplate := "minio-init.sh"
result := append(AppExecuteErrorLogPrefix, "进行MINIO初始化服务 !")
// 环境判定
commandExist, commandName := BaseCommandExistsBatch([]string{
"kubectl",
})
if !commandExist {
result = append(result, "命令不存在", commandName)
return false, result
}
// 下载模板文件
if !PureResultSingleExecute([]string{
"wget",
"-q",
op.OssOfflinePrefix + "/" + initMinioTemplate,
}) {
result = append(result, "下载模板文件")
return false, result
}
// 根据参数 A1C2IP 替换
if !BaseReplace(initMinioTemplate, "SUPREME", funcArgs[0]) {
result = append(result, "替换SUPREME信息")
return false, result
}
if !BaseReplace(initMinioTemplate, "A1C2IP", funcArgs[1]) {
result = append(result, "替换A1C2IP信息")
return false, result
}
if !BaseReplace(initMinioTemplate, "M2D2IP", funcArgs[1]) {
result = append(result, "替换A1C2IP信息")
return false, result
}
// 启动服务
if !PureResultSingleExecute([]string{
"kubectl",
"apply",
"-f",
initMinioTemplate,
}) {
result = append(result, "MINIO 初始化 失败!")
return false, result
}
// 成功启动
return true, []string{
"MINIO 初始化 成功!",
}
}
func (op *AgentOsOperator) deploySRS(funcArgs []string) (bool, []string) {
srsTemplate := "srs-template.yaml"
result := append(AppExecuteErrorLogPrefix, "开始部署SRS服务")
// 环境判定
commandExist, commandName := BaseCommandExistsBatch([]string{
"kubectl",
})
if !commandExist {
result = append(result, "命令不存在", commandName)
return false, result
}
// 下载模板文件
if !PureResultSingleExecute([]string{
"wget",
"-q",
op.OssOfflinePrefix + "/" + srsTemplate,
}) {
result = append(result, "下载模板文件")
return false, result
}
// 根据参数 A1C2IP 替换
if !BaseReplace(srsTemplate, "SUPREME", funcArgs[0]) {
result = append(result, "替换SUPREME信息")
return false, result
}
if !BaseReplace(srsTemplate, "A1C2IP", funcArgs[1]) {
result = append(result, "替换A1C2IP信息")
return false, result
}
if !BaseReplace(srsTemplate, "A1C1JS", funcArgs[1]) {
result = append(result, "替换A1C1JS信息")
return false, result
}
if !BaseReplace(srsTemplate, "M2D2IP", funcArgs[1]) {
result = append(result, "替换M2D2IP信息")
return false, result
}
// 启动服务
if !PureResultSingleExecute([]string{
"kubectl",
"apply",
"-f",
srsTemplate,
}) {
result = append(result, "部署 SRS 失败!")
return false, result
}
// 成功启动
return true, []string{
"部署 SRS 成功!",
}
}
func (op *AgentOsOperator) deployGDR(funcArgs []string) (bool, []string) {
return true, []string{
"请手动进行GDR的部署工作",
}
}
func (op *AgentOsOperator) modifyNacos(funcArgs []string) (bool, []string) {
log.Info("请开始进行Nacos的配置修改工作")
log.Info("请开始进行Nacos的配置修改工作")
after := time.After(120 * time.Second)
<-after
msg := "等待Nacos的配置结束"
log.Info(msg)
return true, []string{msg}
}
func (op *AgentOsOperator) deployBackend(funcArgs []string) (bool, []string) {
backendTemplate := "backend-template.yaml"
result := append(AppExecuteErrorLogPrefix, "部署 后端 服务 !")
// 环境判定
commandExist, commandName := BaseCommandExistsBatch([]string{
"kubectl",
})
if !commandExist {
result = append(result, "命令不存在", commandName)
return false, result
}
// 下载模板文件
if !PureResultSingleExecute([]string{
"wget",
"-q",
op.OssOfflinePrefix + "/" + backendTemplate,
}) {
result = append(result, "下载模板文件")
return false, result
}
// 根据参数 A1C2IP 替换
if !BaseReplace(backendTemplate, "SUPREME", funcArgs[0]) {
result = append(result, "替换SUPREME信息")
return false, result
}
if !BaseReplace(backendTemplate, "A1C2IP", funcArgs[1]) {
result = append(result, "替换A1C2IP信息")
return false, result
}
// 启动服务
if !PureResultSingleExecute([]string{
"kubectl",
"apply",
"-f",
backendTemplate,
}) {
result = append(result, "创建 后端服务 失败!")
return false, result
}
// 成功启动
return true, []string{
"后端服务 部署成功!",
}
}

View File

@@ -27,6 +27,9 @@ type AgentOsOperator struct {
AgentOSReleaseCode string `json:"agent_os_release_code",comment:"主机操作系统的发行版代号, focal之类的"` AgentOSReleaseCode string `json:"agent_os_release_code",comment:"主机操作系统的发行版代号, focal之类的"`
AgentServerInfo *register.AgentServerInfo `json:"agent_server_info"` AgentServerInfo *register.AgentServerInfo `json:"agent_server_info"`
// 离线下载URL地址
OssOfflinePrefix string
} }
// Exec 执行基础功能函数 // Exec 执行基础功能函数
@@ -86,7 +89,6 @@ func (op *AgentOsOperator) Exec(baseFuncName string, funcArgs ...string) []strin
break break
default: default:
multiLineCommand = op.ok(funcArgs) multiLineCommand = op.ok(funcArgs)
} }
log.DebugF("multiLineCommand are => %v", multiLineCommand) log.DebugF("multiLineCommand are => %v", multiLineCommand)
@@ -95,7 +97,10 @@ func (op *AgentOsOperator) Exec(baseFuncName string, funcArgs ...string) []strin
// exec the command here // exec the command here
for _, singleLineCommand := range multiLineCommand { for _, singleLineCommand := range multiLineCommand {
result = append(result, AllOutputCommandExecutor(singleLineCommand)...) singleCommandResult := AllOutputCommandExecutor(singleLineCommand)
result = append(result, "")
result = append(result, singleCommandResult...)
// debug usage // debug usage
log.DebugF("exec result are => %v", result) log.DebugF("exec result are => %v", result)

View File

@@ -31,6 +31,7 @@ func ReadTimeCommandExecutor(singleLineCommand []string) {
} }
// AllOutputCommandExecutor 收集全部执行结果、错误并且返回
func AllOutputCommandExecutor(singleLineCommand []string) []string { func AllOutputCommandExecutor(singleLineCommand []string) []string {
cmd := exec.Command(singleLineCommand[0], singleLineCommand[1:]...) cmd := exec.Command(singleLineCommand[0], singleLineCommand[1:]...)
@@ -79,3 +80,29 @@ func collectOutput(r io.Reader, resultSlice []string) []string {
return resultSlice return resultSlice
} }
// PureResultSingleExecute 执行单行命令,忽略输出,只对执行成功与否负责
func PureResultSingleExecute(singleCommand []string) bool {
cmd := exec.Command(singleCommand[0], singleCommand[1:]...)
err := cmd.Run()
if err != nil {
log.DebugF("指令 %s 执行 错误", singleCommand)
return false
} else {
log.DebugF("指令 %s 执行 成功", singleCommand)
return true
}
}
// PureResultSingleExecuteBatch 批量 执行单行命令,忽略输出,只对执行成功与否负责
func PureResultSingleExecuteBatch(singleCommandList [][]string) bool {
for _, singleCommand := range singleCommandList {
if !PureResultSingleExecute(singleCommand) {
return false
}
}
return true
}

View File

@@ -2,7 +2,7 @@ package executor
import "strings" import "strings"
func BuildAgentOsOperator(osInfo string) *AgentOsOperator { func BuildAgentOsOperator(osInfo string, ossOfflinePrefix string) *AgentOsOperator {
AgentOsOperatorCache = &AgentOsOperator{ AgentOsOperatorCache = &AgentOsOperator{
InstallCommandPrefix: []string{ InstallCommandPrefix: []string{
@@ -15,6 +15,7 @@ func BuildAgentOsOperator(osInfo string) *AgentOsOperator {
AgentArch: "amd64", AgentArch: "amd64",
AgentOSReleaseCode: "focal", AgentOSReleaseCode: "focal",
AgentServerInfo: nil, AgentServerInfo: nil,
OssOfflinePrefix: ossOfflinePrefix,
} }
// os type // os type

View File

@@ -0,0 +1,27 @@
package executor
import "strings"
var configFilePath = "/root/.kube/config"
func CheckPodStatus(specific string, supreme string) bool {
if !BaseCommandExists("kubectl") {
log.Error("kubectl命令不存在无法查看Pod状态请查看")
}
executor, err := SingleLineCommandExecutor([]string{
"kubectl", "-n", supreme, "get", "pod", specific, "-o", "jsonpath='{.status.phase}'",
})
if err != nil {
return false
}
for _, resultLine := range executor {
if strings.HasPrefix(resultLine, "Running") {
return true
}
}
return false
}

View File

@@ -37,6 +37,7 @@ octopus:
executor: executor:
# agent执行一条Command的最长超时时间 # agent执行一条Command的最长超时时间
processMaxTimeOut: 60 processMaxTimeOut: 60
ossOfflinePrefix: https://b2.107421.xyz
status: status:
app: app:
- Nginx/nginx - Nginx/nginx