-
Notifications
You must be signed in to change notification settings - Fork 447
feat: Support for correlations on datasources #2415
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
base: master
Are you sure you want to change the base?
feat: Support for correlations on datasources #2415
Conversation
Add support for datasource correlations as requested in issue grafana#2201. This allows users to configure datasource correlations as code using the operator. Changes: - Add GrafanaDatasourceCorrelation, GrafanaDatasourceCorrelationConfig, and GrafanaDatasourceCorrelationTransformation types - Add Correlations field to GrafanaDatasourceSpec - Update datasource controller to sync correlations with Grafana API - Correlations are created, updated, and deleted via the Grafana datasources correlations API endpoints The implementation follows the existing patterns used by other resources in the operator (similar to AlertRuleGroups pattern). Closes grafana#2201 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]> Signed-off-by: majiayu000 <[email protected]>
weisdd
left a comment
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 the PR.
As with any other PR, we'd like to see tests covering the new functionality (e.g. adding, modifying, removing correlations, data conversions, etc), otherwise it'd be hard to conclude that any of those changes work as intended (manual testing is something we'd like to avoid).
For interactions with Grafana, externalGrafanaCr from controllers/suite_test.go can be re-used.
As a side note, LLMs tend to add comments everywhere, even to the blocks of code that are self-explanatory. It's better to remove those comments in places where they don't tell anything new (by new I mean, e.g., why something is implemented in a certain way). Example of a useless comment from this PR:
// Get existing correlations from Grafana
existingCorrelations, err := gClient.Datasources.GetCorrelationsBySourceUID(sourceUID)|
Thanks for your reminder. Will try now! |
Allow updates by avoiding provisioned correlation creation.
| Name: targetName, | ||
| Type: "prometheus", | ||
| Access: "proxy", | ||
| URL: "https://demo.promlabs.com", |
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.
Please, don't introduce any dependencies on external services. If you need to imitate a datasource, you can use httptest.NewServer. We have a helper to sets up a mux with json content (tk8s.GetJSONmux).
|
@weisdd updated correlations: set Type on update requests and switched correlation tests to use a local httptest datasource URL (no external services). No tests run. |
theSuess
left a comment
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.
It works as expected but I found some code smells I'd like to see fixed before we can merge this.
I'll defer to @weisdd or @Baarsgaard for reviewing the tests as I haven't had the time to get familiar with the recent changes to our test layout
| } | ||
|
|
||
| existingByKey := make(map[string]*models.Correlation) | ||
| if existingCorrelations != 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.
This check is not needed. We can rely upon this being non-nil if the err is nil
controllers/datasource_controller.go
Outdated
| if len(cr.Spec.Correlations) == 0 { | ||
| return r.deleteAllCorrelations(ctx, gClient, sourceUID) | ||
| } |
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.
Since this isn't a bulk API, the performance gains over the regular code path are minimal, so IMHO we can get rid of this
controllers/datasource_controller.go
Outdated
| key := correlationKey(desired.TargetUID, desired.Label) | ||
| if existing, found := existingByKey[key]; found { | ||
| if err := r.updateCorrelationByUID(gClient, sourceUID, existing.UID, desired); err != nil { | ||
| return fmt.Errorf("updating correlation (targetUID=%s, label=%s): %w", desired.TargetUID, desired.Label, 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.
Errors should be static in case we want to match on them at some point. Extra information like the UID/Label should go in a log entry if needed
controllers/datasource_controller.go
Outdated
| } | ||
| } else { | ||
| if err := r.createCorrelation(gClient, sourceUID, desired); err != nil { | ||
| return fmt.Errorf("creating correlation (targetUID=%s, label=%s): %w", desired.TargetUID, desired.Label, 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.
Errors should be static in case we want to match on them at some point. Extra information like the UID/Label should go in a log entry if needed
controllers/datasource_controller.go
Outdated
| Type: models.CorrelationType(config.Type), | ||
| } | ||
|
|
||
| if config.Target != 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.
No need for this to be conditional as the convertJSONToInterface can handle nil
controllers/datasource_controller.go
Outdated
| result.Target = convertJSONToInterface(config.Target) | ||
| } | ||
|
|
||
| if len(config.Transformations) > 0 { |
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.
Again, no need for this to be conditional as an empty loop is skipped
controllers/datasource_controller.go
Outdated
| Field: config.Field, | ||
| } | ||
|
|
||
| if config.Target != 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.
No need for this to be conditional as the convertJSONToInterface can handle nil
controllers/datasource_controller.go
Outdated
| result.Target = convertJSONToInterface(config.Target) | ||
| } | ||
|
|
||
| if len(config.Transformations) > 0 { |
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.
Again, no need for this to be conditional as an empty loop is skipped
|
Thanks for the review @theSuess! I've addressed your feedback:
One note: I retained the |
Fixes #2201
Summary
Adds support for configuring datasource correlations as code using the operator.
Changes
correlationsfield toGrafanaDatasourceSpecGrafanaDatasourceCorrelation,GrafanaDatasourceCorrelationConfig, andGrafanaDatasourceCorrelationTransformationtypesExample Usage
🤖 Generated with Claude Code