mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-23 10:45:45 +01:00
Merge pull request #7272 from ywk253100/190402_trigger_operation
Fix replication related issues
This commit is contained in:
commit
68803313d9
@ -85,6 +85,7 @@ create table replication_task (
|
|||||||
resource_type varchar(64),
|
resource_type varchar(64),
|
||||||
src_resource varchar(256),
|
src_resource varchar(256),
|
||||||
dst_resource varchar(256),
|
dst_resource varchar(256),
|
||||||
|
operation varchar(32),
|
||||||
job_id varchar(64),
|
job_id varchar(64),
|
||||||
status varchar(32),
|
status varchar(32),
|
||||||
start_time timestamp default CURRENT_TIMESTAMP,
|
start_time timestamp default CURRENT_TIMESTAMP,
|
||||||
|
@ -5,6 +5,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/goharbor/harbor/src/replication/ng/event"
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/common/dao"
|
"github.com/goharbor/harbor/src/common/dao"
|
||||||
"github.com/goharbor/harbor/src/common/utils/log"
|
"github.com/goharbor/harbor/src/common/utils/log"
|
||||||
"github.com/goharbor/harbor/src/core/api/models"
|
"github.com/goharbor/harbor/src/core/api/models"
|
||||||
@ -215,16 +217,27 @@ func (t *RegistryAPI) Delete() {
|
|||||||
|
|
||||||
// GetInfo returns the base info and capability declarations of the registry
|
// GetInfo returns the base info and capability declarations of the registry
|
||||||
func (t *RegistryAPI) GetInfo() {
|
func (t *RegistryAPI) GetInfo() {
|
||||||
id := t.GetIDFromURL()
|
id, err := t.GetInt64FromPath(":id")
|
||||||
registry, err := t.manager.Get(id)
|
// "0" is used for the ID of the local Harbor registry
|
||||||
if err != nil {
|
if err != nil || id < 0 {
|
||||||
t.HandleInternalServerError(fmt.Sprintf("failed to get registry %d: %v", id, err))
|
t.HandleBadRequest(fmt.Sprintf("invalid registry ID %s", t.GetString(":id")))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if registry == nil {
|
var registry *model.Registry
|
||||||
t.HandleNotFound(fmt.Sprintf("registry %d not found", id))
|
if id == 0 {
|
||||||
return
|
registry = event.GetLocalRegistry()
|
||||||
|
} else {
|
||||||
|
registry, err = t.manager.Get(id)
|
||||||
|
if err != nil {
|
||||||
|
t.HandleInternalServerError(fmt.Sprintf("failed to get registry %d: %v", id, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if registry == nil {
|
||||||
|
t.HandleNotFound(fmt.Sprintf("registry %d not found", id))
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
factory, err := adapter.GetFactory(registry.Type)
|
factory, err := adapter.GetFactory(registry.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.HandleInternalServerError(fmt.Sprintf("failed to get the adapter factory for registry type %s: %v", registry.Type, err))
|
t.HandleInternalServerError(fmt.Sprintf("failed to get the adapter factory for registry type %s: %v", registry.Type, err))
|
||||||
|
@ -19,6 +19,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/goharbor/harbor/src/replication/ng/model"
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/replication/ng/event"
|
"github.com/goharbor/harbor/src/replication/ng/event"
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/replication/ng"
|
"github.com/goharbor/harbor/src/replication/ng"
|
||||||
@ -120,7 +122,8 @@ func (r *ReplicationOperationAPI) CreateExecution() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
executionID, err := ng.OperationCtl.StartReplication(policy, nil)
|
trigger := r.GetString("trigger", model.TriggerTypeManual)
|
||||||
|
executionID, err := ng.OperationCtl.StartReplication(policy, nil, trigger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.HandleInternalServerError(fmt.Sprintf("failed to start replication for policy %d: %v", execution.PolicyID, err))
|
r.HandleInternalServerError(fmt.Sprintf("failed to start replication for policy %d: %v", execution.PolicyID, err))
|
||||||
return
|
return
|
||||||
|
@ -25,7 +25,7 @@ import (
|
|||||||
|
|
||||||
type fakedOperationController struct{}
|
type fakedOperationController struct{}
|
||||||
|
|
||||||
func (f *fakedOperationController) StartReplication(policy *model.Policy, resource *model.Resource) (int64, error) {
|
func (f *fakedOperationController) StartReplication(policy *model.Policy, resource *model.Resource, trigger string) (int64, error) {
|
||||||
return 1, nil
|
return 1, nil
|
||||||
}
|
}
|
||||||
func (f *fakedOperationController) StopReplication(int64) error {
|
func (f *fakedOperationController) StopReplication(int64) error {
|
||||||
|
@ -135,7 +135,8 @@ func initRouters() {
|
|||||||
|
|
||||||
beego.Router("/api/registries", &api.RegistryAPI{}, "get:List;post:Post")
|
beego.Router("/api/registries", &api.RegistryAPI{}, "get:List;post:Post")
|
||||||
beego.Router("/api/registries/:id([0-9]+)", &api.RegistryAPI{}, "get:Get;put:Put;delete:Delete")
|
beego.Router("/api/registries/:id([0-9]+)", &api.RegistryAPI{}, "get:Get;put:Put;delete:Delete")
|
||||||
beego.Router("/api/registries/:id([0-9]+)/info", &api.RegistryAPI{}, "get:GetInfo")
|
// we use "0" as the ID of the local Harbor registry, so don't add "([0-9]+)" in the path
|
||||||
|
beego.Router("/api/registries/:id/info", &api.RegistryAPI{}, "get:GetInfo")
|
||||||
|
|
||||||
beego.Router("/v2/*", &controllers.RegistryProxy{}, "*:Handle")
|
beego.Router("/v2/*", &controllers.RegistryProxy{}, "*:Handle")
|
||||||
|
|
||||||
|
@ -106,13 +106,13 @@ type TaskFieldsName struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Task represent the tasks in one execution.
|
// Task represent the tasks in one execution.
|
||||||
// TODO add operation property
|
|
||||||
type Task struct {
|
type Task struct {
|
||||||
ID int64 `orm:"pk;auto;column(id)" json:"id"`
|
ID int64 `orm:"pk;auto;column(id)" json:"id"`
|
||||||
ExecutionID int64 `orm:"column(execution_id)" json:"execution_id"`
|
ExecutionID int64 `orm:"column(execution_id)" json:"execution_id"`
|
||||||
ResourceType string `orm:"column(resource_type)" json:"resource_type"`
|
ResourceType string `orm:"column(resource_type)" json:"resource_type"`
|
||||||
SrcResource string `orm:"column(src_resource)" json:"src_resource"`
|
SrcResource string `orm:"column(src_resource)" json:"src_resource"`
|
||||||
DstResource string `orm:"column(dst_resource)" json:"dst_resource"`
|
DstResource string `orm:"column(dst_resource)" json:"dst_resource"`
|
||||||
|
Operation string `orm:"column(operation)" json:"operation"`
|
||||||
JobID string `orm:"column(job_id)" json:"job_id"`
|
JobID string `orm:"column(job_id)" json:"job_id"`
|
||||||
Status string `orm:"column(status)" json:"status"`
|
Status string `orm:"column(status)" json:"status"`
|
||||||
StartTime time.Time `orm:"column(start_time)" json:"start_time"`
|
StartTime time.Time `orm:"column(start_time)" json:"start_time"`
|
||||||
|
@ -76,7 +76,7 @@ func (h *handler) Handle(event *Event) error {
|
|||||||
if err := PopulateRegistries(h.registryMgr, policy); err != nil {
|
if err := PopulateRegistries(h.registryMgr, policy); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
id, err := h.opCtl.StartReplication(policy, event.Resource)
|
id, err := h.opCtl.StartReplication(policy, event.Resource, model.TriggerTypeEventBased)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -140,7 +140,7 @@ func PopulateRegistries(registryMgr registry.Manager, policy *model.Policy) erro
|
|||||||
|
|
||||||
func getRegistry(registryMgr registry.Manager, registry *model.Registry) (*model.Registry, error) {
|
func getRegistry(registryMgr registry.Manager, registry *model.Registry) (*model.Registry, error) {
|
||||||
if registry == nil || registry.ID == 0 {
|
if registry == nil || registry.ID == 0 {
|
||||||
return getLocalRegistry(), nil
|
return GetLocalRegistry(), nil
|
||||||
}
|
}
|
||||||
reg, err := registryMgr.Get(registry.ID)
|
reg, err := registryMgr.Get(registry.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -152,7 +152,8 @@ func getRegistry(registryMgr registry.Manager, registry *model.Registry) (*model
|
|||||||
return reg, nil
|
return reg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLocalRegistry() *model.Registry {
|
// GetLocalRegistry returns the info of the local Harbor registry
|
||||||
|
func GetLocalRegistry() *model.Registry {
|
||||||
return &model.Registry{
|
return &model.Registry{
|
||||||
Type: model.RegistryTypeHarbor,
|
Type: model.RegistryTypeHarbor,
|
||||||
Name: "Local",
|
Name: "Local",
|
||||||
|
@ -28,7 +28,7 @@ import (
|
|||||||
|
|
||||||
type fakedOperationController struct{}
|
type fakedOperationController struct{}
|
||||||
|
|
||||||
func (f *fakedOperationController) StartReplication(policy *model.Policy, resource *model.Resource) (int64, error) {
|
func (f *fakedOperationController) StartReplication(policy *model.Policy, resource *model.Resource, trigger string) (int64, error) {
|
||||||
return 1, nil
|
return 1, nil
|
||||||
}
|
}
|
||||||
func (f *fakedOperationController) StopReplication(int64) error {
|
func (f *fakedOperationController) StopReplication(int64) error {
|
||||||
|
@ -31,7 +31,8 @@ import (
|
|||||||
// Controller handles the replication-related operations: start,
|
// Controller handles the replication-related operations: start,
|
||||||
// stop, query, etc.
|
// stop, query, etc.
|
||||||
type Controller interface {
|
type Controller interface {
|
||||||
StartReplication(policy *model.Policy, resource *model.Resource) (int64, error)
|
// trigger is used to specified that what this replication is triggered by
|
||||||
|
StartReplication(policy *model.Policy, resource *model.Resource, trigger string) (int64, error)
|
||||||
StopReplication(int64) error
|
StopReplication(int64) error
|
||||||
ListExecutions(...*models.ExecutionQuery) (int64, []*models.Execution, error)
|
ListExecutions(...*models.ExecutionQuery) (int64, []*models.Execution, error)
|
||||||
GetExecution(int64) (*models.Execution, error)
|
GetExecution(int64) (*models.Execution, error)
|
||||||
@ -56,12 +57,14 @@ type controller struct {
|
|||||||
scheduler scheduler.Scheduler
|
scheduler scheduler.Scheduler
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *controller) StartReplication(policy *model.Policy, resource *model.Resource) (int64, error) {
|
func (c *controller) StartReplication(policy *model.Policy, resource *model.Resource, trigger string) (int64, error) {
|
||||||
if resource != nil && len(resource.Metadata.Vtags) != 1 {
|
if resource != nil && len(resource.Metadata.Vtags) != 1 {
|
||||||
return 0, fmt.Errorf("the length of Vtags must be 1: %v", resource.Metadata.Vtags)
|
return 0, fmt.Errorf("the length of Vtags must be 1: %v", resource.Metadata.Vtags)
|
||||||
}
|
}
|
||||||
|
if len(trigger) == 0 {
|
||||||
id, err := createExecution(c.executionMgr, policy.ID)
|
trigger = model.TriggerTypeManual
|
||||||
|
}
|
||||||
|
id, err := createExecution(c.executionMgr, policy.ID, trigger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@ -139,9 +142,10 @@ func (c *controller) GetTaskLog(taskID int64) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create the execution record in database
|
// create the execution record in database
|
||||||
func createExecution(mgr execution.Manager, policyID int64) (int64, error) {
|
func createExecution(mgr execution.Manager, policyID int64, trigger string) (int64, error) {
|
||||||
id, err := mgr.Create(&models.Execution{
|
id, err := mgr.Create(&models.Execution{
|
||||||
PolicyID: policyID,
|
PolicyID: policyID,
|
||||||
|
Trigger: trigger,
|
||||||
Status: models.ExecutionStatusInProgress,
|
Status: models.ExecutionStatusInProgress,
|
||||||
StartTime: time.Now(),
|
StartTime: time.Now(),
|
||||||
})
|
})
|
||||||
|
@ -232,24 +232,24 @@ func TestStartReplication(t *testing.T) {
|
|||||||
Vtags: []string{"1.0", "2.0"},
|
Vtags: []string{"1.0", "2.0"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, err = ctl.StartReplication(policy, resource)
|
_, err = ctl.StartReplication(policy, resource, model.TriggerTypeEventBased)
|
||||||
require.NotNil(t, err)
|
require.NotNil(t, err)
|
||||||
|
|
||||||
// replicate resource deletion
|
// replicate resource deletion
|
||||||
resource.Metadata.Vtags = []string{"1.0"}
|
resource.Metadata.Vtags = []string{"1.0"}
|
||||||
resource.Deleted = true
|
resource.Deleted = true
|
||||||
id, err := ctl.StartReplication(policy, resource)
|
id, err := ctl.StartReplication(policy, resource, model.TriggerTypeEventBased)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
assert.Equal(t, int64(1), id)
|
assert.Equal(t, int64(1), id)
|
||||||
|
|
||||||
// replicate resource copy
|
// replicate resource copy
|
||||||
resource.Deleted = false
|
resource.Deleted = false
|
||||||
id, err = ctl.StartReplication(policy, resource)
|
id, err = ctl.StartReplication(policy, resource, model.TriggerTypeEventBased)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
assert.Equal(t, int64(1), id)
|
assert.Equal(t, int64(1), id)
|
||||||
|
|
||||||
// nil resource
|
// nil resource
|
||||||
id, err = ctl.StartReplication(policy, nil)
|
id, err = ctl.StartReplication(policy, nil, model.TriggerTypeEventBased)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
assert.Equal(t, int64(1), id)
|
assert.Equal(t, int64(1), id)
|
||||||
}
|
}
|
||||||
|
@ -263,12 +263,17 @@ func preprocess(scheduler scheduler.Scheduler, srcResources, dstResources []*mod
|
|||||||
// create task records in database
|
// create task records in database
|
||||||
func createTasks(mgr execution.Manager, executionID int64, items []*scheduler.ScheduleItem) error {
|
func createTasks(mgr execution.Manager, executionID int64, items []*scheduler.ScheduleItem) error {
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
|
operation := "copy"
|
||||||
|
if item.DstResource.Deleted {
|
||||||
|
operation = "deletion"
|
||||||
|
}
|
||||||
task := &models.Task{
|
task := &models.Task{
|
||||||
ExecutionID: executionID,
|
ExecutionID: executionID,
|
||||||
Status: models.TaskStatusInitialized,
|
Status: models.TaskStatusInitialized,
|
||||||
ResourceType: string(item.SrcResource.Type),
|
ResourceType: string(item.SrcResource.Type),
|
||||||
SrcResource: getResourceName(item.SrcResource),
|
SrcResource: getResourceName(item.SrcResource),
|
||||||
DstResource: getResourceName(item.DstResource),
|
DstResource: getResourceName(item.DstResource),
|
||||||
|
Operation: operation,
|
||||||
}
|
}
|
||||||
id, err := mgr.CreateTask(task)
|
id, err := mgr.CreateTask(task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -28,7 +28,7 @@ type fakedOperationController struct {
|
|||||||
status string
|
status string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fakedOperationController) StartReplication(*model.Policy, *model.Resource) (int64, error) {
|
func (f *fakedOperationController) StartReplication(*model.Policy, *model.Resource, string) (int64, error) {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
func (f *fakedOperationController) StopReplication(int64) error {
|
func (f *fakedOperationController) StopReplication(int64) error {
|
||||||
|
@ -19,6 +19,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/goharbor/harbor/src/replication/ng/model"
|
||||||
|
|
||||||
common_http "github.com/goharbor/harbor/src/common/http"
|
common_http "github.com/goharbor/harbor/src/common/http"
|
||||||
"github.com/goharbor/harbor/src/common/job"
|
"github.com/goharbor/harbor/src/common/job"
|
||||||
job_models "github.com/goharbor/harbor/src/common/job/models"
|
job_models "github.com/goharbor/harbor/src/common/job/models"
|
||||||
@ -60,7 +62,7 @@ func (s *scheduler) Schedule(policyID int64, cron string) error {
|
|||||||
}
|
}
|
||||||
log.Debugf("the schedule job record %d added", id)
|
log.Debugf("the schedule job record %d added", id)
|
||||||
|
|
||||||
replicateURL := fmt.Sprintf("%s/api/replication/executions", config.Config.CoreURL)
|
replicateURL := fmt.Sprintf("%s/api/replication/executions?trigger=%s", config.Config.CoreURL, model.TriggerTypeScheduled)
|
||||||
statusHookURL := fmt.Sprintf("%s/service/notifications/jobs/replication/schedule/%d", config.Config.CoreURL, id)
|
statusHookURL := fmt.Sprintf("%s/service/notifications/jobs/replication/schedule/%d", config.Config.CoreURL, id)
|
||||||
jobID, err := s.jobservice.SubmitJob(&job_models.JobData{
|
jobID, err := s.jobservice.SubmitJob(&job_models.JobData{
|
||||||
Name: job.Scheduler,
|
Name: job.Scheduler,
|
||||||
|
Loading…
Reference in New Issue
Block a user