implement retain action performer

Signed-off-by: Steven Zou <szou@vmware.com>
This commit is contained in:
Steven Zou 2019-07-19 15:59:21 +08:00
parent 0994e5efc9
commit c2b5d95e02
5 changed files with 172 additions and 11 deletions

View File

@ -17,6 +17,7 @@ package main
import ( import (
"encoding/gob" "encoding/gob"
"fmt" "fmt"
"github.com/goharbor/harbor/src/pkg/retention"
"os" "os"
"os/signal" "os/signal"
"strconv" "strconv"
@ -157,6 +158,12 @@ func main() {
log.Infof("Because SYNC_REGISTRY set false , no need to sync registry \n") log.Infof("Because SYNC_REGISTRY set false , no need to sync registry \n")
} }
// Initialize retention
log.Info("Initialize retention")
if err := retention.Init(); err != nil {
log.Fatalf("Failed to initialize retention with error: %s", err)
}
log.Info("Init proxy") log.Info("Init proxy")
proxy.Init() proxy.Init()
// go proxy.StartProxy() // go proxy.StartProxy()

23
src/pkg/retention/boot.go Normal file
View File

@ -0,0 +1,23 @@
// 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 retention
// Init the retention components
func Init() error {
// New default retention client
DefaultClient = NewClient()
return nil
}

View File

@ -29,6 +29,9 @@ import (
"github.com/goharbor/harbor/src/pkg/retention/res" "github.com/goharbor/harbor/src/pkg/retention/res"
) )
// DefaultClient for the retention
var DefaultClient Client
// Client is designed to access core service to get required infos // Client is designed to access core service to get required infos
type Client interface { type Client interface {
// Get the tag candidates under the repository // Get the tag candidates under the repository
@ -63,8 +66,8 @@ type Client interface {
SubmitTask(taskID int64, repository *res.Repository, meta *policy.LiteMeta) (string, error) SubmitTask(taskID int64, repository *res.Repository, meta *policy.LiteMeta) (string, error)
} }
// New basic client // NewClient new a basic client
func New(client ...*http.Client) Client { func NewClient(client ...*http.Client) Client {
var c *http.Client var c *http.Client
if len(client) > 0 { if len(client) > 0 {
c = client[0] c = client[0]

View File

@ -14,7 +14,10 @@
package action package action
import "github.com/goharbor/harbor/src/pkg/retention/res" import (
"github.com/goharbor/harbor/src/pkg/retention"
"github.com/goharbor/harbor/src/pkg/retention/res"
)
const ( const (
// Retain artifacts // Retain artifacts
@ -43,17 +46,30 @@ type retainAction struct {
} }
// Perform the action // Perform the action
func (ra *retainAction) Perform(candidates []*res.Candidate) ([]*res.Result, error) { func (ra *retainAction) Perform(candidates []*res.Candidate) (results []*res.Result, err error) {
// TODO: REPLACE SAMPLE CODE WITH REAL IMPLEMENTATION retained := make(map[string]bool)
results := make([]*res.Result, 0)
for _, c := range candidates { for _, c := range candidates {
results = append(results, &res.Result{ retained[c.Hash()] = true
Target: c,
})
} }
return results, nil // start to delete
if len(ra.all) > 0 {
for _, art := range ra.all {
if _, ok := retained[art.Hash()]; !ok {
result := &res.Result{
Target: art,
}
if err := retention.DefaultClient.Delete(art); err != nil {
result.Error = err
}
results = append(results, result)
}
}
}
return
} }
// NewRetainAction is factory method for RetainAction // NewRetainAction is factory method for RetainAction

View File

@ -0,0 +1,112 @@
// 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 action
import (
"github.com/goharbor/harbor/src/pkg/retention"
"github.com/goharbor/harbor/src/pkg/retention/policy"
"github.com/goharbor/harbor/src/pkg/retention/res"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"testing"
"time"
)
// TestPerformerSuite tests the performer related function
type TestPerformerSuite struct {
suite.Suite
oldClient retention.Client
all []*res.Candidate
}
// TestPerformer is the entry of the TestPerformerSuite
func TestPerformer(t *testing.T) {
suite.Run(t, new(TestPerformerSuite))
}
// SetupSuite ...
func (suite *TestPerformerSuite) SetupSuite() {
suite.all = []*res.Candidate{
{
Namespace: "library",
Repository: "harbor",
Kind: "image",
Tag: "latest",
PushedTime: time.Now().Unix(),
Labels: []string{"L1", "L2"},
},
{
Namespace: "library",
Repository: "harbor",
Kind: "image",
Tag: "dev",
PushedTime: time.Now().Unix(),
Labels: []string{"L3"},
},
}
suite.oldClient = retention.DefaultClient
retention.DefaultClient = &fakeRetentionClient{}
}
// TearDownSuite ...
func (suite *TestPerformerSuite) TearDownSuite() {
retention.DefaultClient = suite.oldClient
}
// TestPerform tests Perform action
func (suite *TestPerformerSuite) TestPerform() {
p := &retainAction{
all: suite.all,
}
candidates := []*res.Candidate{
{
Namespace: "library",
Repository: "harbor",
Kind: "image",
Tag: "latest",
PushedTime: time.Now().Unix(),
Labels: []string{"L1", "L2"},
},
}
results, err := p.Perform(candidates)
require.NoError(suite.T(), err)
require.Equal(suite.T(), 1, len(results))
require.NotNil(suite.T(), results[0].Target)
assert.NoError(suite.T(), results[0].Error)
assert.Equal(suite.T(), "latest", results[0].Target.Tag)
}
type fakeRetentionClient struct{}
// GetCandidates ...
func (frc *fakeRetentionClient) GetCandidates(repo *res.Repository) ([]*res.Candidate, error) {
return nil, errors.New("not implemented")
}
// Delete ...
func (frc *fakeRetentionClient) Delete(candidate *res.Candidate) error {
return nil
}
// SubmitTask ...
func (frc *fakeRetentionClient) SubmitTask(taskID int64, repository *res.Repository, meta *policy.LiteMeta) (string, error) {
return "", errors.New("not implemented")
}