mirror of
https://github.com/goharbor/harbor.git
synced 2024-12-20 07:37:38 +01:00
feat: add p2p preheat policy model
Signed-off-by: chlins <chlins.zhang@gmail.com>
This commit is contained in:
parent
309a9ff13c
commit
dd9e97f755
150
src/pkg/p2p/preheat/models/policy/policy.go
Normal file
150
src/pkg/p2p/preheat/models/policy/policy.go
Normal file
@ -0,0 +1,150 @@
|
||||
// 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 policy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/astaxie/beego/validation"
|
||||
"github.com/robfig/cron"
|
||||
)
|
||||
|
||||
const (
|
||||
// Filters:
|
||||
// Repository : type=Repository value=name text (double star pattern used)
|
||||
// Tag: type=Tag value=tag text (double star pattern used)
|
||||
// Signature: type=Signature value=bool (True/False)
|
||||
// Vulnerability: type=Vulnerability value=Severity (expected bar)
|
||||
// Label: type=Label value=label array
|
||||
|
||||
// FilterTypeRepository represents the repository filter type
|
||||
FilterTypeRepository FilterType = "repository"
|
||||
// FilterTypeTag represents the tag filter type
|
||||
FilterTypeTag FilterType = "tag"
|
||||
// FilterTypeSignature represents the signature filter type
|
||||
FilterTypeSignature FilterType = "signature"
|
||||
// FilterTypeVulnerability represents the vulnerability filter type
|
||||
FilterTypeVulnerability FilterType = "vulnerability"
|
||||
// FilterTypeLabel represents the label filter type
|
||||
FilterTypeLabel FilterType = "label"
|
||||
|
||||
// TriggerTypeManual represents the manual trigger type
|
||||
TriggerTypeManual TriggerType = "manual"
|
||||
// TriggerTypeScheduled represents the scheduled trigger type
|
||||
TriggerTypeScheduled TriggerType = "scheduled"
|
||||
// TriggerTypeEventBased represents the event_based trigger type
|
||||
TriggerTypeEventBased TriggerType = "event_based"
|
||||
)
|
||||
|
||||
// Schema defines p2p preheat policy schema
|
||||
type Schema struct {
|
||||
ID int64 `orm:"column(id)" json:"id"`
|
||||
Name string `orm:"column(name)" json:"name"`
|
||||
Description string `orm:"column(description)" json:"description"`
|
||||
// use project name
|
||||
Project string `orm:"column(project)" json:"project"`
|
||||
ProviderID int64 `orm:"column(provider_id)" json:"provider_id"`
|
||||
Filters []*Filter `orm:"column(-)" json:"filters"`
|
||||
// Use JSON data format (query by filter type should be supported)
|
||||
FiltersStr string `orm:"column(filters)" json:"-"`
|
||||
Trigger *Trigger `orm:"column(-)" json:"trigger"`
|
||||
// Use JSON data format (query by trigger type should be supported)
|
||||
TriggerStr string `orm:"column(trigger)" json:"-"`
|
||||
Enabled bool `orm:"column(enabled)" json:"enabled"`
|
||||
CreatedAt time.Time `orm:"column(creation_time)" json:"creation_time"`
|
||||
UpdatedTime time.Time `orm:"column(update_time)" json:"update_time"`
|
||||
}
|
||||
|
||||
// FilterType represents the type info of the filter.
|
||||
type FilterType = string
|
||||
|
||||
// Filter holds the info of the filter
|
||||
type Filter struct {
|
||||
Type FilterType `json:"type"`
|
||||
Value interface{} `json:"value"`
|
||||
}
|
||||
|
||||
// TriggerType represents the type of trigger.
|
||||
type TriggerType = string
|
||||
|
||||
// Trigger holds the trigger info.
|
||||
type Trigger struct {
|
||||
// The preheat policy trigger type. The valid values ar manual, scheduled.
|
||||
Type TriggerType `json:"type"`
|
||||
Settings struct {
|
||||
// The cron string for scheduled trigger.
|
||||
Cron string `json:"cron,omitempty"`
|
||||
} `json:"trigger_setting,omitempty"`
|
||||
}
|
||||
|
||||
// Valid the policy
|
||||
func (s *Schema) Valid(v *validation.Validation) {
|
||||
if len(s.Name) == 0 {
|
||||
v.SetError("name", "cannot be empty")
|
||||
}
|
||||
|
||||
// valid the filters
|
||||
for _, filter := range s.Filters {
|
||||
switch filter.Type {
|
||||
case FilterTypeRepository, FilterTypeTag, FilterTypeVulnerability:
|
||||
_, ok := filter.Value.(string)
|
||||
if !ok {
|
||||
v.SetError("filters", "the type of filter value isn't string")
|
||||
break
|
||||
}
|
||||
case FilterTypeSignature:
|
||||
_, ok := filter.Value.(bool)
|
||||
if !ok {
|
||||
v.SetError("filers", "the type of signature filter value isn't bool")
|
||||
break
|
||||
}
|
||||
case FilterTypeLabel:
|
||||
labels, ok := filter.Value.([]interface{})
|
||||
if !ok {
|
||||
v.SetError("filters", "the type of label filter value isn't string slice")
|
||||
break
|
||||
}
|
||||
for _, label := range labels {
|
||||
_, ok := label.(string)
|
||||
if !ok {
|
||||
v.SetError("filters", "the type of label filter value isn't string slice")
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
v.SetError("filters", "invalid filter type")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// valid trigger
|
||||
if s.Trigger != nil {
|
||||
switch s.Trigger.Type {
|
||||
case TriggerTypeManual, TriggerTypeEventBased:
|
||||
case TriggerTypeScheduled:
|
||||
if len(s.Trigger.Settings.Cron) == 0 {
|
||||
v.SetError("trigger", fmt.Sprintf("the cron string cannot be empty when the trigger type is %s", TriggerTypeScheduled))
|
||||
} else {
|
||||
_, err := cron.Parse(s.Trigger.Settings.Cron)
|
||||
if err != nil {
|
||||
v.SetError("trigger", fmt.Sprintf("invalid cron string for scheduled trigger: %s", s.Trigger.Settings.Cron))
|
||||
}
|
||||
}
|
||||
default:
|
||||
v.SetError("trigger", "invalid trigger type")
|
||||
}
|
||||
}
|
||||
}
|
132
src/pkg/p2p/preheat/models/policy/policy_test.go
Normal file
132
src/pkg/p2p/preheat/models/policy/policy_test.go
Normal file
@ -0,0 +1,132 @@
|
||||
// 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 policy
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/astaxie/beego/validation"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
// PolicyTestSuite is a test suite for policy schema.
|
||||
type PolicyTestSuite struct {
|
||||
suite.Suite
|
||||
|
||||
schema *Schema
|
||||
}
|
||||
|
||||
// TestPolicy is the entry method of running PolicyTestSuite.
|
||||
func TestPolicy(t *testing.T) {
|
||||
suite.Run(t, &PolicyTestSuite{})
|
||||
}
|
||||
|
||||
// SetupSuite prepares the env for PolicyTestSuite.
|
||||
func (p *PolicyTestSuite) SetupSuite() {
|
||||
p.schema = &Schema{}
|
||||
}
|
||||
|
||||
// TearDownSuite clears the env for PolicyTestSuite.
|
||||
func (p *PolicyTestSuite) TearDownSuite() {
|
||||
p.schema = nil
|
||||
}
|
||||
|
||||
// TestValid tests Valid method.
|
||||
func (p *PolicyTestSuite) TestValid() {
|
||||
// policy name is empty, should return error
|
||||
v := &validation.Validation{}
|
||||
p.schema.Valid(v)
|
||||
require.True(p.T(), v.HasErrors(), "no policy name should return one error")
|
||||
require.Contains(p.T(), v.Errors[0].Error(), "cannot be empty")
|
||||
|
||||
// policy with name but with error filter type
|
||||
p.schema.Name = "policy-test"
|
||||
p.schema.Filters = []*Filter{
|
||||
{
|
||||
Type: "invalid-type",
|
||||
},
|
||||
}
|
||||
v = &validation.Validation{}
|
||||
p.schema.Valid(v)
|
||||
require.True(p.T(), v.HasErrors(), "invalid filter type should return one error")
|
||||
require.Contains(p.T(), v.Errors[0].Error(), "invalid filter type")
|
||||
|
||||
filterCases := [][]*Filter{
|
||||
{
|
||||
{
|
||||
Type: FilterTypeSignature,
|
||||
Value: "invalid-value",
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
{
|
||||
Type: FilterTypeTag,
|
||||
Value: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
Type: FilterTypeLabel,
|
||||
Value: "invalid-value",
|
||||
},
|
||||
},
|
||||
}
|
||||
// with valid filter type but with error value type
|
||||
for _, filters := range filterCases {
|
||||
p.schema.Filters = filters
|
||||
v = &validation.Validation{}
|
||||
p.schema.Valid(v)
|
||||
require.True(p.T(), v.HasErrors(), "invalid filter value type should return one error")
|
||||
}
|
||||
|
||||
// with valid filter but error trigger type
|
||||
p.schema.Filters = []*Filter{
|
||||
{
|
||||
Type: FilterTypeSignature,
|
||||
Value: true,
|
||||
},
|
||||
}
|
||||
p.schema.Trigger = &Trigger{
|
||||
Type: "invalid-type",
|
||||
}
|
||||
v = &validation.Validation{}
|
||||
p.schema.Valid(v)
|
||||
require.True(p.T(), v.HasErrors(), "invalid trigger type should return one error")
|
||||
require.Contains(p.T(), v.Errors[0].Error(), "invalid trigger type")
|
||||
|
||||
// with valid filter but error trigger value
|
||||
p.schema.Trigger = &Trigger{
|
||||
Type: TriggerTypeScheduled,
|
||||
}
|
||||
v = &validation.Validation{}
|
||||
p.schema.Valid(v)
|
||||
require.True(p.T(), v.HasErrors(), "invalid trigger value should return one error")
|
||||
require.Contains(p.T(), v.Errors[0].Error(), "the cron string cannot be empty")
|
||||
// with invalid cron
|
||||
p.schema.Trigger.Settings.Cron = "1111111111111"
|
||||
v = &validation.Validation{}
|
||||
p.schema.Valid(v)
|
||||
require.True(p.T(), v.HasErrors(), "invalid trigger value should return one error")
|
||||
require.Contains(p.T(), v.Errors[0].Error(), "invalid cron string for scheduled trigger")
|
||||
|
||||
// all is well
|
||||
p.schema.Trigger.Settings.Cron = "0/12 * * * *"
|
||||
v = &validation.Validation{}
|
||||
p.schema.Valid(v)
|
||||
require.False(p.T(), v.HasErrors(), "should return nil error")
|
||||
}
|
Loading…
Reference in New Issue
Block a user