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

feat: adds controller to allow addon to reconcile on changes #46

Open
wants to merge 13 commits into
base: main
Choose a base branch
from

Conversation

JoaoBraveCoding
Copy link
Collaborator

This PR introduces a controller that will watch for resources used for the addon configuration and it will annotate the corresponding ManifestWorks triggering a reconciliation

@coveralls
Copy link

coveralls commented May 6, 2024

Pull Request Test Coverage Report for Build 9209225475

Details

  • 0 of 0 changed or added relevant lines in 0 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage remained the same at 50.637%

Totals Coverage Status
Change from base Build 8877284128: 0.0%
Covered Lines: 318
Relevant Lines: 628

💛 - Coveralls

@iblancasa
Copy link
Contributor

It seems I have permission to push to this branch. I added a commit and reverted it. Added my changes in JoaoBraveCoding#11

iblancasa and others added 2 commits May 14, 2024 14:29
* Move the watcher cli application to be a go routine

Signed-off-by: Israel Blancas <iblancasa@gmail.com>

* Fix lint

Signed-off-by: Israel Blancas <iblancasa@gmail.com>

* Fix lint

Signed-off-by: Israel Blancas <iblancasa@gmail.com>

* Update internal/controllers/watcher/controller.go

Co-authored-by: Joao Marcal <joao.marcal12@gmail.com>

* Update internal/controllers/watcher/controller.go

Co-authored-by: Joao Marcal <joao.marcal12@gmail.com>

* Update main.go

Co-authored-by: Joao Marcal <joao.marcal12@gmail.com>

* Update main.go

Co-authored-by: Joao Marcal <joao.marcal12@gmail.com>

* Add suggestion

Signed-off-by: Israel Blancas <iblancasa@gmail.com>

---------

Signed-off-by: Israel Blancas <iblancasa@gmail.com>
Co-authored-by: Joao Marcal <joao.marcal12@gmail.com>
Signed-off-by: Israel Blancas <iblancasa@gmail.com>
@iblancasa
Copy link
Contributor

What is missing to move from draft to Ready for review?

Copy link
Collaborator Author

@JoaoBraveCoding JoaoBraveCoding left a comment

Choose a reason for hiding this comment

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

@iblancasa some points to improve

client.Client
Log logr.Logger
Scheme *runtime.Scheme
addonnManager *addonmanager.AddonManager
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Can we make this a reference? It will make the trigger code cleaner.

Suggested change
addonnManager *addonmanager.AddonManager
addonnManager addonmanager.AddonManager

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Any reason why we didn't move this to a reference? This way we can do r.addonnManager.Trigger(req.Namespace, req.Name) instead of *(r.addonnManager).Trigger(req.Namespace, req.Name)

Comment on lines 147 to 198
func (r *WatcherReconciler) enqueueForClusterWideResource() handler.EventHandler {
return handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request {
addonList := &addonapiv1alpha1.ManagedClusterAddOnList{}
if err := r.Client.List(ctx, addonList, &client.ListOptions{
LabelSelector: labels.SelectorFromSet(labels.Set{
"open-cluster-management.io/addon-name": "multicluster-observability-addon",
}),
}); err != nil {
r.Log.Error(err, "Error listing managedclusteraddon resources in event handler")
return nil
}

if len(addonList.Items) == 0 {
r.Log.V(2).Info("no managedclusteraddon found")
return nil
}

clustersetValue, clustersetExists := obj.GetAnnotations()["cluster.open-cluster-management.io/clusterset"]
var clustersInClusterSet map[string]struct{}
if clustersetExists {
clusterList := &clusterv1.ManagedClusterList{}
if err := r.Client.List(ctx, clusterList, &client.ListOptions{
LabelSelector: labels.SelectorFromSet(labels.Set{
"cluster.open-cluster-management.io/clusterset": clustersetValue,
}),
}); err != nil {
r.Log.Error(err, "Error listing managedcluster resources in event handler")
return nil
}
clustersInClusterSet = make(map[string]struct{}, len(clusterList.Items))
for _, cluster := range clusterList.Items {
clustersInClusterSet[cluster.Name] = struct{}{}
}
}

var requests []reconcile.Request
for _, addon := range addonList.Items {
_, installed := clustersInClusterSet[addon.Namespace]
if clustersetExists && !installed {
continue
}

requests = append(requests, reconcile.Request{
NamespacedName: types.NamespacedName{
Namespace: addon.Namespace,
Name: addon.Name,
},
})
}
return requests
})
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

In the new design, we can drop this code as it will not be needed

