feat: add p2p preheat swagger yaml and implement preheat api policy handler

Signed-off-by: chlins <chlins.zhang@gmail.com>
This commit is contained in:
chlins 2020-07-04 17:02:54 +08:00
parent 254ea193fa
commit 37a00912b7
10 changed files with 554 additions and 0 deletions

View File

@ -814,6 +814,151 @@ paths:
$ref: '#/responses/404' $ref: '#/responses/404'
'500': '500':
$ref: '#/responses/500' $ref: '#/responses/500'
/projects/{project_name}/preheat/policies:
post:
summary: Create a preheat policy under a project
description: Create a preheat policy under a project
tags:
- preheat
operationId: CreatePolicy
parameters:
- $ref: '#/parameters/requestId'
- $ref: '#/parameters/projectName'
- name: policy
in: body
description: The policy schema info
required: true
schema:
$ref: '#/definitions/PreheatPolicy'
responses:
'201':
description: Create policy success
schema:
$ref: '#/responses/201'
'400':
$ref: '#/responses/400'
'401':
$ref: '#/responses/401'
'403':
$ref: '#/responses/403'
'409':
$ref: '#/responses/409'
'500':
$ref: '#/responses/500'
get:
summary: List preheat policies
description: List preheat policies
tags:
- preheat
operationId: ListPolicies
parameters:
- $ref: '#/parameters/requestId'
- $ref: '#/parameters/projectName'
- $ref: '#/parameters/page'
- $ref: '#/parameters/pageSize'
- $ref: '#/parameters/query'
responses:
'200':
description: List preheat policies success
headers:
X-Total-Count:
description: The total count of tags
type: integer
Link:
description: Link refers to the previous page and next page
type: string
schema:
type: array
items:
$ref: '#/definitions/PreheatPolicy'
'400':
$ref: '#/responses/400'
'401':
$ref: '#/responses/401'
'403':
$ref: '#/responses/403'
'500':
$ref: '#/responses/500'
/projects/{project_name}/preheat/policies/{preheat_policy_name}:
get:
summary: Get a preheat policy
description: Get a preheat policy
tags:
- preheat
operationId: GetPolicy
parameters:
- $ref: '#/parameters/requestId'
- $ref: '#/parameters/projectName'
- $ref: '#/parameters/preheatPolicyName'
responses:
'200':
description: Get a preheat policy success
schema:
$ref: '#/definitions/PreheatPolicy'
'400':
$ref: '#/responses/400'
'401':
$ref: '#/responses/401'
'404':
$ref: '#/responses/404'
'403':
$ref: '#/responses/403'
'500':
$ref: '#/responses/500'
put:
summary: Update preheat policy
description: Update preheat policy
tags:
- preheat
operationId: UpdatePolicy
parameters:
- $ref: '#/parameters/requestId'
- $ref: '#/parameters/projectName'
- $ref: '#/parameters/preheatPolicyName'
- name: policy
in: body
description: The policy schema info
required: true
schema:
$ref: '#/definitions/PreheatPolicy'
responses:
'200':
$ref: '#/responses/200'
'400':
$ref: '#/responses/400'
'401':
$ref: '#/responses/401'
'404':
$ref: '#/responses/404'
'403':
$ref: '#/responses/403'
'409':
$ref: '#/responses/409'
'500':
$ref: '#/responses/500'
delete:
summary: Delete a preheat policy
description: Delete a preheat policy
tags:
- preheat
operationId: DeletePolicy
parameters:
- $ref: '#/parameters/requestId'
- $ref: '#/parameters/projectName'
- $ref: '#/parameters/preheatPolicyName'
responses:
'200':
$ref: '#/responses/200'
'400':
$ref: '#/responses/400'
'401':
$ref: '#/responses/401'
'404':
$ref: '#/responses/404'
'403':
$ref: '#/responses/403'
'500':
$ref: '#/responses/500'
parameters: parameters:
query: query:
name: q name: q
@ -880,6 +1025,13 @@ parameters:
description: Instance ID description: Instance ID
required: true required: true
type: integer type: integer
preheatPolicyName:
name: preheat_policy_name
in: path
description: Preheat Policy Name
required: true
type: string
responses: responses:
'200': '200':
description: Success description: Success
@ -1360,3 +1512,38 @@ definitions:
id: id:
type: integer type: integer
description: ID of instance created description: ID of instance created
PreheatPolicy:
type: object
properties:
id:
type: integer
description: The ID of preheat policy
name:
type: string
description: The Name of preheat policy
description:
type: string
description: The Description of preheat policy
project_id:
type: integer
description: The ID of preheat policy project
provider_id:
type: integer
description: The ID of preheat policy provider
filters:
type: string
description: The Filters of preheat policy
trigger:
type: string
description: The Trigger of preheat policy
enabled:
type: boolean
description: Whether the preheat policy enabled
creation_time:
type: string
format: date-time
description: The Create Time of preheat policy
update_time:
type: string
format: date-time
description: The Update Time of preheat policy

