diff --git a/src/replication/filter/filter.go b/src/replication/filter/filter.go index 6f2d6e72a..e28ffe61b 100644 --- a/src/replication/filter/filter.go +++ b/src/replication/filter/filter.go @@ -72,9 +72,9 @@ func NewVTagNameFilter(pattern string) Filter { } // NewVTagLabelFilter return a Filter to filter vtags according to the label -func NewVTagLabelFilter(label string) Filter { +func NewVTagLabelFilter(labels []string) Filter { return &labelFilter{ - label: label, + labels: labels, } } @@ -138,7 +138,7 @@ func (n *nameFilter) Filter(filterables ...Filterable) ([]Filterable, error) { } type labelFilter struct { - label string + labels []string } func (l *labelFilter) ApplyTo(filterable Filterable) bool { @@ -154,18 +154,24 @@ func (l *labelFilter) ApplyTo(filterable Filterable) bool { func (l *labelFilter) Filter(filterables ...Filterable) ([]Filterable, error) { // if no specified label in the filter, just returns the input filterable // candidate as the result - if len(l.label) == 0 { + if len(l.labels) == 0 { return filterables, nil } result := []Filterable{} for _, filterable := range filterables { - match := false + labels := map[string]struct{}{} for _, label := range filterable.GetLabels() { - if label == l.label { - match = true + labels[label] = struct{}{} + } + match := true + for _, label := range l.labels { + if _, exist := labels[label]; !exist { + match = false break } } + // add the filterable to the result list if it contains + // all labels defined for the filter if match { result = append(result, filterable) } diff --git a/src/replication/filter/filter_test.go b/src/replication/filter/filter_test.go index 4a379c048..a066b6a7d 100644 --- a/src/replication/filter/filter_test.go +++ b/src/replication/filter/filter_test.go @@ -120,7 +120,7 @@ func TestFilterOfLabelFilter(t *testing.T) { } // pass the filter filter := &labelFilter{ - label: "production", + labels: []string{"production"}, } result, err := filter.Filter(filterable) require.Nil(t, err) @@ -128,7 +128,7 @@ func TestFilterOfLabelFilter(t *testing.T) { assert.True(t, reflect.DeepEqual(filterable, result[0].(*fakeFilterable))) } // cannot pass the filter - filter.label = "cannotpass" + filter.labels = []string{"production", "ci-pass"} result, err = filter.Filter(filterable) require.Nil(t, err) assert.Equal(t, 0, len(result)) @@ -160,7 +160,7 @@ func TestDoFilter(t *testing.T) { filterables := []Filterable{tag1, tag2} filters := []Filter{ NewVTagNameFilter("*"), - NewVTagLabelFilter("production"), + NewVTagLabelFilter([]string{"production"}), } err := DoFilter(&filterables, filters...) require.Nil(t, err) diff --git a/src/replication/model/policy.go b/src/replication/model/policy.go index 130f34e3c..21c89565f 100644 --- a/src/replication/model/policy.go +++ b/src/replication/model/policy.go @@ -88,19 +88,33 @@ func (p *Policy) Valid(v *validation.Validation) { // valid the filters for _, filter := range p.Filters { - value, ok := filter.Value.(string) - if !ok { - v.SetError("filters", "the type of filter value isn't string") - break - } switch filter.Type { - case FilterTypeResource: - rt := ResourceType(value) - if !(rt == ResourceTypeImage || rt == ResourceTypeChart) { - v.SetError("filters", fmt.Sprintf("invalid resource filter: %s", value)) + case FilterTypeResource, FilterTypeName, FilterTypeTag: + value, ok := filter.Value.(string) + if !ok { + v.SetError("filters", "the type of filter value isn't string") break } - case FilterTypeName, FilterTypeTag, FilterTypeLabel: + if filter.Type == FilterTypeResource { + rt := ResourceType(value) + if !(rt == ResourceTypeImage || rt == ResourceTypeChart) { + v.SetError("filters", fmt.Sprintf("invalid resource filter: %s", value)) + 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 @@ -148,7 +162,10 @@ func (f *Filter) DoFilter(filterables interface{}) error { case FilterTypeTag: ft = filter.NewVTagNameFilter(f.Value.(string)) case FilterTypeLabel: - ft = filter.NewVTagLabelFilter(f.Value.(string)) + labels, ok := f.Value.([]string) + if ok { + ft = filter.NewVTagLabelFilter(labels) + } case FilterTypeResource: ft = filter.NewResourceTypeFilter(f.Value.(string)) default: diff --git a/src/replication/model/policy_test.go b/src/replication/model/policy_test.go index 190e1b6e8..262c0b23f 100644 --- a/src/replication/model/policy_test.go +++ b/src/replication/model/policy_test.go @@ -105,8 +105,8 @@ func TestValidOfPolicy(t *testing.T) { Value: ResourceTypeImage, }, { - Type: FilterTypeName, - Value: "a[", + Type: FilterTypeTag, + Value: "", }, }, }, diff --git a/src/replication/policy/manager/manager.go b/src/replication/policy/manager/manager.go index 42735e9ee..cdd67a20c 100644 --- a/src/replication/policy/manager/manager.go +++ b/src/replication/policy/manager/manager.go @@ -271,6 +271,13 @@ func parseFilters(str string) ([]*model.Filter, error) { if filter.Type == model.FilterTypeResource { filter.Value = (model.ResourceType)(filter.Value.(string)) } + if filter.Type == model.FilterTypeLabel { + labels := []string{} + for _, label := range filter.Value.([]interface{}) { + labels = append(labels, label.(string)) + } + filter.Value = labels + } filters = append(filters, filter) } return filters, nil