-
Notifications
You must be signed in to change notification settings - Fork 399
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: support notification template #1775
base: master
Are you sure you want to change the base?
Conversation
Sure, I'll do that. |
f604c8d
to
0956145
Compare
Wow!!! This is awesome @chenlujjj! We really need this and I was actually thinking about opening an issue to ask if I can contribute it myself. Awesome thanks! |
Any ETA for this nice feature to be released? Many thanks! |
Hi @CarlosLanderas ,I'm waiting for #1770 to be merged, so that I can rewrite this PR on top of it. |
Perfect @chenlujjj , thanks! |
@chenlujjj we just merged #1770 so if you have the time to rebase ontop of that, that'd be great! |
0956145
to
d81aeae
Compare
d81aeae
to
af84b6b
Compare
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.
Hi @chenlujjj looks good overall.
I spotted a few places in the Reconcile function where you're doing more than necessary.
Some of the code can be deleted or replaced with a couple of helper functions.
The other comments are mostly minor changes!
I wrote these diffs in the Github UI, there is likely an error in one or more of them
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.
c22bb96
to
87b78e6
Compare
Thank you @Baarsgaard , I've updated the code based on your review suggestions and implementation of grafana folder controller. |
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.
Significantly less comments this time 😄 good work!
4d31b7c
to
e42ad78
Compare
@Baarsgaard Thanks for your patient review. I resolved all the comments. I've got one question: in the following code if err != nil || len(instances) == 0 {
setNoMatchingInstancesCondition(¬ificationTemplate.Status.Conditions, notificationTemplate.Generation, err)
meta.RemoveStatusCondition(¬ificationTemplate.Status.Conditions, conditionNotificationTemplateSynchronized)
notificationTemplate.Status.NoMatchingInstances = true
controllerLog.Error(err, "could not find matching instances", "name", notificationTemplate.Name, "namespace", notificationTemplate.Namespace)
return ctrl.Result{RequeueAfter: RequeueDelay}, err
} does it matter to |
@Baarsgaard Could you please take another review, thank you. |
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.
Hi @chenlujjj sorry for the delay, here's another couple of comments 😅
Additionally, I'm very sorry for the PRs that I open that end up blocking yours 🙇♂️
be3b5ac
to
6b001c4
Compare
@chenlujjj Both #1801 and #1804 were merged, you can now continue, and I will not be opening any more PRs that interfere with this! |
415e156
to
776792e
Compare
chore: pass linter
776792e
to
d2b665a
Compare
Thank you @Baarsgaard . |
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.
Sorry for delays in reviews, during the holiday season many of maintainers are absent.
Overall, the code looks good to me, though we still need to make a few adjustments. Aside from the comments I've added, we also need to:
- add an e2e-test for the resource;
- add an example (check
examples
folder).
if err != nil { | ||
return ctrl.Result{}, fmt.Errorf("could not find matching instances: %w", err) | ||
} else { | ||
return ctrl.Result{}, fmt.Errorf("could not find matching instances") |
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 we should not return an error here. - Having zero matching instances is a valid case, e.g. due to timing (the notification template gets reconciled earlier than Grafana), Grafana CR will be added later, etc. - In such scenario, we only need to update condition, but should not return errors in my opinion.
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 took a deeper look at GetScopedMatchingInstances
and the error is only defined when the client returns an error on listing grafana instances.
What do you think of:
if err != nil {
return ctrl.Result{}, fmt.Errorf("could not find matching instances: %w", err)
} else {
r.Log.Info("could not find matching instances")
return ctrl.Result{Requeue: false}, nil
}
This way the log is still clear on what is happening and actual errors are logged.
Alternatively, we can change the function signature of GetScopedMatchingInstances
to never return an error and only return empty arrays?
Then handle all the logging of errors within GetScopedMatchingInstances
?
instances := GetScopedMatchingInstances(controllerLog, ctx, r.Client, notificationTemplate)
if len(instances) == 0 {
setNoMatchingInstancesCondition(¬ificationTemplate.Status.Conditions, notificationTemplate.Generation, err)
meta.RemoveStatusCondition(¬ificationTemplate.Status.Conditions, conditionNotificationTemplateSynchronized)
r.Log.Info("could not find matching instances")
return ctrl.Result{Requeue: false}, nil
}
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.
In my view:
- We should not silence errors. If the client hits an error, the operator should return the error and make another reconciliation attempt;
- We should not handle error- and zero length cases in one if-block, - even in an abstract case, I would put it as a code-style issue;
- Usage of
if err != nil {} ... else
is not encouraged in Go either. - Normally, you would have something likeif err != nil { return err }
and then, on a separate line, the next independent block.
I think notification policy controller offers a more or less optimal example:
instances, err := GetMatchingInstances(ctx, r.Client, notificationPolicy.Spec.InstanceSelector)
if err != nil {
setNoMatchingInstance(¬ificationPolicy.Status.Conditions, notificationPolicy.Generation, "ErrFetchingInstances", fmt.Sprintf("error occurred during fetching of instances: %s", err.Error()))
meta.RemoveStatusCondition(¬ificationPolicy.Status.Conditions, conditionNotificationPolicySynchronized)
r.Log.Error(err, "could not find matching instances")
return ctrl.Result{RequeueAfter: RequeueDelay}, err
}
if len(instances.Items) == 0 {
meta.RemoveStatusCondition(¬ificationPolicy.Status.Conditions, conditionNotificationPolicySynchronized)
setNoMatchingInstance(¬ificationPolicy.Status.Conditions, notificationPolicy.Generation, "EmptyAPIReply", "Instances could not be fetched, reconciliation will be retried")
return ctrl.Result{}, nil
}
Though, the last log line can be improved (we can do that later, in batch).
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 idiomatic go code would then, in this case, be?:
instances, err := GetScopedMatchingInstances(controllerLog, ctx, r.Client, notificationTemplate)
if err != nil {
setNoMatchingInstancesCondition(¬ificationTemplate.Status.Conditions, notificationTemplate.Generation, err)
meta.RemoveStatusCondition(¬ificationTemplate.Status.Conditions, conditionNotificationTemplateSynchronized)
return ctrl.Result{}, fmt.Errorf("could not find matching instances: %w", err)
}
if len(instances) == 0 {
setNoMatchingInstancesCondition(¬ificationTemplate.Status.Conditions, notificationTemplate.Generation, err)
meta.RemoveStatusCondition(¬ificationTemplate.Status.Conditions, conditionNotificationTemplateSynchronized)
return ctrl.Result{RequeueAfter: RequeueDelay}, nil
}
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.
Yeah. As you can see, it's much cleaner and easier to follow :) I would only add a new line before if len(instances) == 0
for better readability.
_, err = r.getNotificationTemplateByName(ctx, instance, notificationTemplate) | ||
if err != nil { | ||
return fmt.Errorf("getting notification template by name: %w", err) | ||
} |
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.
_, err = r.getNotificationTemplateByName(ctx, instance, notificationTemplate) | |
if err != nil { | |
return fmt.Errorf("getting notification template by name: %w", err) | |
} |
If a template is absent, it should not be considered an error, otherwise we'll have a never-ending reconciliation. Grafana API returns 204 (No Content) when someone attempts to remove non-existing template, it's treated as success by the Grafana API client we're using.
related issue: #1736