mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-26 04:05:40 +01:00
Introduce system artifact manager cleanup job (#16879)
Signed-off-by: prahaladdarkin <prahaladd@vmware.com>
This commit is contained in:
parent
b8a71ac348
commit
4d062c33d1
32
src/controller/systemartifact/callback.go
Normal file
32
src/controller/systemartifact/callback.go
Normal file
@ -0,0 +1,32 @@
|
||||
package systemartifact
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/goharbor/harbor/src/jobservice/logger"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/pkg/scheduler"
|
||||
"github.com/goharbor/harbor/src/pkg/task"
|
||||
)
|
||||
|
||||
const (
|
||||
SystemArtifactCleanupCallback = "SYSTEM_ARTIFACT_CLEANUP"
|
||||
)
|
||||
|
||||
var (
|
||||
cleanupController = Ctl
|
||||
)
|
||||
|
||||
func init() {
|
||||
if err := scheduler.RegisterCallbackFunc(SystemArtifactCleanupCallback, cleanupCallBack); err != nil {
|
||||
log.Fatalf("failed to register the callback for the system artifact cleanup schedule, error %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func cleanupCallBack(ctx context.Context, param string) error {
|
||||
|
||||
err := cleanupController.Start(ctx, true, task.ExecutionTriggerSchedule)
|
||||
if err != nil {
|
||||
logger.Errorf("System artifact cleanup job encountered errors: %v", err)
|
||||
}
|
||||
return err
|
||||
}
|
56
src/controller/systemartifact/callback_test.go
Normal file
56
src/controller/systemartifact/callback_test.go
Normal file
@ -0,0 +1,56 @@
|
||||
package systemartifact
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/goharbor/harbor/src/pkg/task"
|
||||
"github.com/goharbor/harbor/src/testing/controller/systemartifact"
|
||||
"github.com/goharbor/harbor/src/testing/mock"
|
||||
testifymock "github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type CallbackTestSuite struct {
|
||||
suite.Suite
|
||||
cleanupController *systemartifact.Controller
|
||||
}
|
||||
|
||||
func (suite *CallbackTestSuite) SetupSuite() {
|
||||
suite.cleanupController = &systemartifact.Controller{}
|
||||
cleanupController = suite.cleanupController
|
||||
}
|
||||
|
||||
func (suite *CallbackTestSuite) TestCleanupCallbackSuccess() {
|
||||
{
|
||||
ctx := context.TODO()
|
||||
suite.cleanupController.On("Start", mock.Anything, mock.Anything, mock.Anything).Return(nil)
|
||||
triggerScheduleMatcher := testifymock.MatchedBy(func(trigger string) bool {
|
||||
return trigger == task.ExecutionTriggerSchedule
|
||||
})
|
||||
err := cleanupCallBack(ctx, "")
|
||||
suite.NoErrorf(err, "Unexpected error : %v", err)
|
||||
suite.cleanupController.AssertCalled(suite.T(), "Start", mock.Anything, true, triggerScheduleMatcher)
|
||||
}
|
||||
{
|
||||
suite.cleanupController = nil
|
||||
suite.cleanupController = &systemartifact.Controller{}
|
||||
cleanupController = suite.cleanupController
|
||||
}
|
||||
|
||||
{
|
||||
ctx := context.TODO()
|
||||
suite.cleanupController.On("Start", mock.Anything, mock.Anything, mock.Anything).Return(errors.New("test error"))
|
||||
triggerScheduleMatcher := testifymock.MatchedBy(func(trigger string) bool {
|
||||
return trigger == task.ExecutionTriggerSchedule
|
||||
})
|
||||
err := cleanupCallBack(ctx, "")
|
||||
suite.Error(err)
|
||||
suite.cleanupController.AssertCalled(suite.T(), "Start", mock.Anything, true, triggerScheduleMatcher)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestCallbackTestSuite(t *testing.T) {
|
||||
suite.Run(t, &CallbackTestSuite{})
|
||||
}
|
156
src/controller/systemartifact/execution.go
Normal file
156
src/controller/systemartifact/execution.go
Normal file
@ -0,0 +1,156 @@
|
||||
package systemartifact
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/goharbor/harbor/src/jobservice/job"
|
||||
"github.com/goharbor/harbor/src/jobservice/logger"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
"github.com/goharbor/harbor/src/lib/retry"
|
||||
"github.com/goharbor/harbor/src/pkg/scheduler"
|
||||
"github.com/goharbor/harbor/src/pkg/systemartifact"
|
||||
"github.com/goharbor/harbor/src/pkg/task"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
VendorTypeSystemArtifactCleanup = "SYSTEM_ARTIFACT_CLEANUP"
|
||||
cronTypeDaily = "Daily"
|
||||
cronSpec = "0 0 0 * * *"
|
||||
)
|
||||
|
||||
var (
|
||||
sched = scheduler.Sched
|
||||
)
|
||||
|
||||
func init() {
|
||||
task.SetExecutionSweeperCount(VendorTypeSystemArtifactCleanup, 50)
|
||||
}
|
||||
|
||||
var Ctl = NewController()
|
||||
|
||||
type Controller interface {
|
||||
Start(ctx context.Context, async bool, trigger string) error
|
||||
}
|
||||
|
||||
func NewController() Controller {
|
||||
return &controller{
|
||||
execMgr: task.ExecMgr,
|
||||
taskMgr: task.Mgr,
|
||||
systemArtifactMgr: systemartifact.Mgr,
|
||||
makeCtx: orm.Context,
|
||||
}
|
||||
}
|
||||
|
||||
type controller struct {
|
||||
execMgr task.ExecutionManager
|
||||
taskMgr task.Manager
|
||||
systemArtifactMgr systemartifact.Manager
|
||||
makeCtx func() context.Context
|
||||
}
|
||||
|
||||
func (c *controller) Start(ctx context.Context, async bool, trigger string) error {
|
||||
execId, err := c.execMgr.Create(ctx, VendorTypeSystemArtifactCleanup, 0, trigger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// cleanup job would always be scheduled in async mode in production
|
||||
// allowing for sync mode execution only for test mode purposes
|
||||
// if there are any trigger settings then pass them to the cleanup manager first
|
||||
jobParams := job.Parameters{}
|
||||
|
||||
if !async {
|
||||
err := c.createCleanupTask(ctx, jobParams, execId)
|
||||
if err != nil {
|
||||
log.Errorf("failed to create system artifact clean-up task: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Info("Created job for scan data export successfully")
|
||||
return nil
|
||||
}
|
||||
go func(ctx context.Context) {
|
||||
err := retry.Retry(func() error {
|
||||
_, err := c.execMgr.Get(ctx, execId)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorf("failed to get the execution %d for the export data cleanup job", execId)
|
||||
return
|
||||
}
|
||||
err = c.createCleanupTask(ctx, jobParams, execId)
|
||||
if err != nil {
|
||||
logger.Errorf("Encountered error in scan data artifact cleanup : %v", err)
|
||||
return
|
||||
}
|
||||
}(c.makeCtx())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *controller) createCleanupTask(ctx context.Context, jobParams job.Parameters, execId int64) error {
|
||||
j := &task.Job{
|
||||
Name: job.SystemArtifactCleanup,
|
||||
Metadata: &job.Metadata{
|
||||
JobKind: job.KindGeneric,
|
||||
},
|
||||
Parameters: jobParams,
|
||||
}
|
||||
|
||||
_, err := c.taskMgr.Create(ctx, execId, j)
|
||||
|
||||
if err != nil {
|
||||
logger.Errorf("Unable to create a scan data export job in clean-up mode : %v", err)
|
||||
c.markError(ctx, execId, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *controller) markError(ctx context.Context, executionID int64, err error) {
|
||||
|
||||
// try to stop the execution first in case that some tasks are already created
|
||||
if err := c.execMgr.StopAndWait(ctx, executionID, 10*time.Second); err != nil {
|
||||
logger.Errorf("failed to stop the execution %d: %v", executionID, err)
|
||||
}
|
||||
if err := c.execMgr.MarkError(ctx, executionID, err.Error()); err != nil {
|
||||
logger.Errorf("failed to mark error for the execution %d: %v", executionID, err)
|
||||
}
|
||||
}
|
||||
|
||||
// ScheduleCleanupTask schedules a system artifact cleanup task
|
||||
func ScheduleCleanupTask(ctx context.Context) {
|
||||
scheduleSystemArtifactCleanJob(ctx)
|
||||
}
|
||||
|
||||
func scheduleSystemArtifactCleanJob(ctx context.Context) {
|
||||
schedule, err := getSystemArtifactCleanupSchedule(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if schedule != nil {
|
||||
logger.Debugf(" Export data cleanup job already scheduled with ID : %v.", schedule.ID)
|
||||
return
|
||||
}
|
||||
scheduleId, err := sched.Schedule(ctx, VendorTypeSystemArtifactCleanup, 0, cronTypeDaily, cronSpec, SystemArtifactCleanupCallback, nil, nil)
|
||||
if err != nil {
|
||||
log.Errorf("Encountered error when scheduling scan data export cleanup job : %v", err)
|
||||
return
|
||||
}
|
||||
log.Infof("Scheduled scan data export cleanup job with ID : %v", scheduleId)
|
||||
}
|
||||
|
||||
func getSystemArtifactCleanupSchedule(ctx context.Context) (*scheduler.Schedule, error) {
|
||||
query := q.New(map[string]interface{}{"vendor_type": VendorTypeSystemArtifactCleanup})
|
||||
schedules, err := sched.ListSchedules(ctx, query)
|
||||
if err != nil {
|
||||
logger.Errorf("Unable to check if export data cleanup job is already scheduled : %v", err)
|
||||
return nil, err
|
||||
}
|
||||
if len(schedules) > 0 {
|
||||
logger.Infof("Found export data cleanup job with schedule id : %v", schedules[0].ID)
|
||||
return schedules[0], nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
217
src/controller/systemartifact/execution_test.go
Normal file
217
src/controller/systemartifact/execution_test.go
Normal file
@ -0,0 +1,217 @@
|
||||
package systemartifact
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
scheduler2 "github.com/goharbor/harbor/src/pkg/scheduler"
|
||||
"github.com/goharbor/harbor/src/pkg/task"
|
||||
ormtesting "github.com/goharbor/harbor/src/testing/lib/orm"
|
||||
"github.com/goharbor/harbor/src/testing/mock"
|
||||
"github.com/goharbor/harbor/src/testing/pkg/scheduler"
|
||||
"github.com/goharbor/harbor/src/testing/pkg/systemartifact"
|
||||
testingTask "github.com/goharbor/harbor/src/testing/pkg/task"
|
||||
"github.com/pkg/errors"
|
||||
testifymock "github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type SystemArtifactCleanupTestSuite struct {
|
||||
suite.Suite
|
||||
execMgr *testingTask.ExecutionManager
|
||||
taskMgr *testingTask.Manager
|
||||
cleanupMgr *systemartifact.Manager
|
||||
ctl *controller
|
||||
sched *scheduler.Scheduler
|
||||
}
|
||||
|
||||
func (suite *SystemArtifactCleanupTestSuite) SetupSuite() {
|
||||
}
|
||||
|
||||
func (suite *SystemArtifactCleanupTestSuite) TestStartCleanup() {
|
||||
suite.taskMgr = &testingTask.Manager{}
|
||||
suite.execMgr = &testingTask.ExecutionManager{}
|
||||
suite.cleanupMgr = &systemartifact.Manager{}
|
||||
suite.ctl = &controller{
|
||||
execMgr: suite.execMgr,
|
||||
taskMgr: suite.taskMgr,
|
||||
systemArtifactMgr: suite.cleanupMgr,
|
||||
makeCtx: func() context.Context { return orm.NewContext(nil, &ormtesting.FakeOrmer{}) },
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
executionID := int64(1)
|
||||
taskId := int64(1)
|
||||
|
||||
suite.execMgr.On("Create", ctx, "SYSTEM_ARTIFACT_CLEANUP", int64(0), "SCHEDULE").Return(executionID, nil).Once()
|
||||
|
||||
suite.taskMgr.On("Create", ctx, executionID, mock.Anything).Return(taskId, nil).Once()
|
||||
|
||||
suite.execMgr.On("MarkDone", ctx, executionID, mock.Anything).Return(nil).Once()
|
||||
|
||||
err := suite.ctl.Start(ctx, false, "SCHEDULE")
|
||||
suite.NoError(err)
|
||||
jobMatcher := testifymock.MatchedBy(func(j *task.Job) bool {
|
||||
return "SYSTEM_ARTIFACT_CLEANUP" == j.Name
|
||||
})
|
||||
suite.taskMgr.AssertCalled(suite.T(), "Create", ctx, executionID, jobMatcher)
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *SystemArtifactCleanupTestSuite) TestStartCleanupErrorDuringCreate() {
|
||||
suite.taskMgr = &testingTask.Manager{}
|
||||
suite.execMgr = &testingTask.ExecutionManager{}
|
||||
suite.cleanupMgr = &systemartifact.Manager{}
|
||||
suite.ctl = &controller{
|
||||
execMgr: suite.execMgr,
|
||||
taskMgr: suite.taskMgr,
|
||||
systemArtifactMgr: suite.cleanupMgr,
|
||||
makeCtx: func() context.Context { return orm.NewContext(nil, &ormtesting.FakeOrmer{}) },
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
executionID := int64(1)
|
||||
|
||||
suite.execMgr.On(
|
||||
"Create", ctx, "SYSTEM_ARTIFACT_CLEANUP", int64(0), "SCHEDULE",
|
||||
).Return(int64(0), errors.New("test error")).Once()
|
||||
|
||||
suite.execMgr.On("MarkDone", ctx, executionID, mock.Anything).Return(nil).Once()
|
||||
|
||||
err := suite.ctl.Start(ctx, false, "SCHEDULE")
|
||||
suite.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *SystemArtifactCleanupTestSuite) TestStartCleanupErrorDuringTaskCreate() {
|
||||
suite.taskMgr = &testingTask.Manager{}
|
||||
suite.execMgr = &testingTask.ExecutionManager{}
|
||||
suite.cleanupMgr = &systemartifact.Manager{}
|
||||
suite.ctl = &controller{
|
||||
execMgr: suite.execMgr,
|
||||
taskMgr: suite.taskMgr,
|
||||
systemArtifactMgr: suite.cleanupMgr,
|
||||
makeCtx: func() context.Context { return orm.NewContext(nil, &ormtesting.FakeOrmer{}) },
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
executionID := int64(1)
|
||||
taskId := int64(0)
|
||||
|
||||
suite.execMgr.On(
|
||||
"Create", ctx, "SYSTEM_ARTIFACT_CLEANUP", int64(0), "SCHEDULE",
|
||||
).Return(executionID, nil).Once()
|
||||
|
||||
suite.taskMgr.On("Create", ctx, executionID, mock.Anything).Return(taskId, errors.New("test error")).Once()
|
||||
|
||||
suite.execMgr.On("MarkError", ctx, executionID, mock.Anything).Return(nil).Once()
|
||||
suite.execMgr.On("StopAndWait", ctx, executionID, mock.Anything).Return(nil).Once()
|
||||
|
||||
err := suite.ctl.Start(ctx, false, "SCHEDULE")
|
||||
suite.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *SystemArtifactCleanupTestSuite) TestScheduleCleanupJobNoPreviousSchedule() {
|
||||
suite.taskMgr = &testingTask.Manager{}
|
||||
suite.execMgr = &testingTask.ExecutionManager{}
|
||||
suite.cleanupMgr = &systemartifact.Manager{}
|
||||
suite.sched = &scheduler.Scheduler{}
|
||||
|
||||
suite.ctl = &controller{
|
||||
execMgr: suite.execMgr,
|
||||
taskMgr: suite.taskMgr,
|
||||
systemArtifactMgr: suite.cleanupMgr,
|
||||
makeCtx: func() context.Context { return orm.NewContext(nil, &ormtesting.FakeOrmer{}) },
|
||||
}
|
||||
|
||||
var extraAttrs map[string]interface{}
|
||||
suite.sched.On("Schedule", mock.Anything,
|
||||
VendorTypeSystemArtifactCleanup, int64(0), cronTypeDaily, cronSpec, SystemArtifactCleanupCallback, nil, extraAttrs).Return(int64(1), nil)
|
||||
suite.sched.On("ListSchedules", mock.Anything, mock.Anything).Return(make([]*scheduler2.Schedule, 0), nil)
|
||||
sched = suite.sched
|
||||
ctx := context.TODO()
|
||||
|
||||
ScheduleCleanupTask(ctx)
|
||||
|
||||
suite.sched.AssertCalled(suite.T(), "Schedule", mock.Anything,
|
||||
VendorTypeSystemArtifactCleanup, int64(0), cronTypeDaily, cronSpec, SystemArtifactCleanupCallback, nil, extraAttrs)
|
||||
}
|
||||
|
||||
func (suite *SystemArtifactCleanupTestSuite) TestScheduleCleanupJobPreviousSchedule() {
|
||||
suite.taskMgr = &testingTask.Manager{}
|
||||
suite.execMgr = &testingTask.ExecutionManager{}
|
||||
suite.cleanupMgr = &systemartifact.Manager{}
|
||||
suite.sched = &scheduler.Scheduler{}
|
||||
|
||||
suite.ctl = &controller{
|
||||
execMgr: suite.execMgr,
|
||||
taskMgr: suite.taskMgr,
|
||||
systemArtifactMgr: suite.cleanupMgr,
|
||||
makeCtx: func() context.Context { return orm.NewContext(nil, &ormtesting.FakeOrmer{}) },
|
||||
}
|
||||
|
||||
var extraAttrs map[string]interface{}
|
||||
suite.sched.On("Schedule", mock.Anything,
|
||||
VendorTypeSystemArtifactCleanup, int64(0), cronTypeDaily, cronSpec, SystemArtifactCleanupCallback, nil, extraAttrs).Return(int64(1), nil)
|
||||
|
||||
existingSchedule := scheduler2.Schedule{ID: int64(10)}
|
||||
suite.sched.On("ListSchedules", mock.Anything, mock.Anything).Return([]*scheduler2.Schedule{&existingSchedule}, nil)
|
||||
sched = suite.sched
|
||||
ctx := context.TODO()
|
||||
|
||||
ScheduleCleanupTask(ctx)
|
||||
|
||||
suite.sched.AssertNotCalled(suite.T(), "Schedule", mock.Anything,
|
||||
VendorTypeSystemArtifactCleanup, int64(0), cronTypeDaily, cronSpec, SystemArtifactCleanupCallback, nil, extraAttrs)
|
||||
}
|
||||
|
||||
func (suite *SystemArtifactCleanupTestSuite) TestScheduleCleanupJobPreviousScheduleError() {
|
||||
suite.taskMgr = &testingTask.Manager{}
|
||||
suite.execMgr = &testingTask.ExecutionManager{}
|
||||
suite.cleanupMgr = &systemartifact.Manager{}
|
||||
suite.sched = &scheduler.Scheduler{}
|
||||
|
||||
suite.ctl = &controller{
|
||||
execMgr: suite.execMgr,
|
||||
taskMgr: suite.taskMgr,
|
||||
systemArtifactMgr: suite.cleanupMgr,
|
||||
makeCtx: func() context.Context { return orm.NewContext(nil, &ormtesting.FakeOrmer{}) },
|
||||
}
|
||||
|
||||
suite.sched.On("Schedule", mock.Anything,
|
||||
VendorTypeSystemArtifactCleanup, int64(0), cronTypeDaily, cronSpec, SystemArtifactCleanupCallback, nil, mock.Anything).Return(int64(1), nil)
|
||||
|
||||
suite.sched.On("ListSchedules", mock.Anything, mock.Anything).Return(nil, errors.New("test error"))
|
||||
sched = suite.sched
|
||||
ctx := context.TODO()
|
||||
|
||||
ScheduleCleanupTask(ctx)
|
||||
|
||||
extraAttributesMatcher := testifymock.MatchedBy(func(attrs map[string]interface{}) bool {
|
||||
return len(attrs) == 0
|
||||
})
|
||||
suite.sched.AssertNotCalled(suite.T(), "Schedule", mock.Anything,
|
||||
VendorTypeSystemArtifactCleanup, int64(0), cronTypeDaily, cronSpec, SystemArtifactCleanupCallback, nil, extraAttributesMatcher)
|
||||
}
|
||||
|
||||
func (suite *SystemArtifactCleanupTestSuite) TearDownSuite() {
|
||||
suite.execMgr = nil
|
||||
suite.taskMgr = nil
|
||||
suite.cleanupMgr = nil
|
||||
suite.ctl = nil
|
||||
suite.sched = nil
|
||||
}
|
||||
|
||||
func TestScanDataExportExecutionTestSuite(t *testing.T) {
|
||||
suite.Run(t, &SystemArtifactCleanupTestSuite{})
|
||||
}
|
@ -25,6 +25,8 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/goharbor/harbor/src/controller/systemartifact"
|
||||
|
||||
"github.com/beego/beego"
|
||||
"github.com/goharbor/harbor/src/core/session"
|
||||
|
||||
@ -227,6 +229,7 @@ func main() {
|
||||
if err != nil {
|
||||
log.Warningf("oidc.FixEmptySubIss() errors out, error: %v", err)
|
||||
}
|
||||
systemartifact.ScheduleCleanupTask(ctx)
|
||||
beego.RunWithMiddleWares("", middlewares.MiddleWares()...)
|
||||
}
|
||||
|
||||
|
45
src/jobservice/job/impl/systemartifact/cleanup.go
Normal file
45
src/jobservice/job/impl/systemartifact/cleanup.go
Normal file
@ -0,0 +1,45 @@
|
||||
package systemartifact
|
||||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/jobservice/job"
|
||||
"github.com/goharbor/harbor/src/pkg/systemartifact"
|
||||
)
|
||||
|
||||
type Cleanup struct {
|
||||
sysArtifactManager systemartifact.Manager
|
||||
}
|
||||
|
||||
func (c *Cleanup) MaxFails() uint {
|
||||
return 1
|
||||
}
|
||||
|
||||
func (c *Cleanup) MaxCurrency() uint {
|
||||
return 1
|
||||
}
|
||||
|
||||
func (c *Cleanup) ShouldRetry() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *Cleanup) Validate(params job.Parameters) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Cleanup) Run(ctx job.Context, params job.Parameters) error {
|
||||
logger := ctx.GetLogger()
|
||||
logger.Infof("Running system data artifact cleanup job...")
|
||||
c.init()
|
||||
numRecordsDeleted, totalSizeReclaimed, err := c.sysArtifactManager.Cleanup(ctx.SystemContext())
|
||||
if err != nil {
|
||||
logger.Errorf("Error when executing system artifact cleanup job: %v", err)
|
||||
return err
|
||||
}
|
||||
logger.Infof("Num System artifacts cleaned up: %d, Total space reclaimed: %d.", numRecordsDeleted, totalSizeReclaimed)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Cleanup) init() {
|
||||
if c.sysArtifactManager == nil {
|
||||
c.sysArtifactManager = systemartifact.NewManager()
|
||||
}
|
||||
}
|
64
src/jobservice/job/impl/systemartifact/cleanup_test.go
Normal file
64
src/jobservice/job/impl/systemartifact/cleanup_test.go
Normal file
@ -0,0 +1,64 @@
|
||||
package systemartifact
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/goharbor/harbor/src/jobservice/job"
|
||||
mockjobservice "github.com/goharbor/harbor/src/testing/jobservice"
|
||||
"github.com/goharbor/harbor/src/testing/mock"
|
||||
"github.com/goharbor/harbor/src/testing/pkg/systemartifact"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type SystemArtifactCleanupSuite struct {
|
||||
suite.Suite
|
||||
sysArtifactMgr *systemartifact.Manager
|
||||
job *Cleanup
|
||||
}
|
||||
|
||||
func (suite *SystemArtifactCleanupSuite) SetupTest() {
|
||||
suite.sysArtifactMgr = &systemartifact.Manager{}
|
||||
suite.job = &Cleanup{sysArtifactManager: suite.sysArtifactMgr}
|
||||
}
|
||||
|
||||
func (suite *SystemArtifactCleanupSuite) TestRun() {
|
||||
mock.OnAnything(suite.sysArtifactMgr, "Cleanup").Return(int64(100), int64(100), nil)
|
||||
params := job.Parameters{}
|
||||
ctx := &mockjobservice.MockJobContext{}
|
||||
|
||||
err := suite.job.Run(ctx, params)
|
||||
suite.NoError(err)
|
||||
// assert that job manager is invoked in this mode
|
||||
suite.sysArtifactMgr.AssertCalled(suite.T(), "Cleanup", mock.Anything)
|
||||
}
|
||||
|
||||
func (suite *SystemArtifactCleanupSuite) TestRunFailure() {
|
||||
mock.OnAnything(suite.sysArtifactMgr, "Cleanup").Return(int64(0), int64(0), errors.New("test error"))
|
||||
params := job.Parameters{}
|
||||
ctx := &mockjobservice.MockJobContext{}
|
||||
|
||||
err := suite.job.Run(ctx, params)
|
||||
suite.Error(err)
|
||||
// assert that job manager is invoked in this mode
|
||||
suite.sysArtifactMgr.AssertCalled(suite.T(), "Cleanup", mock.Anything)
|
||||
}
|
||||
|
||||
func (suite *SystemArtifactCleanupSuite) TestMaxFails() {
|
||||
suite.Equal(uint(1), suite.job.MaxFails())
|
||||
}
|
||||
|
||||
func (suite *SystemArtifactCleanupSuite) TestMaxConcurrency() {
|
||||
suite.Equal(uint(1), suite.job.MaxCurrency())
|
||||
}
|
||||
|
||||
func (suite *SystemArtifactCleanupSuite) TestShouldRetry() {
|
||||
suite.Equal(true, suite.job.ShouldRetry())
|
||||
}
|
||||
|
||||
func (suite *SystemArtifactCleanupSuite) TestValidate() {
|
||||
suite.NoError(suite.job.Validate(job.Parameters{}))
|
||||
}
|
||||
|
||||
func TestSystemArtifactCleanupSuite(t *testing.T) {
|
||||
suite.Run(t, &SystemArtifactCleanupSuite{})
|
||||
}
|
@ -36,4 +36,6 @@ const (
|
||||
P2PPreheat = "P2P_PREHEAT"
|
||||
// PurgeAudit : the name of purge audit job
|
||||
PurgeAudit = "PURGE_AUDIT"
|
||||
// SystemArtifactCleanup : the name of the SystemArtifact cleanup job
|
||||
SystemArtifactCleanup = "SYSTEM_ARTIFACT_CLEANUP"
|
||||
)
|
||||
|
@ -24,6 +24,8 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/goharbor/harbor/src/jobservice/job/impl/systemartifact"
|
||||
|
||||
"github.com/goharbor/harbor/src/jobservice/api"
|
||||
"github.com/goharbor/harbor/src/jobservice/common/utils"
|
||||
"github.com/goharbor/harbor/src/jobservice/config"
|
||||
@ -319,9 +321,10 @@ func (bs *Bootstrap) loadAndRunRedisWorkerPool(
|
||||
// In v2.2 we migrate the scheduled replication, garbage collection and scan all to
|
||||
// the scheduler mechanism, the following three jobs are kept for the legacy jobs
|
||||
// and they can be removed after several releases
|
||||
"IMAGE_REPLICATE": (*legacy.ReplicationScheduler)(nil),
|
||||
"IMAGE_GC": (*legacy.GarbageCollectionScheduler)(nil),
|
||||
"IMAGE_SCAN_ALL": (*legacy.ScanAllScheduler)(nil),
|
||||
"IMAGE_REPLICATE": (*legacy.ReplicationScheduler)(nil),
|
||||
"IMAGE_GC": (*legacy.GarbageCollectionScheduler)(nil),
|
||||
"IMAGE_SCAN_ALL": (*legacy.ScanAllScheduler)(nil),
|
||||
job.SystemArtifactCleanup: (*systemartifact.Cleanup)(nil),
|
||||
}); err != nil {
|
||||
// exit
|
||||
return nil, err
|
||||
|
@ -30,3 +30,4 @@ package controller
|
||||
//go:generate mockery --case snake --dir ../../controller/repository --name Controller --output ./repository --outpkg repository
|
||||
//go:generate mockery --case snake --dir ../../controller/purge --name Controller --output ./purge --outpkg purge
|
||||
//go:generate mockery --case snake --dir ../../controller/jobservice --name SchedulerController --output ./jobservice --outpkg jobservice
|
||||
//go:generate mockery --case snake --dir ../../controller/systemartifact --name Controller --output ./systemartifact --outpkg systemartifact
|
||||
|
Loading…
Reference in New Issue
Block a user