Merge pull request #860 from jonathan-innis/joinnis/image-policy

Adding --select-alpha and --extract to create image policy
pull/893/head
Stefan Prodan 4 years ago committed by GitHub
commit 35507c7854
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -171,7 +171,13 @@ jobs:
./bin/flux create image policy podinfo \ ./bin/flux create image policy podinfo \
--image-ref=podinfo \ --image-ref=podinfo \
--interval=1m \ --interval=1m \
--semver=5.0.x --select-semver=5.0.x
- name: flux create image policy podinfo-select-alpha
run: |
./bin/flux create image policy podinfo-alpha \
--image-ref=podinfo \
--interval=1m \
--select-alpha=desc
- name: flux get image policy - name: flux get image policy
run: | run: |
./bin/flux get image policy podinfo | grep '5.0.3' ./bin/flux get image policy podinfo | grep '5.0.3'

@ -18,6 +18,10 @@ package main
import ( import (
"fmt" "fmt"
"regexp/syntax"
"strings"
"unicode"
"unicode/utf8"
"github.com/spf13/cobra" "github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -41,7 +45,9 @@ the status of the object.`,
type imagePolicyFlags struct { type imagePolicyFlags struct {
imageRef string imageRef string
semver string semver string
alpha string
filterRegex string filterRegex string
filterExtract string
} }
var imagePolicyArgs = imagePolicyFlags{} var imagePolicyArgs = imagePolicyFlags{}
@ -49,8 +55,10 @@ var imagePolicyArgs = imagePolicyFlags{}
func init() { func init() {
flags := createImagePolicyCmd.Flags() flags := createImagePolicyCmd.Flags()
flags.StringVar(&imagePolicyArgs.imageRef, "image-ref", "", "the name of an image repository object") flags.StringVar(&imagePolicyArgs.imageRef, "image-ref", "", "the name of an image repository object")
flags.StringVar(&imagePolicyArgs.semver, "semver", "", "a semver range to apply to tags; e.g., '1.x'") flags.StringVar(&imagePolicyArgs.semver, "select-semver", "", "a semver range to apply to tags; e.g., '1.x'")
flags.StringVar(&imagePolicyArgs.filterRegex, "filter-regex", "", " regular expression pattern used to filter the image tags") flags.StringVar(&imagePolicyArgs.alpha, "select-alpha", "", "use alphabetical sorting to select image; either \"asc\" meaning select the last, or \"desc\" meaning select the first")
flags.StringVar(&imagePolicyArgs.filterRegex, "filter-regex", "", "regular expression pattern used to filter the image tags")
flags.StringVar(&imagePolicyArgs.filterExtract, "filter-extract", "", "replacement pattern (using capture groups from --filter-regex) to use for sorting")
createImageCmd.AddCommand(createImagePolicyCmd) createImageCmd.AddCommand(createImagePolicyCmd)
} }
@ -90,18 +98,40 @@ func createImagePolicyRun(cmd *cobra.Command, args []string) error {
} }
switch { switch {
case imagePolicyArgs.semver != "" && imagePolicyArgs.alpha != "":
return fmt.Errorf("policy cannot be specified with both --select-semver and --select-alpha")
case imagePolicyArgs.semver != "": case imagePolicyArgs.semver != "":
policy.Spec.Policy.SemVer = &imagev1.SemVerPolicy{ policy.Spec.Policy.SemVer = &imagev1.SemVerPolicy{
Range: imagePolicyArgs.semver, Range: imagePolicyArgs.semver,
} }
case imagePolicyArgs.alpha != "":
if imagePolicyArgs.alpha != "desc" && imagePolicyArgs.alpha != "asc" {
return fmt.Errorf("--select-alpha must be one of [\"asc\", \"desc\"]")
}
policy.Spec.Policy.Alphabetical = &imagev1.AlphabeticalPolicy{
Order: imagePolicyArgs.alpha,
}
default: default:
return fmt.Errorf("a policy must be provided with --semver") return fmt.Errorf("a policy must be provided with either --select-semver or --select-alpha")
} }
if imagePolicyArgs.filterRegex != "" { if imagePolicyArgs.filterRegex != "" {
exp, err := syntax.Parse(imagePolicyArgs.filterRegex, syntax.Perl)
if err != nil {
return fmt.Errorf("--filter-regex is an invalid regex pattern")
}
policy.Spec.FilterTags = &imagev1.TagFilter{ policy.Spec.FilterTags = &imagev1.TagFilter{
Pattern: imagePolicyArgs.filterRegex, Pattern: imagePolicyArgs.filterRegex,
} }
if imagePolicyArgs.filterExtract != "" {
if err := validateExtractStr(imagePolicyArgs.filterExtract, exp.CapNames()); err != nil {
return err
}
policy.Spec.FilterTags.Extract = imagePolicyArgs.filterExtract
}
} else if imagePolicyArgs.filterExtract != "" {
return fmt.Errorf("cannot specify --filter-extract without specifying --filter-regex")
} }
if createArgs.export { if createArgs.export {
@ -117,3 +147,94 @@ func createImagePolicyRun(cmd *cobra.Command, args []string) error {
}) })
return err return err
} }
// Performs a dry-run of the extract function in Regexp to validate the template
func validateExtractStr(template string, capNames []string) error {
for len(template) > 0 {
i := strings.Index(template, "$")
if i < 0 {
return nil
}
template = template[i:]
if len(template) > 1 && template[1] == '$' {
template = template[2:]
continue
}
name, num, rest, ok := extract(template)
if !ok {
// Malformed extract string, assume user didn't want this
template = template[1:]
return fmt.Errorf("--filter-extract is malformed")
}
template = rest
if num >= 0 {
// we won't worry about numbers as we can't validate these
continue
} else {
found := false
for _, capName := range capNames {
if name == capName {
found = true
}
}
if !found {
return fmt.Errorf("capture group $%s used in --filter-extract not found in --filter-regex", name)
}
}
}
return nil
}
// extract method from the regexp package
// returns the name or number of the value prepended by $
func extract(str string) (name string, num int, rest string, ok bool) {
if len(str) < 2 || str[0] != '$' {
return
}
brace := false
if str[1] == '{' {
brace = true
str = str[2:]
} else {
str = str[1:]
}
i := 0
for i < len(str) {
rune, size := utf8.DecodeRuneInString(str[i:])
if !unicode.IsLetter(rune) && !unicode.IsDigit(rune) && rune != '_' {
break
}
i += size
}
if i == 0 {
// empty name is not okay
return
}
name = str[:i]
if brace {
if i >= len(str) || str[i] != '}' {
// missing closing brace
return
}
i++
}
// Parse number.
num = 0
for i := 0; i < len(name); i++ {
if name[i] < '0' || '9' < name[i] || num >= 1e8 {
num = -1
break
}
num = num*10 + int(name[i]) - '0'
}
// Disallow leading zeros.
if name[0] == '0' && len(name) > 1 {
num = -1
}
rest = str[i:]
ok = true
return
}

@ -18,10 +18,12 @@ flux create image policy <name> [flags]
### Options ### Options
``` ```
--filter-extract string replacement pattern (using capture groups from --filter-regex) to use for sorting
--filter-regex string regular expression pattern used to filter the image tags --filter-regex string regular expression pattern used to filter the image tags
-h, --help help for policy -h, --help help for policy
--image-ref string the name of an image repository object --image-ref string the name of an image repository object
--semver string a semver range to apply to tags; e.g., '1.x' --select-alpha string use alphabetical sorting to select image; either "asc" meaning select the last, or "desc" meaning select the first
--select-semver string a semver range to apply to tags; e.g., '1.x'
``` ```
### Options inherited from parent commands ### Options inherited from parent commands

Loading…
Cancel
Save