implement policy builder

Signed-off-by: Steven Zou <szou@vmware.com>
This commit is contained in:
Steven Zou 2019-07-09 17:43:19 +08:00
parent c36afcd07d
commit 3409065438
6 changed files with 112 additions and 16 deletions

View File

@ -26,15 +26,19 @@ import (
// processor to handle the rules with OR mapping ways
type processor struct {
performer action.Performer
// keep evaluator and its related selector if existing
// attentions here, the selectors can be empty/nil, that means match all "**"
evaluators map[*rule.Evaluator][]res.Selector
// action performer
performers map[string]action.Performer
}
// New processor
func New() alg.Processor {
return &processor{}
return &processor{
evaluators: make(map[*rule.Evaluator][]res.Selector),
performers: make(map[string]action.Performer),
}
}
// Process the candidates with the rules
@ -47,12 +51,17 @@ func (p *processor) Process(artifacts []*res.Candidate) ([]*res.Result, error) {
var (
// collect errors by wrapping
err error
// collect results
retained = make([]*res.Candidate, 0)
// collect processed candidates
processedCandidates = make(map[string][]*res.Candidate)
)
// for sync
resChan := make(chan []*res.Candidate, 1)
type chanItem struct {
action string
processed []*res.Candidate
}
resChan := make(chan *chanItem, 1)
// handle error
errChan := make(chan error, 1)
// control chan
@ -67,8 +76,12 @@ func (p *processor) Process(artifacts []*res.Candidate) ([]*res.Result, error) {
go func() {
for {
select {
case retainedOnes := <-resChan:
retained = append(retained, retainedOnes...)
case result := <-resChan:
if _, ok := processedCandidates[result.action]; !ok {
processedCandidates[result.action] = make([]*res.Candidate, 0)
}
processedCandidates[result.action] = append(processedCandidates[result.action], result.processed...)
case e := <-errChan:
if err == nil {
err = errors.Wrap(e, "artifact processing error")
@ -120,7 +133,10 @@ func (p *processor) Process(artifacts []*res.Candidate) ([]*res.Result, error) {
if len(processed) > 0 {
// Pass to the outside
resChan <- processed
resChan <- &chanItem{
action: evaluator.Action(),
processed: processed,
}
}
}(evaluator, selectors)
}
@ -132,7 +148,32 @@ func (p *processor) Process(artifacts []*res.Candidate) ([]*res.Result, error) {
return nil, err
}
return p.performer.Perform(retained)
results := make([]*res.Result, 0)
// Perform actions
for act, candidates := range processedCandidates {
var attachedErr error
if pf, ok := p.performers[act]; ok {
if theRes, err := pf.Perform(candidates); err != nil {
attachedErr = err
} else {
results = append(results, theRes...)
}
} else {
attachedErr = errors.Errorf("no performer added for action %s in OR processor", act)
}
if attachedErr != nil {
for _, c := range candidates {
results = append(results, &res.Result{
Target: c,
Error: attachedErr,
})
}
}
}
return results, nil
}
// AddEvaluator appends a rule evaluator for processing
@ -143,6 +184,6 @@ func (p *processor) AddEvaluator(evaluator rule.Evaluator, selectors []res.Selec
}
// SetPerformer sets a action performer to the processor
func (p *processor) SetPerformer(performer action.Performer) {
p.performer = performer
func (p *processor) AddActionPerformer(action string, performer action.Performer) {
p.performers[action] = performer
}

View File

@ -41,9 +41,10 @@ type Processor interface {
// selectors []res.Selector : selectors to narrow down the scope (&& adopted), optional
AddEvaluator(evaluator rule.Evaluator, selectors []res.Selector)
// Set performer for the processor
// Add performer for the related action to the processor
//
// Arguments:
// action string : action name
// performer action.Performer : a performer implementation
SetPerformer(performer action.Performer)
AddActionPerformer(action string, performer action.Performer)
}

View File

@ -15,7 +15,12 @@
package policy
import (
"github.com/goharbor/harbor/src/pkg/retention/policy/action"
"github.com/goharbor/harbor/src/pkg/retention/policy/alg"
"github.com/goharbor/harbor/src/pkg/retention/policy/alg/or"
"github.com/goharbor/harbor/src/pkg/retention/policy/rule"
"github.com/goharbor/harbor/src/pkg/retention/res"
"github.com/goharbor/harbor/src/pkg/retention/res/selectors"
"github.com/pkg/errors"
)
@ -32,8 +37,17 @@ type Builder interface {
Build(rawPolicy string) (alg.Processor, error)
}
// NewBuilder news a basic builder
func NewBuilder(all []*res.Candidate) Builder {
return &basicBuilder{
allCandidates: all,
}
}
// basicBuilder is default implementation of Builder interface
type basicBuilder struct{}
type basicBuilder struct {
allCandidates []*res.Candidate
}
// Build policy processor from the raw policy
func (bb *basicBuilder) Build(rawPolicy string) (alg.Processor, error) {
@ -49,9 +63,36 @@ func (bb *basicBuilder) Build(rawPolicy string) (alg.Processor, error) {
switch liteMeta.Algorithm {
case AlgorithmOR:
// New OR processor
p := or.New()
for _, r := range liteMeta.Rules {
evaluator, err := rule.Get(r.Template, r.Parameters)
if err != nil {
return nil, err
}
perf, err := action.Get(r.Action, bb.allCandidates)
if err != nil {
return nil, errors.Wrap(err, "get action performer by metadata")
}
sl := make([]res.Selector, 0)
for _, s := range r.TagSelectors {
sel, err := selectors.Get(s.Kind, s.Decoration, s.Pattern)
if err != nil {
return nil, errors.Wrap(err, "get selector by metadata")
}
sl = append(sl, sel)
}
p.AddEvaluator(evaluator, sl)
p.AddActionPerformer(r.Action, perf)
return p, nil
}
default:
return nil, errors.Errorf("algorithm %s is not supported", liteMeta.Algorithm)
}
return nil, errors.New("not implemented")
return nil, errors.Errorf("algorithm %s is not supported", liteMeta.Algorithm)
}

View File

@ -27,6 +27,9 @@ type Evaluator interface {
// []*res.Candidate : matched candidates for next stage
// error : common error object if any errors occurred
Process(artifacts []*res.Candidate) ([]*res.Candidate, error)
// Specify what action is performed to the candidates processed by this evaluator
Action() string
}
// RuleFactory defines a factory method for creating rule evaluator

View File

@ -41,6 +41,11 @@ func (e *evaluator) Process(artifacts []*res.Candidate) ([]*res.Candidate, error
return nil, nil
}
// Specify what action is performed to the candidates processed by this evaluator
func (e *evaluator) Action() string {
return action.Retain
}
// New a Evaluator
func New(params rule.Parameters) rule.Evaluator {
if params != nil {

View File

@ -41,6 +41,11 @@ func (e *evaluator) Process(artifacts []*res.Candidate) ([]*res.Candidate, error
return nil, nil
}
// Specify what action is performed to the candidates processed by this evaluator
func (e *evaluator) Action() string {
return action.Retain
}
// New a Evaluator
func New(params rule.Parameters) rule.Evaluator {
if params != nil {