Skip to content
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

Merged
merged 1 commit into from
Dec 10, 2020
Merged

Conversation

relu
Copy link
Member

@relu relu commented Nov 24, 2020

This implementation allows one to set a Prefix to filter a list of tags and/or use Reverse alphabetical order through the respective policy type attributes.

Relates to #31

@relu relu mentioned this pull request Nov 24, 2020
err = r.Status().Update(ctx, &pol)
}
return ctrl.Result{}, err
latest, err = r.calculateLatestImageSemver(&policy, repo.Status.CanonicalImageName)
Copy link
Contributor

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" ?

Copy link
Member

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?

Copy link
Member Author

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@squaremo yes

Copy link
Member Author

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.

Copy link
Member

@squaremo squaremo left a 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 ..

// 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"`
Copy link
Member

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.

Copy link
Member Author

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.

type AlphabeticalPolicy struct {
// Prefix enables filtering the list of tags by given prefix.
// +optional
Prefix string `json:"prefix,omitempty"`
Copy link
Member

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!)

Copy link
Member Author

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.

Copy link
Contributor

@bigkevmcd bigkevmcd Nov 25, 2020

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

Copy link
Member Author

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?

Copy link
Member Author

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)
Copy link
Member

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?

@relu relu force-pushed the alphabetical-order-policy branch 2 times, most recently from 3969f81 to 6d32f76 Compare November 27, 2020 20:12
@relu relu marked this pull request as ready for review November 27, 2020 20:13
Copy link
Member

@squaremo squaremo left a 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.

// literal prefix. If not provided, all the tags from the repository will be
// ordered and compared.
// +optional
MatchTagPrefix string `json:"matchTagPrefix,omitempty"`
Copy link
Member

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.

Copy link
Member

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)
Copy link
Member

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)

Copy link
Member Author

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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep this works well 👍


package policy

type Interface interface {
Copy link
Member

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.)

Copy link
Member Author

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).

@squaremo
Copy link
Member

squaremo commented Dec 1, 2020

Open questions:

  • 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-;
  • if you might need to remove the prefix before considering the remainder for sorting, as in the dev- example.

@relu
Copy link
Member Author

relu commented Dec 1, 2020

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;

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.

whether this is useful for all selection policies -- maybe you tag your images dev-;

I think this can be useful even for semver-like tags that maybe have an incompatible prefix e.g. ver1.2.3 instead of the supported format v1.2.3. This would enable folks to make use of semver policying w/o having to change the format of their tags, or in the situation that would not even be possible due to the repository being outside of their control.

if you might need to remove the prefix before considering the remainder for sorting, as in the dev- example.

An inclusive/exclusive comparison mode toggle would be useful considering the case highlighted above.

@relu relu force-pushed the alphabetical-order-policy branch 2 times, most recently from e9089b8 to b42c6b6 Compare December 1, 2020 16:27
@relu
Copy link
Member Author

relu commented Dec 2, 2020

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.

@@ -34,6 +34,11 @@ type ImagePolicySpec struct {
// selecting the most recent image
Copy link
Member Author

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)

@squaremo
Copy link
Member

squaremo commented Dec 3, 2020

I'm inclined to remove the prefix matching implementation done in the scope of the Alphabetical ordering policy model type.

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.

@relu relu force-pushed the alphabetical-order-policy branch from 9aa909d to aae7e20 Compare December 4, 2020 17:29
@relu
Copy link
Member Author

relu commented Dec 4, 2020

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.

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.

}

// TagPrefixMatcher enables filtering tags based on a set of defined rules
type TagPrefixMatcher struct {
Copy link
Member

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).

Copy link
Member Author

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.

Copy link
Member Author

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.

Copy link
Member

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.

Copy link
Member Author

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.

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

@relu relu force-pushed the alphabetical-order-policy branch from aae7e20 to 3dd2d2d Compare December 9, 2020 15:13
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]>
@relu relu force-pushed the alphabetical-order-policy branch from 3dd2d2d to 9be3bc2 Compare December 9, 2020 19:02
@relu relu requested a review from squaremo December 9, 2020 19:05
Copy link
Member

@squaremo squaremo left a 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
Copy link
Member

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.

Copy link
Member Author

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.

@relu relu merged commit 60e1fb8 into main Dec 10, 2020
@relu relu deleted the alphabetical-order-policy branch December 10, 2020 13:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants