-
Notifications
You must be signed in to change notification settings - Fork 2
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
ROX-19221: Fix reconciling with label selector for multiple reconcilers #42
ROX-19221: Fix reconciling with label selector for multiple reconcilers #42
Conversation
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.
Great job debugging this issue @kurlov!
Pull Request Test Coverage Report for Build 5957809598
💛 - Coveralls |
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 solution looks workable, but a bit rough from my point of view. I would consider adding a label selector to watch
as designed in controller-runtime
@@ -650,6 +651,11 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (res ctrl. | |||
return ctrl.Result{}, err | |||
} | |||
|
|||
if r.selectorPredicate != nil && !r.selectorPredicate.Generic(event.GenericEvent{Object: obj}) { |
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 don't put labels on secrets instead? I.e. do a k8s client customization as it is done for the ownerReference.
Adding correct label selector on secrets watch may also give a performance benefit.
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.
Passing predicate to the secret watch was initial approach. But the downside is that it hides filtering mechanism and it's pretty easy to overlook it in the future (e.g. adding additional watch). Filtering selector in the reconcile is straightforward and robust approach. But you are right, it's not the best in terms of CPU because Reconcile call is triggered
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 CPU consumption is minimal here, a reconcile call in itself it is not computationally expensive - it starts a function with exits immediately.
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.
LGTM, two nits for the custom reconcile.Result and naming.
@@ -650,6 +651,11 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (res ctrl. | |||
return ctrl.Result{}, err | |||
} | |||
|
|||
if r.selectorPredicate != nil && !r.selectorPredicate.Generic(event.GenericEvent{Object: obj}) { | |||
log.V(1).Info("Label selector does not match, skipping reconcile") |
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.
Can you add the affected object and labels to the log message?
As an engineer I would like to see more details why it was skipped and get a hint which label would reconcile the CR.
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.
Name and namespace is part of the logger
Log message will look like this:
2023-08-25T16:25:05+02:00 DEBUG controllers.Central Label selector does not match, skipping reconcile {"central": {"name":"stackrox-central-services","namespace":"stackrox"}}
pkg/reconciler/reconciler_test.go
Outdated
@@ -1392,6 +1397,40 @@ var _ = Describe("Reconciler", func() { | |||
}) | |||
}) | |||
}) | |||
When("label selector succeeds", func() { | |||
It("reconciles only matching label", func() { | |||
By("setting a broken action client getter for the reconciler", func() { |
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.
This describes the action, can you describe it's impact/reason why it is necessary to add a broken action client getter?
For example:
By returning an invalid action client getter to assert different reconcile results
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.
If possible, the solution you've proposed using a custom reconcile.Result
object for a skipped reconcile looks cleaner to me. Changing action client getter would have side-effects on this test, when using the reconcile.Result
the test is side-effect free.
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.
Even though introducing a new result type is a small change but it might effect many part and I would like to reduce scope to the bug fixing only
…rs (#42) * Add filter predicate to secret kind watch * Change fix to filter resource in the reconcile function * Fix doc string typo * Update description for setting broken action client
Issue
Assume there is CR with label
foo=bar
.If run one reconciler with label selector
foo=bar
then everything is fine and the reconciler processes the CR.If start another reconciler with label
foo=another
then this new reconciler also reconcilesfoo=bar
CR. This is not expected.Root cause
There is controller.Watch set for
Secret
kind. This watch has event handler. The Event handler only filters events byGroupVersionKind
of the CR so label selector is ignoredFix
Check for the matching label selector before performing reconcile. Skip reconcile if label is not matching
Local testing with stackrox operator on fresh cluster