Skip to content
This repository has been archived by the owner on Nov 1, 2022. It is now read-only.

Image filtering with regular expressions #1292

Merged
merged 3 commits into from
Aug 17, 2018
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions cluster/kubernetes/policies_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,23 @@ func TestUpdatePolicies(t *testing.T) {
},
wantErr: true,
},
{
name: "add regexp tag policy",
in: nil,
out: []string{"flux.weave.works/tag.nginx", "regexp:(.*?)"},
update: policy.Update{
Add: policy.Set{policy.TagPrefix("nginx"): "regexp:(.*?)"},
},
},
{
name: "add invalid regexp tag policy",
in: nil,
out: []string{"flux.weave.works/tag.nginx", "regexp:(.*?)"},
update: policy.Update{
Add: policy.Set{policy.TagPrefix("nginx"): "regexp:*"},
},
wantErr: true,
},
} {
t.Run(c.name, func(t *testing.T) {
caseIn := templToString(t, annotationsTemplate, c.in)
Expand Down
43 changes: 38 additions & 5 deletions policy/pattern.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import (
"github.com/ryanuber/go-glob"
"github.com/weaveworks/flux/image"
"strings"
"regexp"
)

const (
globPrefix = "glob:"
semverPrefix = "semver:"
regexpPrefix = "regexp:"
)

var (
Expand Down Expand Up @@ -39,17 +41,28 @@ type SemverPattern struct {
constraints *semver.Constraints
}

// NewPattern instantiates a Pattern according to the prefix
// it finds. The prefix can be either `glob:` (default if omitted)
// or `semver:`.
// RegexpPattern matches by regular expression.
type RegexpPattern struct {
pattern string // pattern without prefix
regexp *regexp.Regexp
}

// NewPattern instantiates a Pattern according to the prefix
// it finds. The prefix can be either `glob:` (default if omitted),
// `semver:` or `regexp:`.
func NewPattern(pattern string) Pattern {
if strings.HasPrefix(pattern, semverPrefix) {
switch {
case strings.HasPrefix(pattern, semverPrefix):
pattern = strings.TrimPrefix(pattern, semverPrefix)
c, _ := semver.NewConstraint(pattern)
return SemverPattern{pattern, c}
case strings.HasPrefix(pattern, regexpPrefix):
pattern = strings.TrimPrefix(pattern, regexpPrefix)
r, _ := regexp.Compile(pattern)
return RegexpPattern{pattern, r}
default:
return GlobPattern(strings.TrimPrefix(pattern, globPrefix))
}
return GlobPattern(strings.TrimPrefix(pattern, globPrefix))
}

func (g GlobPattern) Matches(tag string) bool {
Expand Down Expand Up @@ -91,3 +104,23 @@ func (s SemverPattern) Newer(a, b *image.Info) bool {
func (s SemverPattern) Valid() bool {
return s.constraints != nil
}

func (r RegexpPattern) Matches(tag string) bool {
if r.regexp == nil {
// Invalid regexp match anything
return true
}
return r.regexp.MatchString(tag)
}

func (r RegexpPattern) String() string {
return regexpPrefix + r.pattern
}

func (r RegexpPattern) Newer(a, b *image.Info) bool {
return image.NewerByCreated(a, b)
}

func (r RegexpPattern) Valid() bool {
return r.regexp != nil
}
35 changes: 35 additions & 0 deletions policy/pattern_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,38 @@ func TestSemverPattern_Matches(t *testing.T) {
}
}
}

func TestRegexpPattern_Matches(t *testing.T) {
for _, tt := range []struct {
name string
pattern string
true []string
false []string
}{
{
name: "all prefixed",
pattern: "regexp:(.*?)",
true: []string{"", "1", "foo"},
false: nil,
},
{
name: "regexp",
pattern: "regexp:^([a-zA-Z]+)$",
true: []string{"foo", "BAR", "fooBAR"},
false: []string{"1", "foo-1"},
},
} {
pattern := NewPattern(tt.pattern)
assert.IsType(t, RegexpPattern{}, pattern)
for _, tag := range tt.true {
t.Run(fmt.Sprintf("%s[%q]", tt.name, tag), func(t *testing.T) {
assert.True(t, pattern.Matches(tag))
})
}
for _, tag := range tt.false {
t.Run(fmt.Sprintf("%s[%q]", tt.name, tag), func(t *testing.T) {
assert.False(t, pattern.Matches(tag))
})
}
}
}
5 changes: 5 additions & 0 deletions site/using.md
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,11 @@ fluxctl policy --controller=default:deployment/helloworld --tag-all='semver:*'
Using a semver filter will also affect how flux sorts images, so
that the higher versions will be considered newer.

If your images have complex tags you can filter by regular expression:
```
fluxctl policy --controller=default:deployment/helloworld --tag-all='regexp:^([a-zA-Z]+)$'
```

This comment was marked as abuse.

## Actions triggered through `fluxctl`

`fluxctl` provides the following flags for the message and author customization:
Expand Down