Merge pull request #9393 from wy65701436/immutable-match

add immutable match
This commit is contained in:
Wenkai Yin(尹文开) 2019-10-15 18:51:43 +08:00 committed by GitHub
commit 372875ad64
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 267 additions and 1 deletions

View File

@ -46,7 +46,7 @@ func (itr *ImmutableTagRuleAPI) Prepare() {
itr.ID = ruleID
}
itr.ctr = immutabletag.NewAPIController(immutabletag.NewDefaultRuleManager())
itr.ctr = immutabletag.ImmuCtr
if strings.EqualFold(itr.Ctx.Request.Method, "get") {
if !itr.requireAccess(rbac.ActionList) {

View File

@ -4,6 +4,11 @@ import (
"github.com/goharbor/harbor/src/pkg/immutabletag/model"
)
var (
// ImmuCtr is a global variable for the default immutable controller implementation
ImmuCtr = NewAPIController(NewDefaultRuleManager())
)
// APIController to handle the requests related with immutabletag
type APIController interface {
// GetImmutableRule ...

View File

@ -0,0 +1,11 @@
package match
import (
"github.com/goharbor/harbor/src/pkg/art"
)
// ImmutableTagMatcher ...
type ImmutableTagMatcher interface {
// Match whether the candidate is in the immutable list
Match(c art.Candidate) (bool, error)
}

View File

@ -0,0 +1,88 @@
package rule
import (
"github.com/goharbor/harbor/src/pkg/art"
"github.com/goharbor/harbor/src/pkg/art/selectors/index"
"github.com/goharbor/harbor/src/pkg/immutabletag"
"github.com/goharbor/harbor/src/pkg/immutabletag/match"
"github.com/goharbor/harbor/src/pkg/immutabletag/model"
)
// Matcher ...
type Matcher struct {
pid int64
rules []model.Metadata
}
// Match ...
func (rm *Matcher) Match(c art.Candidate) (bool, error) {
if err := rm.getImmutableRules(); err != nil {
return false, err
}
cands := []*art.Candidate{&c}
for _, r := range rm.rules {
if r.Disabled {
continue
}
// match repositories according to the repository selectors
var repositoryCandidates []*art.Candidate
repositorySelectors := r.ScopeSelectors["repository"]
if len(repositorySelectors) < 1 {
continue
}
repositorySelector := repositorySelectors[0]
selector, err := index.Get(repositorySelector.Kind, repositorySelector.Decoration,
repositorySelector.Pattern)
if err != nil {
return false, err
}
repositoryCandidates, err = selector.Select(cands)
if err != nil {
return false, err
}
if len(repositoryCandidates) == 0 {
continue
}
// match tag according to the tag selectors
var tagCandidates []*art.Candidate
tagSelectors := r.TagSelectors
if len(tagSelectors) < 0 {
continue
}
tagSelector := r.TagSelectors[0]
selector, err = index.Get(tagSelector.Kind, tagSelector.Decoration,
tagSelector.Pattern)
if err != nil {
return false, err
}
tagCandidates, err = selector.Select(cands)
if err != nil {
return false, err
}
if len(tagCandidates) == 0 {
continue
}
return true, nil
}
return false, nil
}
func (rm *Matcher) getImmutableRules() error {
rules, err := immutabletag.ImmuCtr.ListImmutableRules(rm.pid)
if err != nil {
return err
}
rm.rules = rules
return nil
}
// NewRuleMatcher ...
func NewRuleMatcher(pid int64) match.ImmutableTagMatcher {
return &Matcher{
pid: pid,
}
}

View File

@ -0,0 +1,162 @@
package rule
import (
"github.com/goharbor/harbor/src/common/utils/test"
"github.com/goharbor/harbor/src/pkg/art"
"github.com/goharbor/harbor/src/pkg/immutabletag"
"github.com/goharbor/harbor/src/pkg/immutabletag/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"testing"
"time"
)
// MatchTestSuite ...
type MatchTestSuite struct {
suite.Suite
t *testing.T
assert *assert.Assertions
require *require.Assertions
ctr immutabletag.APIController
ruleID int64
ruleID2 int64
}
// SetupSuite ...
func (s *MatchTestSuite) SetupSuite() {
test.InitDatabaseFromEnv()
s.t = s.T()
s.assert = assert.New(s.t)
s.require = require.New(s.t)
s.ctr = immutabletag.ImmuCtr
}
func (s *MatchTestSuite) TestImmuMatch() {
rule := &model.Metadata{
ID: 1,
ProjectID: 2,
Priority: 1,
Template: "latestPushedK",
Action: "immuablity",
TagSelectors: []*model.Selector{
{
Kind: "doublestar",
Decoration: "matches",
Pattern: "release-[\\d\\.]+",
},
},
ScopeSelectors: map[string][]*model.Selector{
"repository": {
{
Kind: "doublestar",
Decoration: "matches",
Pattern: "redis",
},
},
},
}
rule2 := &model.Metadata{
ID: 1,
ProjectID: 2,
Priority: 1,
Template: "latestPushedK",
Action: "immuablity",
TagSelectors: []*model.Selector{
{
Kind: "doublestar",
Decoration: "matches",
Pattern: "**",
},
},
ScopeSelectors: map[string][]*model.Selector{
"repository": {
{
Kind: "doublestar",
Decoration: "matches",
Pattern: "mysql",
},
},
},
}
id, err := s.ctr.CreateImmutableRule(rule)
s.ruleID = id
s.require.NotNil(err)
id, err = s.ctr.CreateImmutableRule(rule2)
s.ruleID2 = id
s.require.NotNil(err)
match := NewRuleMatcher(2)
c1 := art.Candidate{
NamespaceID: 2,
Namespace: "immutable",
Repository: "redis",
Tag: "release-1.10",
Kind: art.Image,
PushedTime: time.Now().Unix() - 3600,
PulledTime: time.Now().Unix(),
CreationTime: time.Now().Unix() - 7200,
Labels: []string{"label1", "label4", "label5"},
}
isMatch, err := match.Match(c1)
s.require.Equal(isMatch, true)
s.require.Nil(err)
c2 := art.Candidate{
NamespaceID: 2,
Namespace: "immutable",
Repository: "redis",
Tag: "1.10",
Kind: art.Image,
PushedTime: time.Now().Unix() - 3600,
PulledTime: time.Now().Unix(),
CreationTime: time.Now().Unix() - 7200,
Labels: []string{"label1", "label4", "label5"},
}
isMatch, err = match.Match(c2)
s.require.Equal(isMatch, false)
s.require.Nil(err)
c3 := art.Candidate{
NamespaceID: 2,
Namespace: "immutable",
Repository: "mysql",
Tag: "9.4.8",
Kind: art.Image,
PushedTime: time.Now().Unix() - 3600,
PulledTime: time.Now().Unix(),
CreationTime: time.Now().Unix() - 7200,
Labels: []string{"label1"},
}
isMatch, err = match.Match(c3)
s.require.Equal(isMatch, true)
s.require.Nil(err)
c4 := art.Candidate{
NamespaceID: 2,
Namespace: "immutable",
Repository: "hello",
Tag: "world",
Kind: art.Image,
PushedTime: time.Now().Unix() - 3600,
PulledTime: time.Now().Unix(),
CreationTime: time.Now().Unix() - 7200,
Labels: []string{"label1"},
}
isMatch, err = match.Match(c4)
s.require.Equal(isMatch, false)
s.require.Nil(err)
}
// TearDownSuite clears env for test suite
func (s *MatchTestSuite) TearDownSuite() {
err := s.ctr.DeleteImmutableRule(s.ruleID)
require.NoError(s.T(), err, "delete immutable")
err = s.ctr.DeleteImmutableRule(s.ruleID2)
require.NoError(s.T(), err, "delete immutable")
}