add more details in gc history (#18779)

Show more infors in the gc history, like the sweep size and how many blobs and manifests were removed by GC.

Signed-off-by: Wang Yan <wangyan@vmware.com>
This commit is contained in:
Wang Yan 2023-06-02 17:33:09 +08:00 committed by GitHub
parent 97c1fdcd8e
commit 680c78d368
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 124 additions and 3 deletions

View File

@ -35,7 +35,11 @@ func init() {
}
if err := task.RegisterTaskStatusChangePostFunc(job.GarbageCollectionVendorType, gcTaskStatusChange); err != nil {
log.Fatalf("failed to register the task status change post for the gc job, error %v", err)
log.Fatalf("failed to register the task status change post for the garbage collection job, error %v", err)
}
if err := task.RegisterCheckInProcessor(job.GarbageCollectionVendorType, gcCheckIn); err != nil {
log.Fatalf("failed to register the checkin processor for the garbage collection job, error %v", err)
}
}
@ -60,3 +64,42 @@ func gcTaskStatusChange(ctx context.Context, taskID int64, status string) error
return nil
}
func gcCheckIn(ctx context.Context, t *task.Task, sc *job.StatusChange) error {
taskID := t.ID
status := t.Status
log.Infof("received garbage collection task status update event: task-%d, status-%s", taskID, status)
if sc.CheckIn != "" {
var gcObj struct {
SweepSize int64 `json:"freed_space"`
Blobs int64 `json:"purged_blobs"`
Manifests int64 `json:"purged_manifests"`
}
if err := json.Unmarshal([]byte(sc.CheckIn), &gcObj); err != nil {
log.Errorf("failed to resolve checkin of garbage collection task %d: %v", taskID, err)
return err
}
t, err := task.Mgr.Get(ctx, taskID)
if err != nil {
return err
}
e, err := task.ExecMgr.Get(ctx, t.ExecutionID)
if err != nil {
return err
}
e.ExtraAttrs["freed_space"] = gcObj.SweepSize
e.ExtraAttrs["purged_blobs"] = gcObj.Blobs
e.ExtraAttrs["purged_manifests"] = gcObj.Manifests
err = task.ExecMgr.UpdateExtraAttrs(ctx, e.ID, e.ExtraAttrs)
if err != nil {
log.G(ctx).WithField("error", err).Errorf("failed to update of garbage collection task %d", taskID)
return err
}
}
return nil
}

View File

@ -0,0 +1,44 @@
package gc
import (
"context"
"testing"
"github.com/goharbor/harbor/src/jobservice/job"
"github.com/goharbor/harbor/src/pkg/task"
"github.com/goharbor/harbor/src/testing/mock"
tasktesting "github.com/goharbor/harbor/src/testing/pkg/task"
"github.com/stretchr/testify/suite"
)
type callbackTestSuite struct {
suite.Suite
execMgr *tasktesting.ExecutionManager
taskMgr *tasktesting.Manager
}
func (c *callbackTestSuite) SetupTest() {
c.execMgr = &tasktesting.ExecutionManager{}
c.taskMgr = &tasktesting.Manager{}
}
func (c *callbackTestSuite) TestCheckIn() {
t := &task.Task{
ID: 1,
Status: "Success",
}
sc := &job.StatusChange{
CheckIn: "",
}
c.taskMgr.On("Get", mock.Anything, int64(1)).Return(&task.Task{ID: 1, ExecutionID: 1}, nil)
c.execMgr.On("Get", mock.Anything, mock.Anything).Return(&task.Execution{ID: 1}, nil)
c.execMgr.On("UpdateExtraAttrs", mock.Anything, mock.Anything, mock.Anything).Return(nil)
gcCheckIn(context.Background(), t, sc)
}
func TestCallBackTestSuite(t *testing.T) {
suite.Run(t, &callbackTestSuite{})
}

View File

@ -15,6 +15,7 @@
package gc
import (
"encoding/json"
"os"
"time"
@ -255,8 +256,8 @@ func (gc *GarbageCollector) mark(ctx job.Context) error {
func (gc *GarbageCollector) sweep(ctx job.Context) error {
gc.logger = ctx.GetLogger()
sweepSize := int64(0)
blobCnt := 0
mfCnt := 0
blobCnt := int64(0)
mfCnt := int64(0)
total := len(gc.deleteSet)
for i, blob := range gc.deleteSet {
if gc.shouldStop(ctx) {
@ -413,6 +414,11 @@ func (gc *GarbageCollector) sweep(ctx job.Context) error {
}
gc.logger.Infof("%d blobs and %d manifests are actually deleted", blobCnt, mfCnt)
gc.logger.Infof("The GC job actual frees up %d MB space.", sweepSize/1024/1024)
if err := saveGCRes(ctx, sweepSize, blobCnt, mfCnt); err != nil {
gc.logger.Errorf("failed to save the garbage collection results, errMsg=%v", err)
}
return nil
}
@ -647,3 +653,21 @@ func (gc *GarbageCollector) shouldStop(ctx job.Context) bool {
}
return false
}
func saveGCRes(ctx job.Context, sweepSize, blobs, manifests int64) error {
gcObj := struct {
SweepSize int64 `json:"freed_space"`
Blobs int64 `json:"purged_blobs"`
Manifests int64 `json:"purged_manifests"`
}{
SweepSize: sweepSize,
Blobs: blobs,
Manifests: manifests,
}
c, err := json.Marshal(gcObj)
if err != nil {
return err
}
_ = ctx.Checkin(string(c))
return nil
}

View File

@ -217,6 +217,7 @@ func (suite *gcTestSuite) TestRun() {
ctx.On("GetLogger").Return(logger)
ctx.On("OPCommand").Return(job.NilCommand, true)
mock.OnAnything(ctx, "Get").Return("core url", true)
mock.OnAnything(ctx, "Checkin").Return(nil)
suite.artifactCtl.On("List").Return([]*artifact.Artifact{
{
@ -357,6 +358,7 @@ func (suite *gcTestSuite) TestSweep() {
logger := &mockjobservice.MockJobLogger{}
ctx.On("GetLogger").Return(logger)
ctx.On("OPCommand").Return(job.NilCommand, false)
mock.OnAnything(ctx, "Checkin").Return(nil)
mock.OnAnything(suite.blobMgr, "UpdateBlobStatus").Return(int64(1), nil)
mock.OnAnything(suite.blobMgr, "Delete").Return(nil)
@ -378,6 +380,14 @@ func (suite *gcTestSuite) TestSweep() {
suite.Nil(gc.sweep(ctx))
}
func (suite *gcTestSuite) TestSaveRes() {
ctx := &mockjobservice.MockJobContext{}
logger := &mockjobservice.MockJobLogger{}
ctx.On("GetLogger").Return(logger)
mock.OnAnything(ctx, "Checkin").Return(nil)
suite.Nil(saveGCRes(ctx, 123456, 100, 100))
}
func TestGCTestSuite(t *testing.T) {
t.Setenv("UTTEST", "true")
suite.Run(t, &gcTestSuite{})