Merge pull request #8592 from bitsf/tag_retention_conflict_rule

check rule conflict
This commit is contained in:
Steven Zou 2019-08-09 13:59:46 +08:00 committed by GitHub
commit d2fbb98a8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 186 additions and 24 deletions

View File

@ -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()

View File

@ -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,