Comment on lines +101 to +106
if req.Name == "" {
return ctrl.Result{}, noNameErr
}
if req.Namespace == "" {
return ctrl.Result{}, noNamespaceErr
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We can remove these no? Our code shouldn't be triggering reconciliations with these, if it is then there's a bug somewhere

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

When I tested I tested without these and saw no extra reconciliations, any reason why we left them? Not sure how it works with the new enqueue function, but again, if we are reconciling things that we don't want then I would say there is a bug in the enqueue function.

}()
}

// WatcherReconciler reconciles the ManagedClusterAddon to annotate the ManiestWorks resource
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Comment needs to be updated

func (r *WatcherReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&addonapiv1alpha1.ManagedClusterAddOn{}, noReconcilePred).
Watches(&corev1.ConfigMap{}, r.enqueueForClusterSpecificResource(), builder.OnlyMetadata).
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

In the new design, we should be able to drop ConfigMaps.

Complete(r)
}

func (r *WatcherReconciler) enqueueForClusterSpecificResource() handler.EventHandler {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

In the new design, this enqueue function needs to be updated so that if secret gets updated:

  • If the namespace has a MCOA ManagedClusterAddOn then it should trigger an update for that
  • Otherwise, list all MCOA ManifestWorks and check if the secret is referenced in the resources, if it is, trigger a reconciliation for the MCOA ManagedClusterAddOn in the same namespace of the ManifestWorks (I'm also open to ideas/suggestion here on how we can do this better)

@JoaoBraveCoding
Copy link
Collaborator Author

FYI: Tested the current version of this PR with some of my suggestions together with #48 and everything worked out 👌

* If a secret is updated, check if there is any reference to it in any
  of the ManifestWorks
* Change some comments

Signed-off-by: Israel Blancas <iblancasa@gmail.com>
@iblancasa
Copy link
Contributor

@JoaoBraveCoding I added the changes yesterday. I tested the changes and I think everything is working fine. Is ok if we move to Ready for review?

@periklis
Copy link
Collaborator

@iblancasa yes please move to ready for review. I am constantly skim over this and would like to add my review. Thanks for all the dedication and work you both put in here

@JoaoBraveCoding JoaoBraveCoding marked this pull request as ready for review May 23, 2024 10:11
@JoaoBraveCoding JoaoBraveCoding requested review from a team as code owners May 23, 2024 10:11
Comment on lines +101 to +106
if req.Name == "" {
return ctrl.Result{}, noNameErr
}
if req.Namespace == "" {
return ctrl.Result{}, noNamespaceErr
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

When I tested I tested without these and saw no extra reconciliations, any reason why we left them? Not sure how it works with the new enqueue function, but again, if we are reconciling things that we don't want then I would say there is a bug in the enqueue function.

client.Client
Log logr.Logger
Scheme *runtime.Scheme
addonnManager *addonmanager.AddonManager
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Any reason why we didn't move this to a reference? This way we can do r.addonnManager.Trigger(req.Namespace, req.Name) instead of *(r.addonnManager).Trigger(req.Namespace, req.Name)

Comment on lines 119 to 120
Watches(&loggingv1.ClusterLogForwarder{}, r.enqueueForClusterSpecificResource(), builder.OnlyMetadata).
Watches(&otelv1alpha1.OpenTelemetryCollector{}, r.enqueueForClusterSpecificResource(), builder.OnlyMetadata).
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Both these are not necessary, since they will be referenced on the ManagedClusterAddon Status if any changes happen to these resources it will automatically trigger a reconciliation

Comment on lines 130 to 134
switch obj.(type) {
case *corev1.Secret:
return r.getSecretReconcileRequests(ctx, obj, addon)
}
return nil
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Since the watcher (for now) will only watch secrets we don't need to have this and we can call directly return r.getSecretReconcileRequests(ctx, obj, addon)

func (r *WatcherReconciler) getSecretReconcileRequests(ctx context.Context, obj client.Object, addon *addonapiv1alpha1.ManagedClusterAddOn) []reconcile.Request {
rqs := []reconcile.Request{}
mws := &workapiv1.ManifestWorkList{}
if err := r.Client.List(ctx, mws); err != nil {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Here we should list only the ManifestWork that belong to MCOA we can do so in the following way:

Suggested change
if err := r.Client.List(ctx, mws); err != nil {
if err := r.Client.List(ctx, mws, &client.ListOptions{
LabelSelector: labels.SelectorFromSet(labels.Set{
"open-cluster-management.io/addon-name": "multicluster-observability-addon",
}),
}); err != nil {

reconcile.Request{
NamespacedName: types.NamespacedName{
Name: addon.Name,
Namespace: mw.Namespace,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We can move this to a contant since this will aways be the same

Signed-off-by: Israel Blancas <iblancasa@gmail.com>
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.

None yet

4 participants