mirror of
https://github.com/goharbor/harbor.git
synced 2025-01-09 17:37:44 +01:00
Merge pull request #9393 from wy65701436/immutable-match
add immutable match
This commit is contained in:
commit
372875ad64
@ -46,7 +46,7 @@ func (itr *ImmutableTagRuleAPI) Prepare() {
|
|||||||
itr.ID = ruleID
|
itr.ID = ruleID
|
||||||
}
|
}
|
||||||
|
|
||||||
itr.ctr = immutabletag.NewAPIController(immutabletag.NewDefaultRuleManager())
|
itr.ctr = immutabletag.ImmuCtr
|
||||||
|
|
||||||
if strings.EqualFold(itr.Ctx.Request.Method, "get") {
|
if strings.EqualFold(itr.Ctx.Request.Method, "get") {
|
||||||
if !itr.requireAccess(rbac.ActionList) {
|
if !itr.requireAccess(rbac.ActionList) {
|
||||||
|
@ -4,6 +4,11 @@ import (
|
|||||||
"github.com/goharbor/harbor/src/pkg/immutabletag/model"
|
"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
|
// APIController to handle the requests related with immutabletag
|
||||||
type APIController interface {
|
type APIController interface {
|
||||||
// GetImmutableRule ...
|
// GetImmutableRule ...
|
||||||
|
11
src/pkg/immutabletag/match/matcher.go
Normal file
11
src/pkg/immutabletag/match/matcher.go
Normal 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)
|
||||||
|
}
|
88
src/pkg/immutabletag/match/rule/match.go
Normal file
88
src/pkg/immutabletag/match/rule/match.go
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
162
src/pkg/immutabletag/match/rule/match_test.go
Normal file
162
src/pkg/immutabletag/match/rule/match_test.go
Normal 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")
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user