-
Notifications
You must be signed in to change notification settings - Fork 218
Custom event filter for controllers #457
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
Conversation
@metacosm this PR is incomplete as it lacks some tests, however I'd like to discuss if it goes in the right direction because there are some behavioral changes:
|
|
||
@Override | ||
public void eventSourceDeRegisteredForResource(String customResourceUid) { |
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.
Why was this method removed?
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.
because the method was only about to remove the generation from the local cache, but since the cache does not exists anymore the method is useless (and the interface provide a default no-op method)
@lburgazzoli will try to take a look soon, like the idea of predicate very much! Will check deeper later. |
At the moment it is like a POC so, lot of things may be wrong :) |
097933b
to
b29157c
Compare
ebca1db
to
326a3ad
Compare
How do you propose to configure the predicate? |
This is an advanced functionality which I don't think it should be made configurable as it depends on the specific spec/status and behavior of the operator so I think this should not be exposed as a configuration option (IMHO, the "generation aware" configuration option should not be exposed too) |
I'm confused: I thought the whole point of this PR was to be able to configure the behavior with more than just a property or annotation value. Could you please explain the use case in greater details, then? |
hi @lburgazzoli @metacosm sorry busy days, will try to take a look today |
Oh sorry I though that with So far what I did is to use var operator = new Operator();
operator.register(new MyController(), new MyConfiguration() {
@Override
public CustomResourcePredicate<MyResource> getPredicate() {
return ...;
}
}); |
OK, so that should part of the configuration overriding mechanism, then… |
will have a look later this week or beginning next week |
I've added support to the conf override, now I wonder if it still make sense to expose the option to configure the generation awarness |
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.
Please rebase your PR so that all commits follow the conventional commit message format: https://www.conventionalcommits.org/en/v1.0.0/
I'm not sure either but then again we can't break the API before v2. That said, the other question I have is how someone using Quarkus where the controller is automatically registered would be able to specify their predicates and have it taken into account… |
What about something like: @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface Controller {
Class<CustomResource> eventFilter default GenrationAwareFilter.class;
} @Controller(
eventFilter = MyCustomResourcePredicate.class
) As alternative the controller should be able to set some config option in its |
@lburgazzoli @metacosm just to add my two cents.
|
// if the finalizer has not been set, the operator logic will add it so there will be | ||
// events generated by the operator itself that won't lead to a new generation so such | ||
// events should not be filtered | ||
final CustomResourceEventFilter<T> finalizerPredicate = |
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.
Why are we checking this with predicate? It would be much simpler and easy to read with just checking directly the field with in a method.
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.
So that the same logic is applied everywhere it's needed instead of having variations of the same code.
Back to the main topic of this PR: In general I think if we could solve these cases elegantly with this predicates as now, it would be a nice way to implement things like generation awareness. On the other hand I see currently two issues:
|
I'm not sure about this point but it can eventually be done or maybe we can clearly document that the As a side note, removing the
This issue/PR is not related to testing or canary deployment (that issue was the one about using label selector #453) but it is about letting the user be able to install advanced filter to reduce the reconcile events. |
If we document that old object might be null, not sure if that would make sense even to put it there - Or we could also replicate the 3 methods in the filter (Create, Update, Delete), (if we are actually going to use informers in the background.) This interface I guess comes from the fact that there is an informer used in the background and the old object is always cached. The main problems with the But on large clusters where there are thousands of custom resources we don't want to cache all the objects since it can happen that there might be just no related events coming for a very long time. In that case it might be more efficient to just read the CR from the k8s API. The plan for the future is that we will provide a configurable cache for this (like Caffein). So in this case the old object won't be available by definition. |
Fine with me, maybe we can have an ad-hoc meeting for this discussion ? |
Definitely, that would be the best IMHO. |
Converted to a draft until we get consensus |
/** | ||
* Determines whether the change between the old version of the resource and the new one needs to | ||
* be propagated to the controller or not. | ||
* |
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.
Should we have filter on Creates(Deletes)?
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.
done
@lburgazzoli will take a look today, after finished my current issue |
try { | ||
lock.lock(); | ||
final var uid = getUID(resource); | ||
if (predicate.test(resources.get(uid))) { | ||
if (passthrough != predicate) { | ||
log.trace("Update cache after condition is true: {}", getName(resource)); | ||
} | ||
resources.put(uid, resource); | ||
// defensive copy | ||
resources.put(getUID(resource), clone(resource)); |
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.
why are we cloning here?
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.
The reason is that as example, if for some reason the process that applies the finalizer fails when updating the object, then the cache would still reporting the object as having the finalizer which is not correct.
it probably won't matter so if it should be removed, I ca do it in a subsequent pr
(configuration, oldResource, newResource) -> { | ||
if (configuration.useFinalizer()) { | ||
final var finalizer = configuration.getFinalizer(); | ||
boolean oldFinalizer = oldResource == null || oldResource.hasFinalizer(finalizer); |
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.
It would be good to write unit tests for these methods, since there is non-trivial logic. But it can be a separate PR.
Fixes #404