-
Notifications
You must be signed in to change notification settings - Fork 78
TopologyReconciler #440
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
TopologyReconciler #440
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.
Thanks for this Chunyi!
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.
Love the changes so far, but I'm wondering if there can be a couple of changes to the nested data structures we're now using.
controllers/common_test.go
Outdated
| ) | ||
|
|
||
| var _ = Describe("Controllers/Common", func() { | ||
| var _ = Describe("SetInternalDomainName", 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.
I'm not convinced this function SetInternalDomainName needs to exist (before or after this PR!).
In the product code all it does is set a property of the Reconciler, which is already set in main.go.
In the test code, it's only used in common_test.go, to see the responses when the internal domain is either provided or not.
The whole scope of this test file feels weird to me as well - it's not actually testing anything in the common.go despite the name. It also is doing setup of the domain names within the It clauses of each branch (instead of (Just)BeforeEach)
Some suggestions I have:
- Rename this file to
topology_controller_test.go - Delete the
SetInternalDomainNamefunction - In this test, set the domain name when the controllers are instantiated in
suite_test.goto a variable and useJustBeforeEachto change it in each test case 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.
Good point. Method removed and I've updated the test.
main.go
Outdated
| Recorder: mgr.GetEventRecorderFor(controllers.QueueControllerName), | ||
| RabbitmqClientFactory: rabbitmqclient.RabbitholeClientFactory, | ||
| KubernetesClusterDomain: clusterDomain, | ||
| ReconcileFunc: &controllers.QueueReconciler{Recorder: queueRecorder, Client: mgr.GetClient()}, |
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 TopologyReconciler object contains essentially an embedded version of itself, since the QueueReconciler is not too different from the TopologyReconciler object. We're even instantiating it with the same Recorder and Client as the parent type, and that duplication implies to me that there's some bleed between the two in responsibility.
Looking at the old reconcilers, I'm not actually convinced we need to keep them as objects anymore - the two methods DeclareFunc and DeleteFunc very rarely access properties on their respective objects anymore, and so could be functions.
I think with that in mind, the DeclareFunc and DeleteFunc could be converted from methods into functions, and then this property of the TopologyReconciler can literally be a function signature, i.e.
// TopologyReconciler reconciles any topology rabbitmq objects
type TopologyReconciler struct {
client.Client
Type client.Object
WatchTypes []client.Object
Log logr.Logger
Scheme *runtime.Scheme
Recorder record.EventRecorder
RabbitmqClientFactory rabbitmqclient.Factory
KubernetesClusterDomain string
DeleteFunc func(ctx context.Context, client rabbitmqclient.Client, resource topology.TopologyResource) error
DeleteFunc func(ctx context.Context, client rabbitmqclient.Client, resource topology.TopologyResource) error
}TopologyReconciler{
Client: mgr.GetClient(),
Type: &topology.Queue{},
Log: ctrl.Log.WithName(controllers.QueueControllerName),
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorderFor(controllers.QueueControllerName),
RabbitmqClientFactory: rabbitmqclient.RabbitholeClientFactory,
KubernetesClusterDomain: clusterDomain,
DeclareFunc: &controllers.QueueDeclare,
DeleteFunc: &controllers.QueueDelete,
}What do you think?
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 having the declare and delete function directly in TopologyReconciler is going to limit the extensibility. Each resource reconciler needs different input to their declare and delete functions. For example the User and the Permission reconciler needs the Scheme to be able to set owner reference, and federation/shovel needs the k8s client to be able to fetch k8s secret. Having a embeded struct means we have the flexibility of adding fields and use them in declare and delete functions without changing the signature/type.
That said, the Recorder can be removed, and the k8s client can be removed for Reconciler that's not using it. I've updated and re pushed.
- CR reconcilers still needs to implement their own declare and delete logic, but logic regards to finalizers and generate rabbitmq client are all in the TopologyReconciler.Reconciler for deduplication
642343d to
ce830ae
Compare
This closes https://github.com/rabbitmq/service-operator-experience/issues/100
Note to reviewers: remember to look at the commits in this PR and consider if they can be squashed
Note to contributors: remember to re-generate client set if there are any API changes
Summary Of Changes
I will squash the commits or re adjust the commit history before merging.
TopologyReconcilerwhich implements the controller runtimeReconcilerinterface withReconcile()andSetupWithManager(). TheTopologyReconciler.Reconcile()takes care of generating a rabbit hole client, add finalizer to the given object. It calls aDeclareFuncand aDeleteFuncwhich are configured by each custom resourceReconcilerthemselves.TopologyReconciler.Reconcile()also logs/events/set status for the given obj after calling theDeclareFunc(success and failure) andDeleteFunc(success and failure) .Reconcile()andSetupWithManager()method from the generated Reconciler. Any custom reconcile logic will go intoDeclareFuncandDeleteFunc.failed to delete federation upstream parameterit will now becomefailed to delete federation. This is because failed delete (also declare) logging and events are handled in a generic way in theTopologyReconciler.Reconcile()where it formats the message as "failed to delete lowercase-resource-kind". For declare, it would be either "failed to declare lowercase-resource-kind" and "Successfully declared lowercase-resource-kind". For several resources, like Exchange, Binding, Queue, this is the same format as it used to be. For Federation, Shove, Schema replication there is a small change.Additional Context
The
TopologyReconciler.setObservedGeneration()are from reconciler-runtime.