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 // processor to handle the rules with OR mapping ways
type processor struct { type processor struct {
performer action.Performer
// keep evaluator and its related selector if existing // keep evaluator and its related selector if existing
// attentions here, the selectors can be empty/nil, that means match all "**" // attentions here, the selectors can be empty/nil, that means match all "**"
evaluators map[*rule.Evaluator][]res.Selector evaluators map[*rule.Evaluator][]res.Selector
// action performer
performers map[string]action.Performer
} }
// New processor // New processor
func New() alg.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 // Process the candidates with the rules
@ -47,12 +51,17 @@ func (p *processor) Process(artifacts []*res.Candidate) ([]*res.Result, error) {
var ( var (
// collect errors by wrapping // collect errors by wrapping
err error err error
// collect results // collect processed candidates
retained = make([]*res.Candidate, 0) processedCandidates = make(map[string][]*res.Candidate)
) )
// for sync // for sync
resChan := make(chan []*res.Candidate, 1) type chanItem struct {
action string
processed []*res.Candidate
}
resChan := make(chan *chanItem, 1)
// handle error // handle error
errChan := make(chan error, 1) errChan := make(chan error, 1)
// control chan // control chan
@ -67,8 +76,12 @@ func (p *processor) Process(artifacts []*res.Candidate) ([]*res.Result, error) {
go func() { go func() {
for { for {
select { select {
case retainedOnes := <-resChan: case result := <-resChan:
retained = append(retained, retainedOnes...) 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: case e := <-errChan:
if err == nil { if err == nil {
err = errors.Wrap(e, "artifact processing error") 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 { if len(processed) > 0 {
// Pass to the outside // Pass to the outside
resChan <- processed resChan <- &chanItem{
action: evaluator.Action(),
processed: processed,
}
} }
}(evaluator, selectors) }(evaluator, selectors)
} }
@ -132,7 +148,32 @@ func (p *processor) Process(artifacts []*res.Candidate) ([]*res.Result, error) {
return nil, err 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 // 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 // SetPerformer sets a action performer to the processor
func (p *processor) SetPerformer(performer action.Performer) { func (p *processor) AddActionPerformer(action string, performer action.Performer) {
p.performer = 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 // selectors []res.Selector : selectors to narrow down the scope (&& adopted), optional
AddEvaluator(evaluator rule.Evaluator, selectors []res.Selector) AddEvaluator(evaluator rule.Evaluator, selectors []res.Selector)
// Set performer for the processor // Add performer for the related action to the processor
// //
// Arguments: // Arguments:
// action string : action name
// performer action.Performer : a performer implementation // performer action.Performer : a performer implementation
SetPerformer(performer action.Performer) AddActionPerformer(action string, performer action.Performer)
} }

View File

@ -15,7 +15,12 @@
package policy package policy
import ( 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"
"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" "github.com/pkg/errors"
) )
@ -32,8 +37,17 @@ type Builder interface {
Build(rawPolicy string) (alg.Processor, error) 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 // basicBuilder is default implementation of Builder interface
type basicBuilder struct{} type basicBuilder struct {
allCandidates []*res.Candidate
}
// Build policy processor from the raw policy // Build policy processor from the raw policy
func (bb *basicBuilder) Build(rawPolicy string) (alg.Processor, error) { 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 { switch liteMeta.Algorithm {
case AlgorithmOR: case AlgorithmOR:
default: // New OR processor
return nil, errors.Errorf("algorithm %s is not supported", liteMeta.Algorithm) p := or.New()
for _, r := range liteMeta.Rules {
evaluator, err := rule.Get(r.Template, r.Parameters)
if err != nil {
return nil, err
} }
return nil, errors.New("not implemented") 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)
} }

View File

@ -27,6 +27,9 @@ type Evaluator interface {
// []*res.Candidate : matched candidates for next stage // []*res.Candidate : matched candidates for next stage
// error : common error object if any errors occurred // error : common error object if any errors occurred
Process(artifacts []*res.Candidate) ([]*res.Candidate, error) 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 // 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 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 // New a Evaluator
func New(params rule.Parameters) rule.Evaluator { func New(params rule.Parameters) rule.Evaluator {
if params != nil { if params != nil {

View File

@ -41,6 +41,11 @@ func (e *evaluator) Process(artifacts []*res.Candidate) ([]*res.Candidate, error
return nil, nil 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 // New a Evaluator
func New(params rule.Parameters) rule.Evaluator { func New(params rule.Parameters) rule.Evaluator {
if params != nil { if params != nil {