-
Notifications
You must be signed in to change notification settings - Fork 69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement Alphabetical order policy #58
Conversation
err = r.Status().Update(ctx, &pol) | ||
} | ||
return ctrl.Result{}, err | ||
latest, err = r.calculateLatestImageSemver(&policy, repo.Status.CanonicalImageName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we couldn't break these out into implementations of a Policy interface, with a simple map translation here, which would make it easier to test the policies "standalone" ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does "map translation" mean here -- dispatch via a map of policy name -> implementation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that makes sense. I'm going to try to come up with something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@squaremo yes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've moved the logic to an internal policy
package and defined there the policy types and a factory to resolve the type based on the ImagePolicyChoice
object. I think this is a lot better than the switch and allows us to extend further if needed without involving any controller logic changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just some comments, while this is a draft ..
api/v1alpha1/imagepolicy_types.go
Outdated
// If true the order would be: C B A (A would be chosen) | ||
// If false the order would be: A B C (C would be chosen) | ||
// +optional | ||
Reversed *bool `json:"reverse,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An alternative, more familiar to some people, is using order: ASC|DESC
(as in "ascending" or "descending"). The intuitive default would be ascending, which is the same as reverse: false
, the default here and the most useful for e.g., calendar-dated tags.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thinking was based more on the meaning of the adjective, which implies the default ascending order according to the alphabet, so reversed came to mind as the right modifier word. I would be inclined to change it if you think order makes more sense.
api/v1alpha1/imagepolicy_types.go
Outdated
type AlphabeticalPolicy struct { | ||
// Prefix enables filtering the list of tags by given prefix. | ||
// +optional | ||
Prefix string `json:"prefix,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a pattern or a literal? Does the matching prefix get removed before ordering? (Worth putting these considerations in the docs!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now it's just a literal, using strings.HasPrefix
. We can discuss the possibility to use a pattern, though I wasn't able to think of any use case for that, however, some people might find support for that useful. What do you think?
As a side note, zooming out a bit, I think it might make sense to provide the ability to filter out tags at the level of the imagerepository resource as well, in order to prevent polluting the tags database with any unused entries.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you need to clarify the intent of the prefix, i.e. is it matching, or excluding.
To clarify, imagine you are reading the YAML for a policy, you shouldn't really need to go and read the CRD or Go source to work out what it does
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would think users might want to limit the tags the policy would apply to only to a subset of tags e.g rel-*
or nightly-*
. The intention was to use Prefix
for matching this subset, excluding other irrelevant tags.
Would renaming this attribute to MatchTagPrefix
make more sense?
What about supporting multiple values?
Or maybe adding support for regular expressions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made some changes, however, some of the questions I mentioned above are still valid.
err = r.Status().Update(ctx, &pol) | ||
} | ||
return ctrl.Result{}, err | ||
latest, err = r.calculateLatestImageSemver(&policy, repo.Status.CanonicalImageName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does "map translation" mean here -- dispatch via a map of policy name -> implementation?
3969f81
to
6d32f76
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had some minor nits to pick, so I've review-commented. We can also discuss the questions left to resolve, in the main comment thread.
api/v1alpha1/imagepolicy_types.go
Outdated
// literal prefix. If not provided, all the tags from the repository will be | ||
// ordered and compared. | ||
// +optional | ||
MatchTagPrefix string `json:"matchTagPrefix,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To carry on from your suggestion in the previous conversation:
it might make sense to provide the ability to filter out tags at the level of the imagerepository resource
That does make some sense, yes. For some purposes I can see it being useful to filter in the policy -- e.g., if you want nightly-*
builds. For other purposes, you might want to filter in the repository, e.g., if there's specific images that are unusable, or upset the scanning, that you want to filter out. I've posted #62 for this latter use case.
Would renaming this attribute to MatchTagPrefix make more sense?
What about supporting multiple values?
Or maybe adding support for regular expressions?
The name MatchTagPrefix
is good. Your questions make me wonder about few things:
- how to leave room for other ways of filtering later -- e.g., would it ever make sense to have prefix matching and regular expressions, and if not, how to prevent those both being supplied;
- whether this is useful for all selection policies -- maybe you tag your images
dev-<semver>
; - if you might need to remove the prefix before considering the remainder for sorting, as in the
dev-<semver>
example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(posting this in the main comment thread)
@@ -103,12 +102,12 @@ func (r *ImagePolicyReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) | |||
return ctrl.Result{}, nil | |||
} | |||
|
|||
policy := pol.Spec.Policy | |||
resolver, err := policy.Policy(pol.Spec.Policy) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
policy policy policy :-) What about policy.SelectorFromSpec(pol.Spec.Policy)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh man, I'm bad at naming things 🤦♂️
func Policy(choice imagev1.ImagePolicyChoice) (Interface, error) { | ||
var p Interface | ||
var err error | ||
switch { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep this works well 👍
internal/policy/policy.go
Outdated
|
||
package policy | ||
|
||
type Interface interface { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd name this something that describes what it does. (The interface in go's sort package defines the single requirement for sort
, which doesn't typically need to be named outside of its own package -- so it can be forgiven for being named sort.Interface
.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fine, then I'll name it Policer
(I had to check if that word exists and was pleasantly surprised it does).
Open questions:
|
I would argue for policy-scoped filtering rather than per policy type implementation, for me this makes more sense because of my previous experience working with ECR Lifecycle Policies that also enable applying policies based on a prefix-based list of strings.
I think this can be useful even for semver-like tags that maybe have an incompatible prefix e.g.
An inclusive/exclusive comparison mode toggle would be useful considering the case highlighted above. |
e9089b8
to
b42c6b6
Compare
An extra thought on the policy level prefix matching feature. I think it would be best if we implement this after we integrate a "real" database into the controller so that we can use its capabilities to filter out the tags dataset. I'm inclined to remove the prefix matching implementation done in the scope of the Alphabetical ordering policy model type. |
b42c6b6
to
9aa909d
Compare
api/v1alpha1/imagepolicy_types.go
Outdated
@@ -34,6 +34,11 @@ type ImagePolicySpec struct { | |||
// selecting the most recent image |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's what I had in mind re: #62 (comment)
As in, not include the prefix matching here, and just have alphabetical ordering? If so I think that's a good idea, until we resolve those discussions above. |
9aa909d
to
aae7e20
Compare
You can check the currently proposed design, I've moved the prefix filtering into the policy spec itself rather than at the level of the policy type implementation. |
api/v1alpha1/imagepolicy_types.go
Outdated
} | ||
|
||
// TagPrefixMatcher enables filtering tags based on a set of defined rules | ||
type TagPrefixMatcher struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like how this is expressed. At risk of exploding the scope, is it ever useful to match by suffix? Or using a glob? (I would count regexp out, per xkcd).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Considering there are images that have suffixes such as -alpine
, -slim
, -rc
etc. it might be a valid use case. I'm not sure what's the best approach around dealing with both of these use cases, I kind of like more the idea of globbing patterns vs prefix/suffix matching, would probably make sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using something like this maybe?
The only downside moving to glob patterns would probably be that we wouldn't be able to support the current pre-sort "trimming" functionality.
I'm trying to figure out, as a user, what would bring in the most value at the moment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm yeah glob libraries don't tend to implement captures.
Meta-suggestion: shall we move this discussion to an issue or new PR, and reduce this PR to just the alphabetical ordering and related refactoring? That would still be pretty helpful, e.g., for calendar-versioned images.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, will move out the prefix filtering to a separate branch and open a PR once this one gets merged.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@relu i see your branch for this, but do not see an open PR. Dont want to step on any toes, but can we open this PR? Our currently workflow prevents us from moving to the Helm Controller until we have this functionality, but the helm operator is breaking due to the deprecation of the old stable repo, so we are stuck currently: https://github.com/fluxcd/image-reflector-controller/tree/tag-prefix-matching
aae7e20
to
3dd2d2d
Compare
This implementation allows one to set a `MatchTagPrefix` to filter a list of tags and/or use `Order` to set the ordering rule by which tags are evaluated. Signed-off-by: Aurel Canciu <[email protected]>
3dd2d2d
to
9be3bc2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Neat! Thanks @relu 🍍 I really like seeing the tests bolstered too.
@@ -174,7 +175,7 @@ func (r *ImagePolicyReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) | |||
} | |||
r.event(pol, events.EventSeverityInfo, msg) | |||
|
|||
return ctrl.Result{}, nil | |||
return ctrl.Result{}, err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure of the intent of this change, though it doesn't change the meaning of the code as it stands.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Likely a relic from previous changes made that are no longer part of this PR. Should probably be changed back to nil
.
This implementation allows one to set a
Prefix
to filter a list of tags and/or useReverse
alphabetical order through the respective policy type attributes.Relates to #31