-
Notifications
You must be signed in to change notification settings - Fork 55
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
chore(reconciler): refactors Reconciler to simplify handling dependent resources #185
chore(reconciler): refactors Reconciler to simplify handling dependent resources #185
Conversation
This way we can stick to the contract introduced by `Reconciler` interface and keep the code simpler. Additionally adds an idiom to ensure that each type conforms to the interface definition at compile time. Signed-off-by: bartoszmajsak <[email protected]>
This can also help with #183 (comment) |
0ab3d19
to
ebe1d56
Compare
This improvement is built on top of `Reconciler` interface to provide a unified approach for handling dependent resources. For this purpose, from the original `Reconciler` interface, `SubResourceReconciler` interface has been derived. It includes the `Reconcile` function from the parent and in addition provides two additional contracts for handling dependent resources: > `Cleanup` This is expected to be called when there is no relevant ISVC in the namespace. This allows handling "singleton" resources used for all ISVCs across the namespace, e.g. `PodMonitor` or `PeerAuthentication`. > `Delete` Allows to remove resources no longer needed when associated ISVC is deleted. This is currently only used by AuthConfig and Route reconcilers. For the latter, it is needed as the route is in another namespace, therefore we cannot use ISVC as the owner reference. > Enhancements - All reconcilers now include the "compile-time assertion of interface implementation" idiom to ensure consistency across the reconcilers (and to actually leverage the idea of interface contracts). - To simplify and reduce code duplication there are two default implementations (called traits) - `NoResourceRemoval` and `SingleResourcePerNamespace` which can be included in a concrete `SubResourceReconciler`. Signed-off-by: bartoszmajsak <[email protected]>
As it now holds more than a single interface Signed-off-by: bartoszmajsak <[email protected]>
When constructing a manager the defined scheme instance is passed to manager's client. Therefore calling manager.GetClient().Scheme(), or in fact client.Scheme() on injected one, makes passing scheme to reconcilers redundant. This simplifies the code by removing explicit coupling with the scheme instance. Signed-off-by: bartoszmajsak <[email protected]>
With this approach there is no need for extract code in main reconcilers (i.e. KServe and ModelMesh) to handle reconcile/delete/cleanup logic of related resources. The only requirement now is to add instance of the subresource reconciler to the slice, the rest is handled uniformly. It also process all subreconcilers now instead of failing fast on the first occured error, following the eventual consistency approach. This is handled by using go-multierror library which is also found in odh-operator. Signed-off-by: bartoszmajsak <[email protected]>
ebe1d56
to
45ac5fc
Compare
Removing a need for passing |
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 this idea a lot. Thanks for the PR @bartoszmajsak. I was wondering if it'd be a good idea to document the implementation expectation for new subresource reconcilers? The explanation you've provided in the PR is excellent, maybe we can add it in a more permanent location (docs/DEVELOPERS_GUIDE.MD perhaps?) Might help the repo stay consistent in the future. WDYT
Oh totally! Excellent suggestion. That's more or less the reason I went one step further with PR description :) Once we get this PR finalized, and I expect some changes based on feedback, I will follow up with refined dev docs. |
return err | ||
} | ||
return nil | ||
} | ||
|
||
func (r *KserveAuthConfigReconciler) Delete(ctx context.Context, log logr.Logger, isvc *kservev1beta1.InferenceService) error { |
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 do we need explicit Delete function implementation for authorinov1beta2.AuthConfig
type resource. As I understood, it already connected with owner reference of InferenceService?
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.
Yes, I thought about it too. It's been like that before and I wonder if we need it. We have an internal store of processed templates, that's why there's this hook here, though it's not really about Deleting stuff in the cluster. @aslakknutsen can this be simplified somehow?
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 store is just a wrapper around Client and has no logic per say. We could leave clean up to Kubernetes GC as suggested.
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.
Ok then it would only leave route reconciler left with Delete, as it's a special case as route sits in istio ns. I will clean it up.
That's this piece in main
:
odh-model-controller/controllers/reconcilers/kserve_route_reconciler.go
Lines 202 to 204 in 5db4925
func (r *KserveRouteReconciler) DeleteRoute(ctx context.Context, isvc *kservev1beta1.InferenceService) error { | |
return r.routeHandler.DeleteRoute(ctx, types.NamespacedName{Name: getKServeRouteName(isvc), Namespace: constants2.IstioNamespace}) | |
} |
controllers/reconcilers/kserve_istio_servicemonitor_reconciler.go
Outdated
Show resolved
Hide resolved
"k8s.io/apimachinery/pkg/types" | ||
ctrl "sigs.k8s.io/controller-runtime" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
) | ||
|
||
var _ SubResourceReconciler = (*KserveAuthConfigReconciler)(nil) | ||
|
||
type KserveAuthConfigReconciler 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.
KserveAuthConfigReconciler
should implement NoResourceRemoval
interface as it have owner relationship with inference 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.
See #185 (comment)
Signed-off-by: bartoszmajsak <[email protected]>
Signed-off-by: bartoszmajsak <[email protected]>
Signed-off-by: bartoszmajsak <[email protected]>
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.
Code changes looks good to me. I didn't get a chance to test these changes by running a inference on cluster. Could you please verify it once.
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.
Very nice @bartoszmajsak
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
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: bartoszmajsak, spolti, vaibhavjainwiz, VedantMahabaleshwarkar The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Description
This improvement is built on top of
Reconciler
interface to provide a unified approach for handling dependent resources. For this purpose, from the originalReconciler
interface,SubResourceReconciler
interface has been derived.It includes the
Reconcile
function from the parent and in addition provides two additional contracts for handling dependent resources:Cleanup
This is expected to be called when there is no relevant ISVC in the namespace. This allows handling "singleton" resources used for all ISVCs across the namespace, e.g.
PodMonitor
orPeerAuthentication
.Delete
Allows to remove resources no longer needed when associated ISVC is deleted. This is currently only used by AuthConfig and Route reconcilers. For the latter, it is needed as the route is in another namespace, therefore we cannot use ISVC as the owner reference.
Other considerations
Alternatively, we could make a distinction between sub-resource being dependent on the ISVC instance (e.g. auth config) and one-per namespace (pod monitor) and split
SubResourceReconciler
to two for separating concerns.Enhancements
Compile-time interface check
All reconcilers now include the "compile-time assertion of interface implementation" idiom to ensure consistency across the reconcilers (and actually to leverage the idea of interface contracts).
Traits
To simplify and reduce code duplication there are two default implementations (called traits) -
NoResourceRemoval
andSingleResourcePerNamespace
which can be included in a concreteSubResourceReconciler.
No
schema
passingWhen constructing a manager the defined scheme instance is passed to the manager's client. Therefore calling
manager.GetClient().Scheme()
, or in factclient.Scheme()
on injected one, makes passing scheme to reconcilers redundant.This change simplifies the code by removing explicit coupling with the scheme instance.
Reconcilers in the slice
With this approach, there is no need for direct calls in main reconcilers (i.e. KServe and ModelMesh) to handle reconcile/delete/cleanup logic of related resources. The only requirement now is to add an instance of the subresource reconciler to the slice, the rest is handled uniformly.
I also process all sub-reconcilers now instead of failing fast on the first error, following the eventual consistency approach.
Other minor changes
reconciler.go
becomestypes.go
as it holds more than one interface now.Out-of-scope considerations
There are a few things I noted, but felt like a scope creep to work on them as part of this PR (it's already big and I wanted to refactor, so preserve the behavior and only change the internal structure):
ctx
with the log instead of passing it down the call chain.logf
allows to easily attach and extract log from ctx. We already use it in webhookHow Has This Been Tested?
Merge criteria: