mirror of
https://github.com/goharbor/harbor.git
synced 2025-03-11 06:04:11 +01:00
Merge pull request #8592 from bitsf/tag_retention_conflict_rule
check rule conflict
This commit is contained in:
commit
d2fbb98a8d
@ -1,6 +1,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
@ -41,30 +42,6 @@ func (r *RetentionAPI) GetMetadatas() {
|
||||
data := `
|
||||
{
|
||||
"templates": [
|
||||
{
|
||||
"rule_template": "lastXDays",
|
||||
"display_text": "the images from the last # days",
|
||||
"action": "retain",
|
||||
"params": [
|
||||
{
|
||||
"type": "int",
|
||||
"unit": "DAYS",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"rule_template": "latestActiveK",
|
||||
"display_text": "the most recent active # images",
|
||||
"action": "retain",
|
||||
"params": [
|
||||
{
|
||||
"type": "int",
|
||||
"unit": "COUNT",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"rule_template": "latestPushedK",
|
||||
"display_text": "the most recently pushed # images",
|
||||
@ -194,6 +171,10 @@ func (r *RetentionAPI) CreateRetention() {
|
||||
r.SendBadRequestError(err)
|
||||
return
|
||||
}
|
||||
if err = r.checkRuleConflict(p); err != nil {
|
||||
r.SendConflictError(err)
|
||||
return
|
||||
}
|
||||
if !r.requireAccess(p, rbac.ActionCreate) {
|
||||
return
|
||||
}
|
||||
@ -241,6 +222,10 @@ func (r *RetentionAPI) UpdateRetention() {
|
||||
return
|
||||
}
|
||||
p.ID = id
|
||||
if err = r.checkRuleConflict(p); err != nil {
|
||||
r.SendConflictError(err)
|
||||
return
|
||||
}
|
||||
if !r.requireAccess(p, rbac.ActionUpdate) {
|
||||
return
|
||||
}
|
||||
@ -250,6 +235,21 @@ func (r *RetentionAPI) UpdateRetention() {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RetentionAPI) checkRuleConflict(p *policy.Metadata) error {
|
||||
temp := make(map[string]int)
|
||||
for n, rule := range p.Rules {
|
||||
tid := rule.ID
|
||||
rule.ID = 0
|
||||
bs, _ := json.Marshal(rule)
|
||||
if old, exists := temp[string(bs)]; exists {
|
||||
return fmt.Errorf("rule %d is conflict with rule %d", n, old)
|
||||
}
|
||||
temp[string(bs)] = tid
|
||||
rule.ID = tid
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TriggerRetentionExec Trigger Retention Execution
|
||||
func (r *RetentionAPI) TriggerRetentionExec() {
|
||||
id, err := r.GetIDFromURL()
|
||||
|
@ -143,6 +143,87 @@ func TestCreatePolicy(t *testing.T) {
|
||||
},
|
||||
code: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPost,
|
||||
url: "/api/retentions",
|
||||
bodyJSON: &policy.Metadata{
|
||||
Algorithm: "or",
|
||||
Rules: []rule.Metadata{
|
||||
{
|
||||
ID: 1,
|
||||
Priority: 1,
|
||||
Template: "recentXdays",
|
||||
Parameters: rule.Parameters{
|
||||
"num": 10,
|
||||
},
|
||||
TagSelectors: []*rule.Selector{
|
||||
{
|
||||
Kind: "label",
|
||||
Decoration: "with",
|
||||
Pattern: "latest",
|
||||
},
|
||||
{
|
||||
Kind: "regularExpression",
|
||||
Decoration: "matches",
|
||||
Pattern: "release-[\\d\\.]+",
|
||||
},
|
||||
},
|
||||
ScopeSelectors: map[string][]*rule.Selector{
|
||||
"repository": {
|
||||
{
|
||||
Kind: "regularExpression",
|
||||
Decoration: "matches",
|
||||
Pattern: ".+",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 2,
|
||||
Priority: 1,
|
||||
Template: "recentXdays",
|
||||
Parameters: rule.Parameters{
|
||||
"num": 10,
|
||||
},
|
||||
TagSelectors: []*rule.Selector{
|
||||
{
|
||||
Kind: "label",
|
||||
Decoration: "with",
|
||||
Pattern: "latest",
|
||||
},
|
||||
{
|
||||
Kind: "regularExpression",
|
||||
Decoration: "matches",
|
||||
Pattern: "release-[\\d\\.]+",
|
||||
},
|
||||
},
|
||||
ScopeSelectors: map[string][]*rule.Selector{
|
||||
"repository": {
|
||||
{
|
||||
Kind: "regularExpression",
|
||||
Decoration: "matches",
|
||||
Pattern: ".+",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Trigger: &policy.Trigger{
|
||||
Kind: "Schedule",
|
||||
Settings: map[string]interface{}{
|
||||
"cron": "* 22 11 * * *",
|
||||
},
|
||||
},
|
||||
Scope: &policy.Scope{
|
||||
Level: "project",
|
||||
Reference: 1,
|
||||
},
|
||||
},
|
||||
credential: sysAdmin,
|
||||
},
|
||||
code: http.StatusConflict,
|
||||
},
|
||||
}
|
||||
|
||||
runCodeCheckingCases(t, cases...)
|
||||
@ -267,6 +348,87 @@ func TestPolicy(t *testing.T) {
|
||||
},
|
||||
code: http.StatusOK,
|
||||
},
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPut,
|
||||
url: fmt.Sprintf("/api/retentions/%d", id),
|
||||
bodyJSON: &policy.Metadata{
|
||||
Algorithm: "or",
|
||||
Rules: []rule.Metadata{
|
||||
{
|
||||
ID: 1,
|
||||
Priority: 1,
|
||||
Template: "recentXdays",
|
||||
Parameters: rule.Parameters{
|
||||
"num": 10,
|
||||
},
|
||||
TagSelectors: []*rule.Selector{
|
||||
{
|
||||
Kind: "label",
|
||||
Decoration: "with",
|
||||
Pattern: "latest",
|
||||
},
|
||||
{
|
||||
Kind: "regularExpression",
|
||||
Decoration: "matches",
|
||||
Pattern: "release-[\\d\\.]+",
|
||||
},
|
||||
},
|
||||
ScopeSelectors: map[string][]*rule.Selector{
|
||||
"repository": {
|
||||
{
|
||||
Kind: "regularExpression",
|
||||
Decoration: "matches",
|
||||
Pattern: "b.+",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 2,
|
||||
Priority: 1,
|
||||
Template: "recentXdays",
|
||||
Parameters: rule.Parameters{
|
||||
"num": 10,
|
||||
},
|
||||
TagSelectors: []*rule.Selector{
|
||||
{
|
||||
Kind: "label",
|
||||
Decoration: "with",
|
||||
Pattern: "latest",
|
||||
},
|
||||
{
|
||||
Kind: "regularExpression",
|
||||
Decoration: "matches",
|
||||
Pattern: "release-[\\d\\.]+",
|
||||
},
|
||||
},
|
||||
ScopeSelectors: map[string][]*rule.Selector{
|
||||
"repository": {
|
||||
{
|
||||
Kind: "regularExpression",
|
||||
Decoration: "matches",
|
||||
Pattern: "b.+",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Trigger: &policy.Trigger{
|
||||
Kind: "Schedule",
|
||||
Settings: map[string]interface{}{
|
||||
"cron": "* 22 11 * * *",
|
||||
},
|
||||
},
|
||||
Scope: &policy.Scope{
|
||||
Level: "project",
|
||||
Reference: 1,
|
||||
},
|
||||
},
|
||||
credential: sysAdmin,
|
||||
},
|
||||
code: http.StatusConflict,
|
||||
},
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPost,
|
||||
|
Loading…
Reference in New Issue
Block a user