264 lines
7.3 KiB
Go
264 lines
7.3 KiB
Go
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"}
|
||
// 使用客户端创建项目
|
||
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) (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
|
||
}
|