From 2863e687189a8c178443b5ea219d77a21815d235 Mon Sep 17 00:00:00 2001 From: chlins Date: Sun, 12 Jul 2020 13:43:16 +0800 Subject: [PATCH] feat: add task controller Signed-off-by: chlins --- src/controller/task/controller.go | 80 +++++++++++++ src/controller/task/controller_test.go | 82 ++++++++++++++ src/controller/task/execution_controller.go | 105 ++++++++++++++++++ .../task/execution_controller_test.go | 98 ++++++++++++++++ 4 files changed, 365 insertions(+) create mode 100644 src/controller/task/controller.go create mode 100644 src/controller/task/controller_test.go create mode 100644 src/controller/task/execution_controller.go create mode 100644 src/controller/task/execution_controller_test.go diff --git a/src/controller/task/controller.go b/src/controller/task/controller.go new file mode 100644 index 000000000..7d570cd0f --- /dev/null +++ b/src/controller/task/controller.go @@ -0,0 +1,80 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package task + +import ( + "context" + + "github.com/goharbor/harbor/src/lib/q" + "github.com/goharbor/harbor/src/pkg/task" +) + +var ( + // Ctl is a global task controller instance + Ctl = NewController() +) + +// Controller manages the task +type Controller interface { + // Create submits the job to jobservice and creates a corresponding task record. + // An execution must be created first and the task will be linked to it. + // The "extraAttrs" can be used to set the customized attributes. + Create(ctx context.Context, executionID int64, job *task.Job, extraAttrs ...map[string]interface{}) (id int64, err error) + // Stop the specified task. + Stop(ctx context.Context, id int64) (err error) + // Get the specified task. + Get(ctx context.Context, id int64) (task *task.Task, err error) + // List the tasks according to the query. + List(ctx context.Context, query *q.Query) (tasks []*task.Task, err error) + // Get the log of the specified task. + GetLog(ctx context.Context, id int64) (log []byte, err error) +} + +// NewController creates an instance of the default task controller. +func NewController() Controller { + return &controller{ + mgr: task.Mgr, + } +} + +// controller defines the default task controller. +type controller struct { + mgr task.Manager +} + +// Create submits the job to jobservice and creates a corresponding task record. +func (c *controller) Create(ctx context.Context, executionID int64, job *task.Job, extraAttrs ...map[string]interface{}) (id int64, err error) { + return c.mgr.Create(ctx, executionID, job, extraAttrs...) +} + +// Stop the specified task. +func (c *controller) Stop(ctx context.Context, id int64) (err error) { + return c.mgr.Stop(ctx, id) +} + +// Get the specified task. +func (c *controller) Get(ctx context.Context, id int64) (task *task.Task, err error) { + return c.mgr.Get(ctx, id) +} + +// List the tasks according to the query. +func (c *controller) List(ctx context.Context, query *q.Query) (tasks []*task.Task, err error) { + return c.mgr.List(ctx, query) +} + +// Get the log of the specified task. +func (c *controller) GetLog(ctx context.Context, id int64) (log []byte, err error) { + return c.mgr.GetLog(ctx, id) +} diff --git a/src/controller/task/controller_test.go b/src/controller/task/controller_test.go new file mode 100644 index 000000000..f223554a5 --- /dev/null +++ b/src/controller/task/controller_test.go @@ -0,0 +1,82 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package task + +import ( + "testing" + + model "github.com/goharbor/harbor/src/pkg/task" + "github.com/goharbor/harbor/src/testing/mock" + "github.com/goharbor/harbor/src/testing/pkg/task" + "github.com/stretchr/testify/suite" +) + +type controllerTestSuite struct { + suite.Suite + ctl *controller + mgr *task.FakeManager +} + +// TestControllerTestSuite tests controller. +func TestControllerTestSuite(t *testing.T) { + suite.Run(t, &controllerTestSuite{}) +} + +// SetupTest setups the testing env. +func (c *controllerTestSuite) SetupTest() { + c.mgr = &task.FakeManager{} + c.ctl = &controller{mgr: c.mgr} +} + +// TestCreate tests create. +func (c *controllerTestSuite) TestCreate() { + c.mgr.On("Create", mock.Anything, mock.Anything, mock.Anything).Return(int64(1), nil) + id, err := c.ctl.Create(nil, 1, nil) + c.NoError(err) + c.Equal(int64(1), id) +} + +// TestStop tests stop. +func (c *controllerTestSuite) TestStop() { + c.mgr.On("Stop", mock.Anything, mock.Anything).Return(nil) + err := c.ctl.Stop(nil, 1) + c.NoError(err) +} + +// TestGet tests get. +func (c *controllerTestSuite) TestGet() { + c.mgr.On("Get", mock.Anything, int64(1)).Return(&model.Task{ID: 1}, nil) + t, err := c.ctl.Get(nil, 1) + c.NoError(err) + c.Equal(int64(1), t.ID) +} + +// TestList tests list. +func (c *controllerTestSuite) TestList() { + c.mgr.On("List", mock.Anything, mock.Anything).Return([]*model.Task{ + {ID: 1}, {ID: 2}, + }, nil) + ts, err := c.ctl.List(nil, nil) + c.NoError(err) + c.Len(ts, 2) +} + +// TestGetLog tests get log. +func (c *controllerTestSuite) TestGetLog() { + c.mgr.On("GetLog", mock.Anything, mock.Anything).Return([]byte("logs"), nil) + l, err := c.ctl.GetLog(nil, 1) + c.NoError(err) + c.Equal([]byte("logs"), l) +} diff --git a/src/controller/task/execution_controller.go b/src/controller/task/execution_controller.go new file mode 100644 index 000000000..8fdb6e1fe --- /dev/null +++ b/src/controller/task/execution_controller.go @@ -0,0 +1,105 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package task + +import ( + "context" + + "github.com/goharbor/harbor/src/lib/q" + "github.com/goharbor/harbor/src/pkg/task" +) + +// ExecutionController manages the execution. +type ExecutionController interface { + // Create an execution. The "vendorType" specifies the type of vendor (e.g. replication, scan, gc, retention, etc.), + // and the "vendorID" specifies the ID of vendor if needed(e.g. policy ID for replication and retention). + // The "extraAttrs" can be used to set the customized attributes. + Create(ctx context.Context, vendorType string, vendorID int64, trigger string, + extraAttrs ...map[string]interface{}) (id int64, err error) + // MarkDone marks the status of the specified execution as success. + // It must be called to update the execution status if the created execution contains no tasks. + // In other cases, the execution status can be calculated from the referenced tasks automatically + // and no need to update it explicitly. + MarkDone(ctx context.Context, id int64, message string) (err error) + // MarkError marks the status of the specified execution as error. + // It must be called to update the execution status when failed to create tasks. + // In other cases, the execution status can be calculated from the referenced tasks automatically + // and no need to update it explicitly. + MarkError(ctx context.Context, id int64, message string) (err error) + // Stop all linked tasks of the specified execution. + Stop(ctx context.Context, id int64) (err error) + // Delete the specified execution and its tasks. + Delete(ctx context.Context, id int64) (err error) + // Get the specified execution. + Get(ctx context.Context, id int64) (execution *task.Execution, err error) + // List executions according to the query. + List(ctx context.Context, query *q.Query) (executions []*task.Execution, err error) +} + +// executionController defines the execution controller. +type executionController struct { + mgr task.ExecutionManager +} + +// NewController creates an instance of the default execution controller. +func NewExecutionController() ExecutionController { + return &executionController{ + mgr: task.ExecMgr, + } +} + +// Create an execution. The "vendorType" specifies the type of vendor (e.g. replication, scan, gc, retention, etc.), +// and the "vendorID" specifies the ID of vendor if needed(e.g. policy ID for replication and retention). +// The "extraAttrs" can be used to set the customized attributes. +func (ec *executionController) Create(ctx context.Context, vendorType string, vendorID int64, trigger string, + extraAttrs ...map[string]interface{}) (id int64, err error) { + return ec.mgr.Create(ctx, vendorType, vendorID, trigger, extraAttrs...) +} + +// MarkDone marks the status of the specified execution as success. +// It must be called to update the execution status if the created execution contains no tasks. +// In other cases, the execution status can be calculated from the referenced tasks automatically +// and no need to update it explicitly. +func (ec *executionController) MarkDone(ctx context.Context, id int64, message string) (err error) { + return ec.mgr.MarkDone(ctx, id, message) +} + +// MarkError marks the status of the specified execution as error. +// It must be called to update the execution status when failed to create tasks. +// In other cases, the execution status can be calculated from the referenced tasks automatically +// and no need to update it explicitly. +func (ec *executionController) MarkError(ctx context.Context, id int64, message string) (err error) { + return ec.mgr.MarkError(ctx, id, message) +} + +// Stop all linked tasks of the specified execution. +func (ec *executionController) Stop(ctx context.Context, id int64) (err error) { + return ec.mgr.Stop(ctx, id) +} + +// Delete the specified execution and its tasks. +func (ec *executionController) Delete(ctx context.Context, id int64) (err error) { + return ec.mgr.Delete(ctx, id) +} + +// Get the specified execution. +func (ec *executionController) Get(ctx context.Context, id int64) (execution *task.Execution, err error) { + return ec.mgr.Get(ctx, id) +} + +// List executions according to the query. +func (ec *executionController) List(ctx context.Context, query *q.Query) (executions []*task.Execution, err error) { + return ec.mgr.List(ctx, query) +} diff --git a/src/controller/task/execution_controller_test.go b/src/controller/task/execution_controller_test.go new file mode 100644 index 000000000..0c6202179 --- /dev/null +++ b/src/controller/task/execution_controller_test.go @@ -0,0 +1,98 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package task + +import ( + "testing" + + model "github.com/goharbor/harbor/src/pkg/task" + "github.com/goharbor/harbor/src/testing/mock" + "github.com/goharbor/harbor/src/testing/pkg/task" + "github.com/stretchr/testify/suite" +) + +type executionControllerTestSuite struct { + suite.Suite + ctl *executionController + mgr *task.FakeExecutionManager +} + +// TestExecutionControllerTestSuite tests controller. +func TestExecutionControllerTestSuite(t *testing.T) { + suite.Run(t, &executionControllerTestSuite{}) +} + +// SetupTest setups the testing env. +func (ec *executionControllerTestSuite) SetupTest() { + ec.mgr = &task.FakeExecutionManager{} + ec.ctl = &executionController{ + mgr: ec.mgr, + } +} + +// TestCreate tests create. +func (ec *executionControllerTestSuite) TestCreate() { + ec.mgr.On("Create", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(int64(1), nil) + id, err := ec.ctl.Create(nil, "", 1, "") + ec.NoError(err) + ec.Equal(int64(1), id) +} + +// TestMarkDown tests mark down. +func (ec *executionControllerTestSuite) TestMarkDone() { + ec.mgr.On("MarkDone", mock.Anything, mock.Anything, mock.Anything).Return(nil) + err := ec.ctl.MarkDone(nil, 1, "") + ec.NoError(err) +} + +// TestMarkError tests mark error. +func (ec *executionControllerTestSuite) TestMarkError() { + ec.mgr.On("MarkError", mock.Anything, mock.Anything, mock.Anything).Return(nil) + err := ec.ctl.MarkError(nil, 1, "") + ec.NoError(err) +} + +// TestStop tests stop. +func (ec *executionControllerTestSuite) TestStop() { + ec.mgr.On("Stop", mock.Anything, mock.Anything).Return(nil) + err := ec.ctl.Stop(nil, 1) + ec.NoError(err) +} + +// TestDelete tests delete. +func (ec *executionControllerTestSuite) TestDelete() { + ec.mgr.On("Delete", mock.Anything, mock.Anything).Return(nil) + err := ec.ctl.Delete(nil, 1) + ec.NoError(err) +} + +// TestGet tests get. +func (ec *executionControllerTestSuite) TestGet() { + ec.mgr.On("Get", mock.Anything, mock.Anything).Return(&model.Execution{ID: 1}, nil) + e, err := ec.ctl.Get(nil, 1) + ec.NoError(err) + ec.Equal(int64(1), e.ID) +} + +// TestList tests list. +func (ec *executionControllerTestSuite) TestList() { + ec.mgr.On("List", mock.Anything, mock.Anything).Return([]*model.Execution{ + {ID: 1}, + {ID: 2}, + }, nil) + es, err := ec.ctl.List(nil, nil) + ec.NoError(err) + ec.Len(es, 2) +}