feat: add p2p preheat policy model

Signed-off-by: chlins <chlins.zhang@gmail.com>
This commit is contained in:
chlins 2020-06-27 16:29:48 +08:00
parent 309a9ff13c
commit dd9e97f755
2 changed files with 282 additions and 0 deletions

View 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")
}
}
}

View 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")
}