From b37f4018a6e6a87e8d90f51f90522532adc75325 Mon Sep 17 00:00:00 2001 From: Wenkai Yin Date: Sat, 23 Mar 2019 07:26:10 +0800 Subject: [PATCH] Update the registry adapter interface This commit adds the Info() method to the registry adapter interface Signed-off-by: Wenkai Yin --- docs/swagger.yaml | 76 ++++++++--------- src/core/api/harborapi_test.go | 1 - src/core/api/registry.go | 61 ++++++++++++++ src/core/api/replication_adapter.go | 54 +----------- src/core/api/replication_adapter_test.go | 59 ++----------- src/core/router.go | 2 +- src/replication/ng/adapter/adapter.go | 89 +++++--------------- src/replication/ng/adapter/adapter_test.go | 83 +++--------------- src/replication/ng/adapter/harbor/adapter.go | 67 +++++++++------ src/replication/ng/flow/copy.go | 5 +- src/replication/ng/flow/stage.go | 10 ++- src/replication/ng/flow/stage_test.go | 24 +++--- src/replication/ng/model/policy.go | 14 +-- src/replication/ng/model/registry.go | 20 +++++ src/replication/ng/operation/controller.go | 2 +- 15 files changed, 228 insertions(+), 339 deletions(-) diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 23143f95e..43ab86af7 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -2431,40 +2431,13 @@ paths: schema: type: array items: - $ref: '#/definitions/ReplicationAdapter' + type: string '401': description: Unauthorized. '403': description: Forbidden. '500': description: Unexpected internal errors. - /replication/adapters/{type}: - get: - summary: Get the specified adapter. - description: | - This endpoint let user get the specified adapter. - parameters: - - name: type - in: path - type: string - required: true - description: The adapter type. - tags: - - Products - responses: - '200': - description: Success. - schema: - type: object - $ref: '#/definitions/ReplicationAdapter' - '401': - description: Unauthorized. - '403': - description: Forbidden. - '404': - description: Not found. - '500': - description: Unexpected internal errors. /registries: get: summary: List registries. @@ -2595,6 +2568,30 @@ paths: description: Registry does not exist. '500': description: Unexpected internal errors. + '/registries/{id}/info': + get: + summary: Get registry info. + description: Get the info of one specific registry. + tags: + - Products + parameters: + - name: id + in: path + type: integer + format: int64 + required: true + description: The registry ID. + responses: + '200': + description: Get registry successfully. + schema: + $ref: '#/definitions/RegistryInfo' + '401': + description: User need to log in first. + '404': + description: Registry not found + '500': + description: Unexpected internal errors. '/targets/{id}/policies/': get: summary: List the target relevant policies. @@ -5279,34 +5276,29 @@ definitions: action: type: string description: The permission action - ReplicationAdapter: + RegistryInfo: type: object - description: The replication adapter + description: The registry info contains the base info and capability declarations of the registry properties: type: type: string - description: The adapter type + description: The registry type description: type: string - description: The adapter description - supported_resource_types: - type: array - description: The resource types that the adapter supports - items: - type: string + description: The description supported_resource_filters: type: array - description: The filters that the adapter supports + description: The filters that the registry supports items: - $ref: '#/definitions/ReplicationAdapterFilter' + $ref: '#/definitions/FilterStyle' supported_triggers: type: array - description: The triggers that the adapter supports + description: The triggers that the registry supports items: type: string - ReplicationAdapterFilter: + FilterStyle: type: object - description: The replication adapter filter + description: The style of the resource filter properties: type: type: string diff --git a/src/core/api/harborapi_test.go b/src/core/api/harborapi_test.go index 8f8d2d77e..b0e9fe721 100644 --- a/src/core/api/harborapi_test.go +++ b/src/core/api/harborapi_test.go @@ -154,7 +154,6 @@ func init() { beego.Router("/api/projects/:pid([0-9]+)/robots/:id([0-9]+)", &RobotAPI{}, "get:Get;put:Put;delete:Delete") beego.Router("/api/replication/adapters", &ReplicationAdapterAPI{}, "get:List") - beego.Router("/api/replication/adapters/:type", &ReplicationAdapterAPI{}, "get:Get") beego.Router("/api/replication/executions", &ReplicationOperationAPI{}, "get:ListExecutions;post:CreateExecution") beego.Router("/api/replication/executions/:id([0-9]+)", &ReplicationOperationAPI{}, "put:StopExecution") beego.Router("/api/replication/executions/:id([0-9]+)/tasks", &ReplicationOperationAPI{}, "get:ListTasks") diff --git a/src/core/api/registry.go b/src/core/api/registry.go index b2599dc22..03a28fd37 100644 --- a/src/core/api/registry.go +++ b/src/core/api/registry.go @@ -9,6 +9,7 @@ import ( "github.com/goharbor/harbor/src/common/utils/log" "github.com/goharbor/harbor/src/core/api/models" "github.com/goharbor/harbor/src/replication/ng" + "github.com/goharbor/harbor/src/replication/ng/adapter" "github.com/goharbor/harbor/src/replication/ng/model" "github.com/goharbor/harbor/src/replication/ng/registry" ) @@ -211,3 +212,63 @@ func (t *RegistryAPI) Delete() { return } } + +// GetInfo returns the base info and capability declarations of the registry +func (t *RegistryAPI) GetInfo() { + id := t.GetIDFromURL() + 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) + if err != nil { + t.HandleInternalServerError(fmt.Sprintf("failed to get the adapter factory for registry type %s: %v", registry.Type, err)) + return + } + adp, err := factory(registry) + if err != nil { + t.HandleInternalServerError(fmt.Sprintf("failed to create the adapter for registry %d: %v", registry.ID, err)) + return + } + info, err := adp.Info() + if err != nil { + t.HandleInternalServerError(fmt.Sprintf("failed to get registry info %d: %v", id, err)) + return + } + t.WriteJSONData(process(info)) +} + +// merge "SupportedResourceTypes" into "SupportedResourceFilters" for UI to render easier +func process(info *model.RegistryInfo) *model.RegistryInfo { + if info == nil { + return nil + } + in := &model.RegistryInfo{ + Type: info.Type, + Description: info.Description, + SupportedTriggers: info.SupportedTriggers, + } + filters := []*model.FilterStyle{} + for _, filter := range info.SupportedResourceFilters { + if filter.Type != model.FilterTypeResource { + filters = append(filters, filter) + } + } + values := []string{} + for _, resourceType := range info.SupportedResourceTypes { + values = append(values, string(resourceType)) + } + filters = append(filters, &model.FilterStyle{ + Type: model.FilterTypeResource, + Style: model.FilterStyleTypeRadio, + Values: values, + }) + in.SupportedResourceFilters = filters + + return in +} diff --git a/src/core/api/replication_adapter.go b/src/core/api/replication_adapter.go index fac813def..ab9256851 100644 --- a/src/core/api/replication_adapter.go +++ b/src/core/api/replication_adapter.go @@ -15,8 +15,6 @@ package api import ( - "fmt" - "github.com/goharbor/harbor/src/replication/ng/adapter" "github.com/goharbor/harbor/src/replication/ng/model" ) @@ -41,53 +39,7 @@ func (r *ReplicationAdapterAPI) Prepare() { // List the replication adapters func (r *ReplicationAdapterAPI) List() { - infos := []*adapter.Info{} - for _, info := range adapter.ListAdapterInfos() { - infos = append(infos, process(info)) - } - r.WriteJSONData(infos) -} - -// Get one specified replication adapter -func (r *ReplicationAdapterAPI) Get() { - t := r.GetStringFromPath(":type") - info := adapter.GetAdapterInfo(model.RegistryType(t)) - if info == nil { - r.HandleNotFound(fmt.Sprintf("adapter for %s not found", t)) - return - } - info = process(info) - r.WriteJSONData(info) -} - -// merge "SupportedResourceTypes" into "SupportedResourceFilters" for UI to render easier -func process(info *adapter.Info) *adapter.Info { - if info == nil { - return nil - } - - in := &adapter.Info{ - Type: info.Type, - Description: info.Description, - SupportedTriggers: info.SupportedTriggers, - } - - filters := []*adapter.Filter{} - for _, filter := range info.SupportedResourceFilters { - if filter.Type != model.FilterTypeResource { - filters = append(filters, filter) - } - } - values := []string{} - for _, resourceType := range info.SupportedResourceTypes { - values = append(values, string(resourceType)) - } - filters = append(filters, &adapter.Filter{ - Type: model.FilterTypeResource, - Style: adapter.FilterStyleRadio, - Values: values, - }) - in.SupportedResourceFilters = filters - - return in + types := []model.RegistryType{} + types = append(types, adapter.ListRegisteredAdapterTypes()...) + r.WriteJSONData(types) } diff --git a/src/core/api/replication_adapter_test.go b/src/core/api/replication_adapter_test.go index 7b17be877..156d34737 100644 --- a/src/core/api/replication_adapter_test.go +++ b/src/core/api/replication_adapter_test.go @@ -24,7 +24,13 @@ import ( "github.com/goharbor/harbor/src/replication/ng/model" ) +func fakedFactory(*model.Registry) (adapter.Adapter, error) { + return nil, nil +} + func TestReplicationAdapterAPIList(t *testing.T) { + err := adapter.RegisterFactory("test", fakedFactory) + require.Nil(t, err) cases := []*codeCheckingCase{ // 401 { @@ -56,56 +62,3 @@ func TestReplicationAdapterAPIList(t *testing.T) { runCodeCheckingCases(t, cases...) } - -func fakedFactory(*model.Registry) (adapter.Adapter, error) { - return nil, nil -} -func TestReplicationAdapterAPIGet(t *testing.T) { - err := adapter.RegisterFactory( - &adapter.Info{ - Type: "test", - SupportedResourceTypes: []model.ResourceType{"image"}, - SupportedTriggers: []model.TriggerType{"mannual"}, - }, fakedFactory) - require.Nil(t, err) - - cases := []*codeCheckingCase{ - // 401 - { - request: &testingRequest{ - method: http.MethodGet, - url: "/api/replication/adapters/test", - }, - code: http.StatusUnauthorized, - }, - // 403 - { - request: &testingRequest{ - method: http.MethodGet, - url: "/api/replication/adapters/test", - credential: nonSysAdmin, - }, - code: http.StatusForbidden, - }, - // 404 - { - request: &testingRequest{ - method: http.MethodGet, - url: "/api/replication/adapters/gcs", - credential: sysAdmin, - }, - code: http.StatusNotFound, - }, - // 200 - { - request: &testingRequest{ - method: http.MethodGet, - url: "/api/replication/adapters/test", - credential: sysAdmin, - }, - code: http.StatusOK, - }, - } - - runCodeCheckingCases(t, cases...) -} diff --git a/src/core/router.go b/src/core/router.go index 9892cd793..5644932d1 100644 --- a/src/core/router.go +++ b/src/core/router.go @@ -101,7 +101,6 @@ func initRouters() { beego.Router("/api/logs", &api.LogAPI{}) beego.Router("/api/replication/adapters", &api.ReplicationAdapterAPI{}, "get:List") - beego.Router("/api/replication/adapters/:type", &api.ReplicationAdapterAPI{}, "get:Get") beego.Router("/api/replication/executions", &api.ReplicationOperationAPI{}, "get:ListExecutions;post:CreateExecution") beego.Router("/api/replication/executions/:id([0-9]+)", &api.ReplicationOperationAPI{}, "put:StopExecution") beego.Router("/api/replication/executions/:id([0-9]+)/tasks", &api.ReplicationOperationAPI{}, "get:ListTasks") @@ -136,6 +135,7 @@ func initRouters() { 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]+)/info", &api.RegistryAPI{}, "get:GetInfo") beego.Router("/v2/*", &controllers.RegistryProxy{}, "*:Handle") diff --git a/src/replication/ng/adapter/adapter.go b/src/replication/ng/adapter/adapter.go index 829f75813..7bd32365d 100644 --- a/src/replication/ng/adapter/adapter.go +++ b/src/replication/ng/adapter/adapter.go @@ -21,45 +21,15 @@ import ( "github.com/goharbor/harbor/src/replication/ng/model" ) -// As the Info isn't a valid map key, so we use the slice -// as the adapter registry -var registry = []*item{} - -// const definition -const ( - FilterStyleText = "input" - FilterStyleRadio = "radio" -) - -// FilterStyle is used for UI to determine how to render the filter -type FilterStyle string - -type item struct { - info *Info - factory Factory -} - -// Filter ... -type Filter struct { - Type model.FilterType `json:"type"` - Style FilterStyle `json:"style"` - Values []string `json:"values,omitempty"` -} - -// Info provides base info and capability declarations of the adapter -type Info struct { - Type model.RegistryType `json:"type"` - Description string `json:"description"` - SupportedResourceTypes []model.ResourceType `json:"-"` - SupportedResourceFilters []*Filter `json:"supported_resource_filters"` - SupportedTriggers []model.TriggerType `json:"supported_triggers"` -} +var registry = map[model.RegistryType]Factory{} // Factory creates a specific Adapter according to the params type Factory func(*model.Registry) (Adapter, error) // Adapter interface defines the capabilities of registry type Adapter interface { + // Info return the information of this adapter + Info() (*model.RegistryInfo, error) // Lists the available namespaces under the specified registry with the // provided credential/token ListNamespaces(*model.NamespaceQuery) ([]*model.Namespace, error) @@ -73,56 +43,35 @@ type Adapter interface { } // RegisterFactory registers one adapter factory to the registry -func RegisterFactory(info *Info, factory Factory) error { - if len(info.Type) == 0 { +func RegisterFactory(t model.RegistryType, factory Factory) error { + if len(t) == 0 { return errors.New("invalid registry type") } - if len(info.SupportedResourceTypes) == 0 { - return errors.New("must support at least one resource type") - } - if len(info.SupportedTriggers) == 0 { - return errors.New("must support at least one trigger") - } if factory == nil { return errors.New("empty adapter factory") } - for _, item := range registry { - if item.info.Type == info.Type { - return fmt.Errorf("adapter factory for %s already exists", info.Type) - } + + if _, exist := registry[t]; exist { + return fmt.Errorf("adapter factory for %s already exists", t) } - registry = append(registry, &item{ - info: info, - factory: factory, - }) + registry[t] = factory return nil } // GetFactory gets the adapter factory by the specified name func GetFactory(t model.RegistryType) (Factory, error) { - for _, item := range registry { - if item.info.Type == t { - return item.factory, nil - } + factory, exist := registry[t] + if !exist { + return nil, fmt.Errorf("adapter factory for %s not found", t) } - return nil, fmt.Errorf("adapter factory for %s not found", t) + return factory, nil } -// ListAdapterInfos lists the info of registered Adapters -func ListAdapterInfos() []*Info { - infos := []*Info{} - for _, item := range registry { - infos = append(infos, item.info) +// ListRegisteredAdapterTypes lists the registered Adapter type +func ListRegisteredAdapterTypes() []model.RegistryType { + types := []model.RegistryType{} + for t := range registry { + types = append(types, t) } - return infos -} - -// GetAdapterInfo returns the info of a specified registry type -func GetAdapterInfo(t model.RegistryType) *Info { - for _, item := range registry { - if item.info.Type == t { - return item.info - } - } - return nil + return types } diff --git a/src/replication/ng/adapter/adapter_test.go b/src/replication/ng/adapter/adapter_test.go index da36d0877..d4333bc96 100644 --- a/src/replication/ng/adapter/adapter_test.go +++ b/src/replication/ng/adapter/adapter_test.go @@ -28,49 +28,18 @@ func fakedFactory(*model.Registry) (Adapter, error) { func TestRegisterFactory(t *testing.T) { // empty type - assert.NotNil(t, RegisterFactory(&Info{}, nil)) - // empty supportted resource type - assert.NotNil(t, RegisterFactory( - &Info{ - Type: "harbor", - }, nil)) - // empty trigger - assert.NotNil(t, RegisterFactory( - &Info{ - Type: "harbor", - SupportedResourceTypes: []model.ResourceType{"image"}, - }, nil)) + assert.NotNil(t, RegisterFactory("", nil)) // empty factory - assert.NotNil(t, RegisterFactory( - &Info{ - Type: "harbor", - SupportedResourceTypes: []model.ResourceType{"image"}, - SupportedTriggers: []model.TriggerType{"mannual"}, - }, nil)) + assert.NotNil(t, RegisterFactory("harbor", nil)) // pass - assert.Nil(t, RegisterFactory( - &Info{ - Type: "harbor", - SupportedResourceTypes: []model.ResourceType{"image"}, - SupportedTriggers: []model.TriggerType{"mannual"}, - }, fakedFactory)) + assert.Nil(t, RegisterFactory("harbor", fakedFactory)) // already exists - assert.NotNil(t, RegisterFactory( - &Info{ - Type: "harbor", - SupportedResourceTypes: []model.ResourceType{"image"}, - SupportedTriggers: []model.TriggerType{"mannual"}, - }, fakedFactory)) + assert.NotNil(t, RegisterFactory("harbor", fakedFactory)) } func TestGetFactory(t *testing.T) { - registry = []*item{} - require.Nil(t, RegisterFactory( - &Info{ - Type: "harbor", - SupportedResourceTypes: []model.ResourceType{"image"}, - SupportedTriggers: []model.TriggerType{"mannual"}, - }, fakedFactory)) + registry = map[model.RegistryType]Factory{} + require.Nil(t, RegisterFactory("harbor", fakedFactory)) // doesn't exist _, err := GetFactory("gcr") assert.NotNil(t, err) @@ -79,40 +48,16 @@ func TestGetFactory(t *testing.T) { assert.Nil(t, err) } -func TestListAdapterInfos(t *testing.T) { - registry = []*item{} +func TestListRegisteredAdapterTypes(t *testing.T) { + registry = map[model.RegistryType]Factory{} // not register, got nothing - infos := ListAdapterInfos() - assert.Equal(t, 0, len(infos)) + types := ListRegisteredAdapterTypes() + assert.Equal(t, 0, len(types)) // register one factory - require.Nil(t, RegisterFactory( - &Info{ - Type: "harbor", - SupportedResourceTypes: []model.ResourceType{"image"}, - SupportedTriggers: []model.TriggerType{"mannual"}, - }, fakedFactory)) + require.Nil(t, RegisterFactory("harbor", fakedFactory)) - infos = ListAdapterInfos() - require.Equal(t, 1, len(infos)) - assert.Equal(t, "harbor", string(infos[0].Type)) -} - -func TestGetAdapterInfo(t *testing.T) { - registry = []*item{} - require.Nil(t, RegisterFactory( - &Info{ - Type: "harbor", - SupportedResourceTypes: []model.ResourceType{"image"}, - SupportedTriggers: []model.TriggerType{"mannual"}, - }, fakedFactory)) - - // doesn't exist - info := GetAdapterInfo("gcr") - assert.Nil(t, info) - - // exist - info = GetAdapterInfo("harbor") - require.NotNil(t, info) - assert.Equal(t, "harbor", string(info.Type)) + types = ListRegisteredAdapterTypes() + require.Equal(t, 1, len(types)) + assert.Equal(t, model.RegistryType("harbor"), types[0]) } diff --git a/src/replication/ng/adapter/harbor/adapter.go b/src/replication/ng/adapter/harbor/adapter.go index 7f5d62d91..7a2aeb2d0 100644 --- a/src/replication/ng/adapter/harbor/adapter.go +++ b/src/replication/ng/adapter/harbor/adapter.go @@ -31,36 +31,10 @@ import ( // TODO add UT func init() { - info := &adp.Info{ - Type: model.RegistryTypeHarbor, - SupportedResourceTypes: []model.ResourceType{ - model.ResourceTypeRepository, - model.ResourceTypeChart, - }, - SupportedResourceFilters: []*adp.Filter{ - { - Type: model.FilterTypeName, - Style: adp.FilterStyleText, - }, - { - Type: model.FilterTypeVersion, - Style: adp.FilterStyleText, - }, - { - Type: model.FilterTypeLabel, - Style: adp.FilterStyleText, - }, - }, - SupportedTriggers: []model.TriggerType{ - model.TriggerTypeManual, - model.TriggerTypeScheduled, - model.TriggerTypeEventBased, - }, - } // TODO passing coreServiceURL and tokenServiceURL coreServiceURL := "http://core:8080" tokenServiceURL := "" - if err := adp.RegisterFactory(info, func(registry *model.Registry) (adp.Adapter, error) { + if err := adp.RegisterFactory(model.RegistryTypeHarbor, func(registry *model.Registry) (adp.Adapter, error) { return newAdapter(registry, coreServiceURL, tokenServiceURL), nil }); err != nil { log.Errorf("failed to register factory for %s: %v", model.RegistryTypeHarbor, err) @@ -110,6 +84,45 @@ func newAdapter(registry *model.Registry, coreServiceURL string, } } +func (a *adapter) Info() (*model.RegistryInfo, error) { + info := &model.RegistryInfo{ + Type: model.RegistryTypeHarbor, + SupportedResourceTypes: []model.ResourceType{ + model.ResourceTypeRepository, + }, + SupportedResourceFilters: []*model.FilterStyle{ + { + Type: model.FilterTypeName, + Style: model.FilterStyleTypeText, + }, + { + Type: model.FilterTypeTag, + Style: model.FilterStyleTypeText, + }, + { + Type: model.FilterTypeLabel, + Style: model.FilterStyleTypeText, + }, + }, + SupportedTriggers: []model.TriggerType{ + model.TriggerTypeManual, + model.TriggerTypeScheduled, + model.TriggerTypeEventBased, + }, + } + + sys := &struct { + ChartRegistryEnabled bool `json:"with_chartmuseum"` + }{} + if err := a.client.Get(a.coreServiceURL+"/api/systeminfo", sys); err != nil { + return nil, err + } + if sys.ChartRegistryEnabled { + info.SupportedResourceTypes = append(info.SupportedResourceTypes, model.ResourceTypeChart) + } + return info, nil +} + // TODO implement the function func (a *adapter) ListNamespaces(*model.NamespaceQuery) ([]*model.Namespace, error) { return nil, nil diff --git a/src/replication/ng/flow/copy.go b/src/replication/ng/flow/copy.go index 979a99668..1b9fab739 100644 --- a/src/replication/ng/flow/copy.go +++ b/src/replication/ng/flow/copy.go @@ -47,12 +47,11 @@ func NewCopyFlow(executionMgr execution.Manager, registryMgr registry.Manager, } func (c *copyFlow) Run(interface{}) error { - srcRegistry, dstRegistry, srcAdapter, dstAdapter, err := initialize(c.registryMgr, c.policy) + _, dstRegistry, srcAdapter, dstAdapter, err := initialize(c.registryMgr, c.policy) if err != nil { return err } - // TODO after refactoring the adapter register, the "srcRegistry.Type" is not needed - srcResources, err := fetchResources(srcAdapter, srcRegistry.Type, c.policy) + srcResources, err := fetchResources(srcAdapter, c.policy) if err != nil { return err } diff --git a/src/replication/ng/flow/stage.go b/src/replication/ng/flow/stage.go index bef8cee56..154a62f3c 100644 --- a/src/replication/ng/flow/stage.go +++ b/src/replication/ng/flow/stage.go @@ -87,7 +87,7 @@ func initialize(mgr registry.Manager, policy *model.Policy) (*model.Registry, *m } // fetch resources from the source registry -func fetchResources(adapter adp.Adapter, adapterType model.RegistryType, policy *model.Policy) ([]*model.Resource, error) { +func fetchResources(adapter adp.Adapter, policy *model.Policy) ([]*model.Resource, error) { resTypes := []model.ResourceType{} filters := []*model.Filter{} for _, filter := range policy.Filters { @@ -98,7 +98,11 @@ func fetchResources(adapter adp.Adapter, adapterType model.RegistryType, policy resTypes = append(resTypes, filter.Value.(model.ResourceType)) } if len(resTypes) == 0 { - resTypes = append(resTypes, adp.GetAdapterInfo(adapterType).SupportedResourceTypes...) + info, err := adapter.Info() + if err != nil { + return nil, fmt.Errorf("failed to get the adapter info: %v", err) + } + resTypes = append(resTypes, info.SupportedResourceTypes...) } resources := []*model.Resource{} @@ -167,7 +171,7 @@ func filterResources(resources []*model.Resource, filters []*model.Filter) ([]*m match = false break } - case model.FilterTypeVersion: + case model.FilterTypeTag: pattern, ok := filter.Value.(string) if !ok { return nil, fmt.Errorf("%v is not a valid string", filter.Value) diff --git a/src/replication/ng/flow/stage_test.go b/src/replication/ng/flow/stage_test.go index 7d4b12377..47ada8921 100644 --- a/src/replication/ng/flow/stage_test.go +++ b/src/replication/ng/flow/stage_test.go @@ -67,6 +67,16 @@ func fakedAdapterFactory(*model.Registry) (adapter.Adapter, error) { type fakedAdapter struct{} +func (f *fakedAdapter) Info() (*model.RegistryInfo, error) { + return &model.RegistryInfo{ + Type: model.RegistryTypeHarbor, + SupportedResourceTypes: []model.ResourceType{ + model.ResourceTypeRepository, + model.ResourceTypeChart, + }, + SupportedTriggers: []model.TriggerType{model.TriggerTypeManual}, + }, nil +} func (f *fakedAdapter) ListNamespaces(*model.NamespaceQuery) ([]*model.Namespace, error) { return nil, nil } @@ -225,15 +235,7 @@ func TestMain(m *testing.M) { config.Config = &config.Configuration{ RegistryURL: url, } - if err := adapter.RegisterFactory( - &adapter.Info{ - Type: model.RegistryTypeHarbor, - SupportedResourceTypes: []model.ResourceType{ - model.ResourceTypeRepository, - model.ResourceTypeChart, - }, - SupportedTriggers: []model.TriggerType{model.TriggerTypeManual}, - }, fakedAdapterFactory); err != nil { + if err := adapter.RegisterFactory(model.RegistryTypeHarbor, fakedAdapterFactory); err != nil { os.Exit(1) } os.Exit(m.Run()) @@ -255,7 +257,7 @@ func TestInitialize(t *testing.T) { func TestFetchResources(t *testing.T) { adapter := &fakedAdapter{} policy := &model.Policy{} - resources, err := fetchResources(adapter, model.RegistryTypeHarbor, policy) + resources, err := fetchResources(adapter, policy) require.Nil(t, err) assert.Equal(t, 2, len(resources)) } @@ -313,7 +315,7 @@ func TestFilterResources(t *testing.T) { Value: "library/harbor", }, { - Type: model.FilterTypeVersion, + Type: model.FilterTypeTag, Value: "0.2.?", }, } diff --git a/src/replication/ng/model/policy.go b/src/replication/ng/model/policy.go index 461bdf826..6cb8296b1 100644 --- a/src/replication/ng/model/policy.go +++ b/src/replication/ng/model/policy.go @@ -23,14 +23,14 @@ import ( // const definition const ( - FilterTypeResource = "Resource" - FilterTypeName = "Name" - FilterTypeVersion = "Version" - FilterTypeLabel = "Label" + FilterTypeResource = "resource" + FilterTypeName = "name" + FilterTypeTag = "tag" + FilterTypeLabel = "label" - TriggerTypeManual = "Manual" - TriggerTypeScheduled = "Scheduled" - TriggerTypeEventBased = "EventBased" + TriggerTypeManual = "manual" + TriggerTypeScheduled = "scheduled" + TriggerTypeEventBased = "event_based" ) // Policy defines the structure of a replication policy diff --git a/src/replication/ng/model/registry.go b/src/replication/ng/model/registry.go index cc4f82f9b..4efa8d0d8 100644 --- a/src/replication/ng/model/registry.go +++ b/src/replication/ng/model/registry.go @@ -20,9 +20,13 @@ import ( "github.com/goharbor/harbor/src/common/models" ) +// const definition const ( // RegistryTypeHarbor indicates registry type harbor RegistryTypeHarbor = "harbor" + + FilterStyleTypeText = "input" + FilterStyleTypeRadio = "radio" ) // RegistryType indicates the type of registry @@ -74,3 +78,19 @@ type RegistryQuery struct { // Pagination specifies the pagination Pagination *models.Pagination } + +// FilterStyle ... +type FilterStyle struct { + Type FilterType `json:"type"` + Style string `json:"style"` + Values []string `json:"values,omitempty"` +} + +// RegistryInfo provides base info and capability declarations of the registry +type RegistryInfo struct { + Type RegistryType `json:"type"` + Description string `json:"description"` + SupportedResourceTypes []ResourceType `json:"-"` + SupportedResourceFilters []*FilterStyle `json:"supported_resource_filters"` + SupportedTriggers []TriggerType `json:"supported_triggers"` +} diff --git a/src/replication/ng/operation/controller.go b/src/replication/ng/operation/controller.go index e38ebd27c..4b60380e6 100644 --- a/src/replication/ng/operation/controller.go +++ b/src/replication/ng/operation/controller.go @@ -98,7 +98,7 @@ func (d *defaultController) createFlow(executionID int64, policy *model.Policy, Value: resource.Metadata.Name, }, { - Type: model.FilterTypeVersion, + Type: model.FilterTypeTag, // only support replicate one tag Value: resource.Metadata.Vtags[0], },