[ Agent ] [ APP ] - nfs mysql redis middleware

This commit is contained in:
zeaslity
2023-11-21 16:17:13 +08:00
parent b4c44c7396
commit 48e8a6c951
5 changed files with 225 additions and 156 deletions

View File

@@ -1,6 +1,7 @@
package executor package executor
import ( import (
"fmt"
"net" "net"
"time" "time"
) )
@@ -17,6 +18,7 @@ type AppFunc interface {
} }
var AppExecuteErrorLogPrefix = []string{"App指令执行错误 => "} var AppExecuteErrorLogPrefix = []string{"App指令执行错误 => "}
var nfsDataPath = "/var/lib/docker/nfs_data"
func (op *AgentOsOperator) Deploy(appFuncName string, funcArgs ...string) (bool, []string) { func (op *AgentOsOperator) Deploy(appFuncName string, funcArgs ...string) (bool, []string) {
@@ -30,14 +32,17 @@ func (op *AgentOsOperator) Deploy(appFuncName string, funcArgs ...string) (bool,
case "DEPLOY_K8S_DASHBOARD": case "DEPLOY_K8S_DASHBOARD":
resultOK, result = op.deployK8sDashboard(funcArgs) resultOK, result = op.deployK8sDashboard(funcArgs)
break break
case "DEPLOY_K8S_NAMESPACE":
resultOK, result = op.deployK8sNamespace(funcArgs)
break
case "DEPLOY_MINIO": case "DEPLOY_MINIO":
resultOK, result = op.deployMinio(funcArgs) resultOK, result = op.deployMinio(funcArgs)
break break
case "DEPLOY_NFS": case "DEPLOY_NFS":
resultOK, result = op.deployNFS(funcArgs) resultOK, result = op.deployNFS(funcArgs)
break break
case "testNFS": case "DEPLOY_TEST_NFS":
resultOK, result = op.testNFS(funcArgs) resultOK, result = op.deployTestNFS(funcArgs)
break break
case "deployPVC": case "deployPVC":
resultOK, result = op.deployPVC(funcArgs) resultOK, result = op.deployPVC(funcArgs)
@@ -202,6 +207,19 @@ func (op *AgentOsOperator) deployK8sDashboard(funcArgs []string) (bool, []string
return true, nil return true, nil
} }
func (op *AgentOsOperator) deployK8sNamespace(funcArgs []string) (bool, []string) {
if !CreateK8sNamespace(funcArgs[1]) {
return false, []string{
fmt.Sprintf("Namespace of %s create error!", funcArgs[1]),
}
}
return true, []string{
fmt.Sprintf("Namespace of %s create success !", funcArgs[1]),
}
}
func (op *AgentOsOperator) deployMinio(funcArgs []string) (bool, []string) { func (op *AgentOsOperator) deployMinio(funcArgs []string) (bool, []string) {
minioTemplateFileName := "minio-docker-compose.yaml" minioTemplateFileName := "minio-docker-compose.yaml"
result := append(AppExecuteErrorLogPrefix, "部署MINIO") result := append(AppExecuteErrorLogPrefix, "部署MINIO")
@@ -255,16 +273,12 @@ func (op *AgentOsOperator) deployMinio(funcArgs []string) (bool, []string) {
func (op *AgentOsOperator) deployNFS(funcArgs []string) (bool, []string) { func (op *AgentOsOperator) deployNFS(funcArgs []string) (bool, []string) {
nfsTemplateFile := "nfs-template.yaml" nfsTemplateFile := "k8s-nfs-template.yaml"
result := append(AppExecuteErrorLogPrefix, "部署NFS") result := append(AppExecuteErrorLogPrefix, "部署NFS")
nfsDataPath := "/nfsdata"
// 环境判定 // 环境判定
commandExist, commandName := BasicCommandExistsBatch([]string{ if !BasicCommandExistByPath("kubectl") {
"kubectl", result = append(result, "命令不存在", "kubectl")
})
if !commandExist {
result = append(result, "命令不存在", commandName)
return false, result return false, result
} }
// 创建目录修改权限 // 创建目录修改权限
@@ -277,29 +291,27 @@ func (op *AgentOsOperator) deployNFS(funcArgs []string) (bool, []string) {
} }
// 下载模板文件 // 下载模板文件
if !PureResultSingleExecute([]string{ k8sNFSYamlFile := "/root/wdd/install/k8s-nfs.yaml"
"wget", ok, resultLog := BasicDownloadFile(op.OssOfflinePrefix+nfsTemplateFile, k8sNFSYamlFile)
"-q", if !ok {
op.OssOfflinePrefix + "/" + nfsTemplateFile, return false, resultLog
}) {
result = append(result, "下载模板文件")
return false, result
} }
// 根据参数 A1C2IP 替换 // 根据参数 A1C2IP 替换
if !BasicReplace(nfsTemplateFile, "N1C2IP", funcArgs[0]) { ip := net.ParseIP(funcArgs[0])
if ip == nil {
return false, append(result,
"ip args error !")
}
if !BasicReplace(k8sNFSYamlFile, "N1C2IP", funcArgs[0]) {
result = append(result, "替换IP信息") result = append(result, "替换IP信息")
return false, result return false, result
} }
// 启动服务 // 启动服务
if !PureResultSingleExecute([]string{ exec, strings := KubectlApplyExec(k8sNFSYamlFile)
"kubectl", if !exec {
"apply", return false, strings
"-f",
nfsTemplateFile,
}) {
result = append(result, "启动NFS失败!")
return false, result
} }
// 成功启动 // 成功启动
@@ -308,48 +320,43 @@ func (op *AgentOsOperator) deployNFS(funcArgs []string) (bool, []string) {
} }
} }
func (op *AgentOsOperator) testNFS(funcArgs []string) (bool, []string) { func (op *AgentOsOperator) deployTestNFS(funcArgs []string) (bool, []string) {
nfsTemplateFile := "nfs-test-template.yaml" nfsTemplateFile := "k8s-nfs-test-template.yaml"
result := append(AppExecuteErrorLogPrefix, "测试NFS部署") result := append(AppExecuteErrorLogPrefix, "测试NFS部署")
// 环境判定 // 环境判定
commandExist, commandName := BasicCommandExistsBatch([]string{ if !BasicCommandExistByPath("kubectl") {
"kubectl", result = append(result, "命令不存在", "kubectl")
})
if !commandExist {
result = append(result, "命令不存在", commandName)
return false, result return false, result
} }
// 下载模板文件 // 下载模板文件
if !PureResultSingleExecute([]string{ k8sNFSYamlFile := "/root/wdd/install/k8s-nfs-test.yaml"
"wget", ok, resultLog := BasicDownloadFile(op.OssOfflinePrefix+nfsTemplateFile, k8sNFSYamlFile)
"-q", if !ok {
op.OssOfflinePrefix + "/" + nfsTemplateFile, return false, resultLog
}) {
result = append(result, "下载模板文件")
return false, result
} }
// 根据参数 A1C2IP 替换 // 根据参数 A1C2IP 替换
if !BasicReplace(nfsTemplateFile, "N1C2IP", funcArgs[0]) { ip := net.ParseIP(funcArgs[0])
if ip == nil {
return false, append(result,
"ip args error !")
}
if !BasicReplace(k8sNFSYamlFile, "N1C2IP", funcArgs[0]) {
result = append(result, "替换IP信息") result = append(result, "替换IP信息")
return false, result return false, result
} }
// 启动服务 // 启动服务
if !PureResultSingleExecute([]string{ // 启动服务
"kubectl", exec, strings := KubectlApplyExec(k8sNFSYamlFile)
"apply", if !exec {
"-f", return false, strings
nfsTemplateFile,
}) {
result = append(result, "启动NFS-TEST失败!")
return false, result
} }
// 测试文件是否存在 // 测试文件是否存在
if !BasicFileExists("/nfsdata/test-pod*/NFS-CREATE-SUCCESS") { if !BasicFileExists(nfsDataPath + "/test-pod*/NFS-CREATE-SUCCESS") {
result = append(result, "NFS 测试功能 异常!!") result = append(result, "NFS 测试功能 异常!!")
return false, result return false, result
} }
@@ -362,42 +369,31 @@ func (op *AgentOsOperator) testNFS(funcArgs []string) (bool, []string) {
func (op *AgentOsOperator) deployPVC(funcArgs []string) (bool, []string) { func (op *AgentOsOperator) deployPVC(funcArgs []string) (bool, []string) {
pvcTemplateFile := "pvc-template.yaml" pvcTemplateFile := "k8s-pvc-template.yaml"
result := append(AppExecuteErrorLogPrefix, "部署PVC") result := append(AppExecuteErrorLogPrefix, "部署PVC")
// 环境判定 // 环境判定
commandExist, commandName := BasicCommandExistsBatch([]string{ if !BasicCommandExistByPath("kubectl") {
"kubectl", result = append(result, "命令不存在", "kubectl")
})
if !commandExist {
result = append(result, "命令不存在", commandName)
return false, result return false, result
} }
// 下载模板文件 // 下载模板文件
if !PureResultSingleExecute([]string{ k8sNFSYamlFile := "/root/wdd/install/k8s-pvc.yaml"
"wget", ok, resultLog := BasicDownloadFile(op.OssOfflinePrefix+pvcTemplateFile, k8sNFSYamlFile)
"-q", if !ok {
op.OssOfflinePrefix + "/" + pvcTemplateFile, return false, resultLog
}) {
result = append(result, "下载模板文件")
return false, result
} }
// 根据参数 A1C2IP 替换 // 根据参数 A1C2IP 替换
if !BasicReplace(pvcTemplateFile, "SUPREME", funcArgs[0]) { if !BasicReplace(k8sNFSYamlFile, "SUPREME", funcArgs[1]) {
result = append(result, "替换SUPREME信息") result = append(result, "替换SUPREME信息")
return false, result return false, result
} }
// 启动服务 // 启动服务
if !PureResultSingleExecute([]string{ exec, strings := KubectlApplyExec(k8sNFSYamlFile)
"kubectl", if !exec {
"apply", return false, strings
"-f",
pvcTemplateFile,
}) {
result = append(result, "创建PVC失败!")
return false, result
} }
// 成功启动 // 成功启动
@@ -408,48 +404,44 @@ func (op *AgentOsOperator) deployPVC(funcArgs []string) (bool, []string) {
func (op *AgentOsOperator) deployMySQL(funcArgs []string) (bool, []string) { func (op *AgentOsOperator) deployMySQL(funcArgs []string) (bool, []string) {
mysqlTemplate := "mysql-template.yaml" mysqlTemplate := "k8s-mysql-template.yaml"
result := append(AppExecuteErrorLogPrefix, "部署 MySQL !") result := append(AppExecuteErrorLogPrefix, "部署 MySQL !")
// 环境判定 // 环境判定
commandExist, commandName := BasicCommandExistsBatch([]string{ if !BasicCommandExistByPath("kubectl") {
"kubectl", result = append(result, "命令不存在", "kubectl")
})
if !commandExist {
result = append(result, "命令不存在", commandName)
return false, result return false, result
} }
// 下载模板文件 // 下载模板文件
if !PureResultSingleExecute([]string{ k8sMysqlYamlFile := "/root/wdd/install/k8s-mysql.yaml"
"wget", ok, resultLog := BasicDownloadFile(op.OssOfflinePrefix+mysqlTemplate, k8sMysqlYamlFile)
"-q", if !ok {
op.OssOfflinePrefix + "/" + mysqlTemplate, return false, resultLog
}) {
result = append(result, "下载模板文件")
return false, result
} }
// 根据参数 A1C2IP 替换 // 根据参数 A1C2IP 替换
if !BasicReplace(mysqlTemplate, "SUPREME", funcArgs[0]) { ip := net.ParseIP(funcArgs[0])
result = append(result, "替换SUPREME信息") if ip == nil {
return false, result return false, append(result,
"ip args error !")
} }
if !BasicReplace(mysqlTemplate, "A1C2IP", funcArgs[1]) { if !BasicReplace(k8sMysqlYamlFile, "A1C2IP", funcArgs[0]) {
result = append(result, "替换A1C2IP信息") result = append(result, "替换A1C2IP信息")
return false, result return false, result
} }
// 启动服务 // 替换SUPREME信
if !PureResultSingleExecute([]string{ if !BasicReplace(k8sMysqlYamlFile, "SUPREME", funcArgs[1]) {
"kubectl", result = append(result, "替换SUPREME信息")
"apply",
"-f",
mysqlTemplate,
}) {
result = append(result, "创建MySQL失败!")
return false, result return false, result
} }
// 启动服务
exec, strings := KubectlApplyExec(k8sMysqlYamlFile)
if !exec {
return false, append(result, strings...)
}
// 成功启动 // 成功启动
return true, []string{ return true, []string{
"MySQL部署成功", "MySQL部署成功",
@@ -473,48 +465,44 @@ func (op *AgentOsOperator) checkMySQL(funcArgs []string) (bool, []string) {
func (op *AgentOsOperator) deployMiddlewares(funcArgs []string) (bool, []string) { func (op *AgentOsOperator) deployMiddlewares(funcArgs []string) (bool, []string) {
middlewaresTemplate := "middleware-template.yaml" middlewaresTemplate := "k8s-middleware-template.yaml"
result := append(AppExecuteErrorLogPrefix, "部署 所有的中间件 !") result := append(AppExecuteErrorLogPrefix, "部署 所有的中间件 !")
// 环境判定 // 环境判定
commandExist, commandName := BasicCommandExistsBatch([]string{ if !BasicCommandExistByPath("kubectl") {
"kubectl", result = append(result, "命令不存在", "kubectl")
})
if !commandExist {
result = append(result, "命令不存在", commandName)
return false, result return false, result
} }
// 下载模板文件 // 下载模板文件
if !PureResultSingleExecute([]string{ k8sMiddlewaresYamlFile := "/root/wdd/install/k8s-middlewares.yaml"
"wget", ok, resultLog := BasicDownloadFile(op.OssOfflinePrefix+middlewaresTemplate, k8sMiddlewaresYamlFile)
"-q", if !ok {
op.OssOfflinePrefix + "/" + middlewaresTemplate, return false, resultLog
}) {
result = append(result, "下载模板文件")
return false, result
} }
// 根据参数 A1C2IP 替换 // 根据参数 A1C2IP 替换
if !BasicReplace(middlewaresTemplate, "SUPREME", funcArgs[0]) { ip := net.ParseIP(funcArgs[0])
result = append(result, "替换SUPREME信息") if ip == nil {
return false, result return false, append(result,
"ip args error !")
} }
if !BasicReplace(middlewaresTemplate, "A1C2IP", funcArgs[1]) { if !BasicReplace(k8sMiddlewaresYamlFile, "A1C2IP", funcArgs[0]) {
result = append(result, "替换A1C2IP信息") result = append(result, "替换A1C2IP信息")
return false, result return false, result
} }
// 启动服务 if !BasicReplace(k8sMiddlewaresYamlFile, "SUPREME", funcArgs[1]) {
if !PureResultSingleExecute([]string{ result = append(result, "替换SUPREME信息")
"kubectl",
"apply",
"-f",
middlewaresTemplate,
}) {
result = append(result, "创建 中间件 失败!")
return false, result return false, result
} }
// 启动服务
exec, strings := KubectlApplyExec(k8sMiddlewaresYamlFile)
if !exec {
return false, append(result, strings...)
}
// 成功启动 // 成功启动
return true, []string{ return true, []string{
"中间件部署成功!", "中间件部署成功!",
@@ -524,48 +512,44 @@ func (op *AgentOsOperator) deployMiddlewares(funcArgs []string) (bool, []string)
func (op *AgentOsOperator) deployRedis(funcArgs []string) (bool, []string) { func (op *AgentOsOperator) deployRedis(funcArgs []string) (bool, []string) {
redisTemplate := "redis-template.yaml" redisTemplate := "k8s-redis-template.yaml"
result := append(AppExecuteErrorLogPrefix, "部署 redis !") result := append(AppExecuteErrorLogPrefix, "部署 redis !")
// 环境判定 // 环境判定
commandExist, commandName := BasicCommandExistsBatch([]string{ if !BasicCommandExistByPath("kubectl") {
"kubectl", result = append(result, "命令不存在", "kubectl")
})
if !commandExist {
result = append(result, "命令不存在", commandName)
return false, result return false, result
} }
// 下载模板文件 // 下载模板文件
if !PureResultSingleExecute([]string{ k8sRedisYamlFile := "/root/wdd/install/k8s-redis.yaml"
"wget", ok, resultLog := BasicDownloadFile(op.OssOfflinePrefix+redisTemplate, k8sRedisYamlFile)
"-q", if !ok {
op.OssOfflinePrefix + "/" + redisTemplate, return false, resultLog
}) {
result = append(result, "下载模板文件")
return false, result
} }
// 根据参数 A1C2IP 替换 // 根据参数 A1C2IP 替换
if !BasicReplace(redisTemplate, "SUPREME", funcArgs[0]) { ip := net.ParseIP(funcArgs[0])
result = append(result, "替换SUPREME信息") if ip == nil {
return false, result return false, append(result,
"ip args error !")
} }
if !BasicReplace(redisTemplate, "A1C2IP", funcArgs[1]) { if !BasicReplace(k8sRedisYamlFile, "A1C2IP", funcArgs[0]) {
result = append(result, "替换A1C2IP信息") result = append(result, "替换A1C2IP信息")
return false, result return false, result
} }
// 启动服务 if !BasicReplace(k8sRedisYamlFile, "SUPREME", funcArgs[1]) {
if !PureResultSingleExecute([]string{ result = append(result, "替换SUPREME信息")
"kubectl",
"apply",
"-f",
redisTemplate,
}) {
result = append(result, "创建 Redis 失败!")
return false, result return false, result
} }
// 启动服务
exec, strings := KubectlApplyExec(k8sRedisYamlFile)
if !exec {
return false, append(result, strings...)
}
// 成功启动 // 成功启动
return true, []string{ return true, []string{
"Redis 部署成功!", "Redis 部署成功!",

View File

@@ -393,7 +393,7 @@ func (hOp *HarborOperator) SyncStatusExec(funcArgs []string) (bool, []string) {
// report status // report status
return false, []string{ return false, []string{
fmt.Sprintf("[sync status] - not complete ! progress is => %s %", fmt.Sprintf("[sync status] - not complete ! progress is => %s %",
strconv.FormatFloat(float64(execution.Succeed)/float64(execution.Total), 'f', 1, 64)), strconv.FormatFloat(float64(execution.Succeed)/float64(execution.Total)*100, 'f', 2, 64)),
} }
} }
} }

View File

@@ -2,18 +2,21 @@ package executor
import ( import (
"fmt" "fmt"
"k8s.io/apimachinery/pkg/api/errors"
"os"
"strings" "strings"
"sync" "sync"
"time" "time"
"context" "context"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
) )
var k8sConfigFilePath = "/root/.kube/config" var k8sConfigFilePath = "/root/wdd/kube_config_cluster.yml"
var k8sClient = newK8sClientInstance() var k8sClient = newK8sClientInstance()
func newK8sClientInstance() *kubernetes.Clientset { func newK8sClientInstance() *kubernetes.Clientset {
@@ -107,7 +110,7 @@ func CheckDeploymentStatusTimeout(specificDeployment string, supreme string, wai
if err != nil { if err != nil {
log.ErrorF("[CheckDeploymentStatusTimeout] - 获取deployment信息失败: %v\n", err) log.ErrorF("[CheckDeploymentStatusTimeout] - 获取deployment信息失败: %v\n", err)
} else { } else {
log.DebugF("[CheckDeploymentStatusTimeout] - 命名空间: %s, Deployment %s 还有Pods未处于Running状态 (Ready: %d, Total: %d)\n", supreme, deployment.Name, deployment.Status.ReadyReplicas, deployment.Status.Replicas) log.DebugF("[CheckDeploymentStatusTimeout] - 命名空间: [ %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 { if deployment.Status.ReadyReplicas == deployment.Status.Replicas {
return true return true
@@ -179,3 +182,80 @@ func KubectlDeleteExec(resourcesYamlFile string) (bool, []string) {
return true, append(resultLog, return true, append(resultLog,
fmt.Sprintf("[KubectlDeleteExec] - %s delete success!", resourcesYamlFile)) fmt.Sprintf("[KubectlDeleteExec] - %s delete success!", resourcesYamlFile))
} }
func CreateK8sNamespace(namespaceName string) bool {
if k8sClient == nil {
log.ErrorF("k8s client is nil, run k8s function error !")
return false
}
// create namespace
// 创建命名空间对象
namespace := &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: namespaceName,
},
}
// 使用客户端创建命名空间
_, err := k8sClient.CoreV1().Namespaces().Create(context.TODO(), namespace, metav1.CreateOptions{})
if err != nil {
log.ErrorF("Error creating namespace: %s \n", 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 GetK8sDashBoardAuthKey() {
// 获取 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)
}
}

View File

@@ -31,6 +31,10 @@ public enum AppFunctionEnum {
"部署nfs+storage_class, 参数为A1C2IP, SUPREME, N1C2IP" "部署nfs+storage_class, 参数为A1C2IP, SUPREME, N1C2IP"
), ),
DEPLOY_TEST_NFS(
"DEPLOY_TEST_NFS",
"部署NFS的测试Pod, 参数为A1C2IP, SUPREME, N1C2IP"
),
DEPLOY_STORAGE_CLASS( DEPLOY_STORAGE_CLASS(
"DEPLOY_STORAGE_CLASS", "DEPLOY_STORAGE_CLASS",

View File

@@ -55,15 +55,15 @@ public class HarborFuncScheduler {
.getTopicName(); .getTopicName();
// create harbor project // create harbor project
if (!CreateHarborProject(projectDeployContext)) { // if (!CreateHarborProject(projectDeployContext)) {
log.error("create harbor project failed !"); // log.error("create harbor project failed !");
} // }
// check harbor project // check harbor project
// list // list
if (!ListHarborProject(projectDeployContext)) { // if (!ListHarborProject(projectDeployContext)) {
log.error("list harbor project failed !"); // log.error("list harbor project failed !");
} // }
int maxSyncStatusCheckCount = 1000; int maxSyncStatusCheckCount = 1000;
int timePinch = 2; int timePinch = 2;
@@ -134,7 +134,6 @@ public class HarborFuncScheduler {
} }
return true; return true;
} }
@@ -177,7 +176,9 @@ public class HarborFuncScheduler {
ServerInfoPO masterNode = projectDeployContext.getMasterNode(); ServerInfoPO masterNode = projectDeployContext.getMasterNode();
ArrayList<String> syncHarborArgList = new ArrayList<>(); ArrayList<String> syncHarborArgList = new ArrayList<>();
// zero arg
syncHarborArgList.add(HarborFunctionEnum.SYNC_PROJECT_BETWEEN_HARBOR.getOpName()); syncHarborArgList.add(HarborFunctionEnum.SYNC_PROJECT_BETWEEN_HARBOR.getOpName());
// first func args
syncHarborArgList.add(masterNode.getServerIpInV4()); syncHarborArgList.add(masterNode.getServerIpInV4());
// second arg sourceHarborHost // second arg sourceHarborHost