Files
ProjectOctopus/agent-go/executor/HarborExecutor.go
2023-11-14 17:05:49 +08:00

265 lines
7.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package executor
import (
"context"
"encoding/json"
"fmt"
"net"
"os"
"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()
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
}
return resultOk, resultLog
}
func (hOp *HarborOperator) CreateProjectExec(funcArgs []string) (bool, []string) {
if hOp.TargetHarborClient == nil {
ok, createClient := hOp.CheckAndBuildHarborClient(funcArgs[0])
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"}
var err error
// 使用客户端创建项目
ctx := context.Background()
for _, projectName := range needToCreateProjectNameList {
log.DebugF("start to create => %s", projectName)
projectReq := &model.ProjectReq{
ProjectName: projectName, // 仓库名称
Metadata: &model.ProjectMetadata{
Public: "true", // 是否是公开的
},
}
exists, _ := client.ProjectExists(ctx, projectName)
if exists {
log.DebugF("[Harbor Create Project] - Project %s already exists ! continue ", projectName)
continue
}
err = client.NewProject(ctx, projectReq)
if err != nil {
errorLog := fmt.Sprintf("Error creating project %s: %s\n", projectName, err.Error())
return false, []string{errorLog}
}
}
successLog := "[Harbor CreateProjectExec] - Project Create Success !"
log.Info(successLog)
return true, []string{successLog}
}
func (hOp *HarborOperator) CheckAndBuildHarborClient(targetHarborHost string) (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
}
hOp.TargetHarborHost = "http://" + targetHarborHost + ":" + hOp.HarborPort + "/api/"
log.DebugF("[Harbor Client Create] - harbor host is => %s", hOp.TargetHarborHost)
// check connection
client, err := apiv2.NewRESTClientForHost(hOp.TargetHarborHost, 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])
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])
if !ok {
return false, []string{
"[Harbor Sync Project ] - Error !",
}
}
hOp.TargetHarborClient = createClient
}
targetClient := hOp.TargetHarborClient
if hOp.SourceHarborClient == nil {
ok, createClient := hOp.CheckAndBuildHarborClient(funcArgs[1])
if !ok {
return false, []string{
"[Harbor Sync Project ] - Error !",
}
}
hOp.SourceHarborClient = createClient
}
sourceClient := hOp.SourceHarborClient
ctx := context.Background()
// check both source and target harbor project exists
needToCreateProjectNameList := []string{"cmii", "rancher"}
for _, projectName := range needToCreateProjectNameList {
syncNotExistHarborProjectError := []string{
"[Harbor Sync Project ] - project not exists !",
}
exists, _ := targetClient.ProjectExists(ctx, projectName)
if !exists {
return false, append(syncNotExistHarborProjectError, "targetClient")
}
projectExists, _ := sourceClient.ProjectExists(ctx, projectName)
if !projectExists {
return false, append(syncNotExistHarborProjectError, "sourceClient")
}
}
// 创建复制策略
newPolicy := &model.ReplicationPolicy{
Name: "sync-repositories-to-target",
Enabled: true,
Deletion: false,
Override: true,
SrcRegistry: &model.Registry{
ID: 0, // 源 Harbor 实例的注册表 ID通常为 0
},
DestRegistry: &model.Registry{
ID: 1, // 目标 Harbor 实例的注册表 ID需要根据实际情况设置
},
DestNamespace: "", // 可以指定目标 Harbor 中的特定项目,如果为空,则使用源项目名称
Trigger: &model.ReplicationTrigger{
Type: "manual", // 可以是 "manual", "scheduled", 或 "event_based"
// 如果是 "scheduled",还需要设置 Cron 表达式
// TriggerSettings: &model.TriggerSettings{Cron: "0 * * * *"},
},
Filters: []*model.ReplicationFilter{
{
Type: "name",
Value: "cmii/**", // 根据需要同步的仓库进行调整
},
{
Type: "name",
Value: "rancher/**", // 根据需要同步的仓库进行调整
},
},
}
// 在源 Harbor 中创建复制策略
log.Info("[Harbor Sync Project ] - Start To Sync Project !")
err := sourceClient.NewReplicationPolicy(ctx, newPolicy.DestRegistry, newPolicy.SrcRegistry, newPolicy.Deletion, newPolicy.Override, newPolicy.Enabled, newPolicy.Filters, newPolicy.Trigger, newPolicy.DestNamespace, newPolicy.Name, newPolicy.Name)
if err != nil {
fmt.Printf("Error creating replication policy: %v\n", err)
return false, []string{
"[Harbor Sync Project ] - Sync Project Failed !",
}
}
return true, nil
}
func (hOp *HarborOperator) Command(baseFuncName string, funcArgs ...string) []string {
return nil
}