View File

@ -95,6 +95,8 @@ type Controller interface {
CreatePolicy(ctx context.Context, schema *policyModels.Schema) (int64, error) CreatePolicy(ctx context.Context, schema *policyModels.Schema) (int64, error)
// GetPolicy gets the policy by id. // GetPolicy gets the policy by id.
GetPolicy(ctx context.Context, id int64) (*policyModels.Schema, error) GetPolicy(ctx context.Context, id int64) (*policyModels.Schema, error)
// GetPolicyByName gets the policy by name.
GetPolicyByName(ctx context.Context, projectID int64, name string) (*policyModels.Schema, error)
// UpdatePolicy updates the policy. // UpdatePolicy updates the policy.
UpdatePolicy(ctx context.Context, schema *policyModels.Schema, props ...string) error UpdatePolicy(ctx context.Context, schema *policyModels.Schema, props ...string) error
// DeletePolicy deletes the policy by id. // DeletePolicy deletes the policy by id.
@ -203,6 +205,11 @@ func (c *controller) GetPolicy(ctx context.Context, id int64) (*policyModels.Sch
return c.pManager.Get(ctx, id) return c.pManager.Get(ctx, id)
} }
// GetPolicyByName gets the policy by name.
func (c *controller) GetPolicyByName(ctx context.Context, projectID int64, name string) (*policyModels.Schema, error) {
return c.pManager.GetByName(ctx, projectID, name)
}
// UpdatePolicy updates the policy. // UpdatePolicy updates the policy.
func (c *controller) UpdatePolicy(ctx context.Context, schema *policyModels.Schema, props ...string) error { func (c *controller) UpdatePolicy(ctx context.Context, schema *policyModels.Schema, props ...string) error {
return c.pManager.Update(ctx, schema, props...) return c.pManager.Update(ctx, schema, props...)

View File

@ -181,6 +181,13 @@ func (s *preheatSuite) TestGetPolicy() {
s.Equal("test", p.Name) s.Equal("test", p.Name)
} }
func (s *preheatSuite) TestGetPolicyByName() {
s.fakePolicyMgr.On("GetByName", s.ctx, int64(1), "test").Return(&policy.Schema{Name: "test"}, nil)
p, err := s.controller.GetPolicyByName(s.ctx, 1, "test")
s.NoError(err)
s.Equal("test", p.Name)
}
func (s *preheatSuite) TestUpdatePolicy() { func (s *preheatSuite) TestUpdatePolicy() {
s.fakePolicyMgr.On("Update", s.ctx, mock.Anything, mock.Anything).Return(nil) s.fakePolicyMgr.On("Update", s.ctx, mock.Anything, mock.Anything).Return(nil)
err := s.controller.UpdateInstance(s.ctx, nil, "") err := s.controller.UpdateInstance(s.ctx, nil, "")

View File

@ -34,6 +34,8 @@ type DAO interface {
Update(ctx context.Context, schema *policy.Schema, props ...string) (err error) Update(ctx context.Context, schema *policy.Schema, props ...string) (err error)
// Get the policy schema by id // Get the policy schema by id
Get(ctx context.Context, id int64) (schema *policy.Schema, err error) Get(ctx context.Context, id int64) (schema *policy.Schema, err error)
// Get the policy schema by name
GetByName(ctx context.Context, projectID int64, name string) (schema *policy.Schema, err error)
// Delete the policy schema by id // Delete the policy schema by id
Delete(ctx context.Context, id int64) (err error) Delete(ctx context.Context, id int64) (err error)
// List policy schemas by query // List policy schemas by query
@ -122,6 +124,25 @@ func (d *dao) Get(ctx context.Context, id int64) (schema *policy.Schema, err err
return schema, nil return schema, nil
} }
// GetByName gets a policy schema by name.
func (d *dao) GetByName(ctx context.Context, projectID int64, name string) (schema *policy.Schema, err error) {
var ormer beego_orm.Ormer
ormer, err = orm.FromContext(ctx)
if err != nil {
return
}
schema = &policy.Schema{Name: name, ProjectID: projectID}
if err = ormer.Read(schema, "Name", "ProjectID"); err != nil {
if e := orm.AsNotFoundError(err, "policy %s not found", name); e != nil {
err = e
}
return nil, err
}
return schema, nil
}
// Delete a policy schema by id. // Delete a policy schema by id.
func (d *dao) Delete(ctx context.Context, id int64) (err error) { func (d *dao) Delete(ctx context.Context, id int64) (err error) {
var ormer beego_orm.Ormer var ormer beego_orm.Ormer

View File

@ -107,6 +107,19 @@ func (d *daoTestSuite) TestGet() {
d.True(errors.IsErr(err, errors.NotFoundCode)) d.True(errors.IsErr(err, errors.NotFoundCode))
} }
// GetByName tests get a policy schema by name.
func (d *daoTestSuite) TestGetByName() {
policy, err := d.dao.GetByName(d.ctx, 1, "default-policy")
d.Require().Nil(err)
d.Require().NotNil(policy)
d.Equal(d.defaultPolicy.Name, policy.Name, "get a default policy")
// not found
_, err = d.dao.GetByName(d.ctx, 2, "default-policy")
d.Require().NotNil(err)
d.True(errors.IsErr(err, errors.NotFoundCode))
}
// Update tests update a policy schema. // Update tests update a policy schema.
func (d *daoTestSuite) TestUpdate() { func (d *daoTestSuite) TestUpdate() {
newDesc := "test update" newDesc := "test update"

View File

@ -35,6 +35,8 @@ type Manager interface {
Update(ctx context.Context, schema *policy.Schema, props ...string) (err error) Update(ctx context.Context, schema *policy.Schema, props ...string) (err error)
// Get the policy schema by id // Get the policy schema by id
Get(ctx context.Context, id int64) (schema *policy.Schema, err error) Get(ctx context.Context, id int64) (schema *policy.Schema, err error)
// GetByName the policy schema by id
GetByName(ctx context.Context, projectID int64, name string) (schema *policy.Schema, err error)
// Delete the policy schema by id // Delete the policy schema by id
Delete(ctx context.Context, id int64) (err error) Delete(ctx context.Context, id int64) (err error)
// List policy schemas by query // List policy schemas by query
@ -74,6 +76,11 @@ func (m *manager) Get(ctx context.Context, id int64) (schema *policy.Schema, err
return m.dao.Get(ctx, id) return m.dao.Get(ctx, id)
} }
// Get the policy schema by name
func (m *manager) GetByName(ctx context.Context, projectID int64, name string) (schema *policy.Schema, err error) {
return m.dao.GetByName(ctx, projectID, name)
}
// Delete the policy schema by id // Delete the policy schema by id
func (m *manager) Delete(ctx context.Context, id int64) (err error) { func (m *manager) Delete(ctx context.Context, id int64) (err error) {
return m.dao.Delete(ctx, id) return m.dao.Delete(ctx, id)

View File

@ -48,6 +48,14 @@ func (f *fakeDao) Get(ctx context.Context, id int64) (*policy.Schema, error) {
} }
return schema, args.Error(1) return schema, args.Error(1)
} }
func (f *fakeDao) GetByName(ctx context.Context, projectID int64, name string) (*policy.Schema, error) {
args := f.Called()
var schema *policy.Schema
if args.Get(0) != nil {
schema = args.Get(0).(*policy.Schema)
}
return schema, args.Error(1)
}
func (f *fakeDao) Delete(ctx context.Context, id int64) error { func (f *fakeDao) Delete(ctx context.Context, id int64) error {
args := f.Called() args := f.Called()
return args.Error(0) return args.Error(0)
@ -112,6 +120,13 @@ func (m *managerTestSuite) TestGet() {
m.Require().Nil(err) m.Require().Nil(err)
} }
// TestGetByName tests Get method.
func (m *managerTestSuite) TestGetByName() {
m.dao.On("GetByName").Return(nil, nil)
_, err := m.mgr.Get(nil, 1)
m.Require().Nil(err)
}
// TestDelete tests Delete method. // TestDelete tests Delete method.
func (m *managerTestSuite) TestDelete() { func (m *managerTestSuite) TestDelete() {
m.dao.On("Delete").Return(nil) m.dao.On("Delete").Return(nil)

View File

@ -2,9 +2,16 @@ package handler
import ( import (
"context" "context"
"errors"
"time"
"github.com/go-openapi/strfmt"
"github.com/goharbor/harbor/src/pkg/p2p/preheat/models/policy"
"github.com/go-openapi/runtime/middleware" "github.com/go-openapi/runtime/middleware"
preheatCtl "github.com/goharbor/harbor/src/controller/p2p/preheat" preheatCtl "github.com/goharbor/harbor/src/controller/p2p/preheat"
projectCtl "github.com/goharbor/harbor/src/controller/project"
"github.com/goharbor/harbor/src/pkg/p2p/preheat/provider" "github.com/goharbor/harbor/src/pkg/p2p/preheat/provider"
"github.com/goharbor/harbor/src/server/v2.0/models" "github.com/goharbor/harbor/src/server/v2.0/models"
"github.com/goharbor/harbor/src/server/v2.0/restapi" "github.com/goharbor/harbor/src/server/v2.0/restapi"
@ -14,6 +21,7 @@ import (
func newPreheatAPI() *preheatAPI { func newPreheatAPI() *preheatAPI {
return &preheatAPI{ return &preheatAPI{
preheatCtl: preheatCtl.Ctl, preheatCtl: preheatCtl.Ctl,
projectCtl: projectCtl.Ctl,
} }
} }
@ -22,6 +30,7 @@ var _ restapi.PreheatAPI = (*preheatAPI)(nil)
type preheatAPI struct { type preheatAPI struct {
BaseAPI BaseAPI
preheatCtl preheatCtl.Controller preheatCtl preheatCtl.Controller
projectCtl projectCtl.Controller
} }
func (api *preheatAPI) Prepare(ctx context.Context, operation string, params interface{}) middleware.Responder { func (api *preheatAPI) Prepare(ctx context.Context, operation string, params interface{}) middleware.Responder {
@ -80,3 +89,149 @@ func convertProvidersToFrontend(backend []*provider.Metadata) (frontend []*model
} }
return return
} }
// GetPolicy is Get a preheat policy
func (api *preheatAPI) GetPolicy(ctx context.Context, params operation.GetPolicyParams) middleware.Responder {
project, err := api.projectCtl.GetByName(ctx, params.ProjectName)
if err != nil {
return api.SendError(ctx, err)
}
var payload *models.PreheatPolicy
policy, err := api.preheatCtl.GetPolicyByName(ctx, project.ProjectID, params.PreheatPolicyName)
if err != nil {
return api.SendError(ctx, err)
}
payload, err = convertPolicyToPayload(policy)
if err != nil {
return api.SendError(ctx, err)
}
return operation.NewGetPolicyOK().WithPayload(payload)
}
// CreatePolicy is Create a preheat policy under a project
func (api *preheatAPI) CreatePolicy(ctx context.Context, params operation.CreatePolicyParams) middleware.Responder {
policy, err := convertParamPolicyToModelPolicy(params.Policy)
if err != nil {
return api.SendError(ctx, err)
}
_, err = api.preheatCtl.CreatePolicy(ctx, policy)
if err != nil {
return api.SendError(ctx, err)
}
return operation.NewCreatePolicyCreated()
}
// UpdatePolicy is Update preheat policy
func (api *preheatAPI) UpdatePolicy(ctx context.Context, params operation.UpdatePolicyParams) middleware.Responder {
policy, err := convertParamPolicyToModelPolicy(params.Policy)
if err != nil {
return api.SendError(ctx, err)
}
err = api.preheatCtl.UpdatePolicy(ctx, policy)
if err != nil {
return api.SendError(ctx, err)
}
return operation.NewUpdatePolicyOK()
}
// DeletePolicy is Delete a preheat policy
func (api *preheatAPI) DeletePolicy(ctx context.Context, params operation.DeletePolicyParams) middleware.Responder {
project, err := api.projectCtl.GetByName(ctx, params.ProjectName)
if err != nil {
return api.SendError(ctx, err)
}
policy, err := api.preheatCtl.GetPolicyByName(ctx, project.ProjectID, params.PreheatPolicyName)
if err != nil {
return api.SendError(ctx, err)
}
err = api.preheatCtl.DeletePolicy(ctx, policy.ID)
if err != nil {
return api.SendError(ctx, err)
}
return operation.NewDeleteInstanceOK()
}
// ListPolicies is List preheat policies
func (api *preheatAPI) ListPolicies(ctx context.Context, params operation.ListPoliciesParams) middleware.Responder {
project, err := api.projectCtl.GetByName(ctx, params.ProjectName)
if err != nil {
return api.SendError(ctx, err)
}
query, err := api.BuildQuery(ctx, params.Q, params.Page, params.PageSize)
if err != nil {
return api.SendError(ctx, err)
}
if query != nil {
query.Keywords["project_id"] = project.ProjectID
}
total, err := api.preheatCtl.CountPolicy(ctx, query)
if err != nil {
return api.SendError(ctx, err)
}
policies, err := api.preheatCtl.ListPolicies(ctx, query)
if err != nil {
return api.SendError(ctx, err)
}
var payload []*models.PreheatPolicy
for _, policy := range policies {
p, err := convertPolicyToPayload(policy)
if err != nil {
return api.SendError(ctx, err)
}
payload = append(payload, p)
}
return operation.NewListPoliciesOK().WithPayload(payload).WithXTotalCount(total).
WithLink(api.Links(ctx, params.HTTPRequest.URL, total, query.PageNumber, query.PageSize).String())
}
// convertPolicyToPayload converts model policy to swagger model
func convertPolicyToPayload(policy *policy.Schema) (*models.PreheatPolicy, error) {
if policy == nil {
return nil, errors.New("policy can not be nil")
}
return &models.PreheatPolicy{
CreationTime: strfmt.DateTime(policy.CreatedAt),
Description: policy.Description,
Enabled: policy.Enabled,
Filters: policy.FiltersStr,
ID: policy.ID,
Name: policy.Name,
ProjectID: policy.ProjectID,
ProviderID: policy.ProviderID,
Trigger: policy.TriggerStr,
UpdateTime: strfmt.DateTime(policy.UpdatedTime),
}, nil
}
// convertParamPolicyToPolicy converts params policy to pkg model policy
func convertParamPolicyToModelPolicy(model *models.PreheatPolicy) (*policy.Schema, error) {
if model == nil {
return nil, errors.New("policy can not be nil")
}
return &policy.Schema{
ID: model.ID,
Name: model.Name,
Description: model.Description,
ProjectID: model.ProjectID,
ProviderID: model.ProviderID,
FiltersStr: model.Filters,
TriggerStr: model.Trigger,
Enabled: model.Enabled,
CreatedAt: time.Time(model.CreationTime),
UpdatedTime: time.Time(model.UpdateTime),
}, nil
}

View File

@ -3,9 +3,13 @@ package handler
import ( import (
"reflect" "reflect"
"testing" "testing"
"time"
"github.com/go-openapi/strfmt"
"github.com/goharbor/harbor/src/pkg/p2p/preheat/models/policy"
"github.com/goharbor/harbor/src/pkg/p2p/preheat/provider" "github.com/goharbor/harbor/src/pkg/p2p/preheat/provider"
"github.com/goharbor/harbor/src/server/v2.0/models" "github.com/goharbor/harbor/src/server/v2.0/models"
"github.com/stretchr/testify/assert"
) )
func Test_convertProvidersToFrontend(t *testing.T) { func Test_convertProvidersToFrontend(t *testing.T) {
@ -31,3 +35,118 @@ func Test_convertProvidersToFrontend(t *testing.T) {
}) })
} }
} }
func Test_convertPolicyToPayload(t *testing.T) {
tests := []struct {
name string
input *policy.Schema
expect *models.PreheatPolicy
shouldErr bool
}{
{
name: "should error",
input: nil,
expect: nil,
shouldErr: true,
},
{
name: "should success",
input: &policy.Schema{
ID: 0,
Name: "abc",
Description: "test case",
ProjectID: 0,
ProviderID: 0,
Filters: nil,
FiltersStr: "",
Trigger: nil,
TriggerStr: "",
Enabled: false,
CreatedAt: time.Time{},
UpdatedTime: time.Time{},
},
expect: &models.PreheatPolicy{
CreationTime: strfmt.DateTime{},
Description: "test case",
Enabled: false,
Filters: "",
ID: 0,
Name: "abc",
ProjectID: 0,
ProviderID: 0,
Trigger: "",
UpdateTime: strfmt.DateTime{},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
actual, err := convertPolicyToPayload(tt.input)
if !tt.shouldErr {
if !assert.Equal(t, tt.expect, actual) {
t.Errorf("convertPolicyToPayload() = %#v, want %#v", actual, tt.expect)
}
} else {
assert.NotNil(t, err)
}
})
}
}
func Test_convertParamPolicyToModelPolicy(t *testing.T) {
tests := []struct {
name string
input *models.PreheatPolicy
expect *policy.Schema
shouldErr bool
}{
{
name: "should err",
input: nil,
expect: nil,
shouldErr: true,
},
{
name: "should success",
input: &models.PreheatPolicy{
CreationTime: strfmt.DateTime{},
Description: "test case",
Enabled: false,
Filters: "",
ID: 0,
Name: "abc",
ProjectID: 0,
ProviderID: 0,
Trigger: "",
UpdateTime: strfmt.DateTime{},
},
expect: &policy.Schema{
ID: 0,
Name: "abc",
Description: "test case",
ProjectID: 0,
ProviderID: 0,
Filters: nil,
FiltersStr: "",
Trigger: nil,
TriggerStr: "",
Enabled: false,
CreatedAt: time.Time{},
UpdatedTime: time.Time{},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
actual, err := convertParamPolicyToModelPolicy(tt.input)
if !tt.shouldErr {
if !assert.Equal(t, tt.expect, actual) {
t.Errorf("convertParamPolicyToModelPolicy() = %#v, want %#v", actual, tt.expect)
}
} else {
assert.NotNil(t, err)
}
})
}
}

View File

@ -95,6 +95,29 @@ func (_m *FakeManager) Get(ctx context.Context, id int64) (*modelspolicy.Schema,
return r0, r1 return r0, r1
} }
// GetByName provides a mock function with given fields: ctx, projectId, name
func (_m *FakeManager) GetByName(ctx context.Context, projectId int64, name string) (*modelspolicy.Schema, error) {
ret := _m.Called(ctx, projectId, name)
var r0 *modelspolicy.Schema
if rf, ok := ret.Get(0).(func(context.Context, int64, string) *modelspolicy.Schema); ok {
r0 = rf(ctx, projectId, name)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*modelspolicy.Schema)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, int64, string) error); ok {
r1 = rf(ctx, projectId, name)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// ListPolicies provides a mock function with given fields: ctx, query // ListPolicies provides a mock function with given fields: ctx, query
func (_m *FakeManager) ListPolicies(ctx context.Context, query *q.Query) ([]*modelspolicy.Schema, error) { func (_m *FakeManager) ListPolicies(ctx context.Context, query *q.Query) ([]*modelspolicy.Schema, error) {
ret := _m.Called(ctx, query) ret := _m.Called(ctx, query)