From e52118c7d1eeecccd93e8b452dc6eaefe922b51c Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Tue, 20 Feb 2024 22:24:20 +0200 Subject: [PATCH 001/138] [v10.4.x] Logs Panel: Add option extra UI functionality for log context (#83129) Logs Panel: Add option extra UI functionality for log context (#83123) * use ref rather than state * add `getLogRowContextUi` to panel (cherry picked from commit f2c0309d714361816466fe6d1161a9cd1fe9f352) Co-authored-by: Sven Grossmann --- public/app/plugins/panel/logs/LogsPanel.tsx | 44 +++++++++++++++++---- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/public/app/plugins/panel/logs/LogsPanel.tsx b/public/app/plugins/panel/logs/LogsPanel.tsx index ea889ece7298..8069088e533c 100644 --- a/public/app/plugins/panel/logs/LogsPanel.tsx +++ b/public/app/plugins/panel/logs/LogsPanel.tsx @@ -9,6 +9,7 @@ import { Field, GrafanaTheme2, hasLogsContextSupport, + hasLogsContextUiSupport, Labels, LogRowContextOptions, LogRowModel, @@ -60,10 +61,10 @@ export const LogsPanel = ({ const [scrollTop, setScrollTop] = useState(0); const logsContainerRef = useRef(null); const [contextRow, setContextRow] = useState(null); - const [closeCallback, setCloseCallback] = useState<(() => void) | null>(null); const timeRange = data.timeRange; const dataSourcesMap = useDatasourcesFromTargets(data.request?.targets); const [scrollElement, setScrollElement] = useState(null); + let closeCallback = useRef<() => void>(); const { eventBus } = usePanelContext(); const onLogRowHover = useCallback( @@ -85,15 +86,18 @@ export const LogsPanel = ({ const onCloseContext = useCallback(() => { setContextRow(null); - if (closeCallback) { - closeCallback(); + if (closeCallback.current) { + closeCallback.current(); } }, [closeCallback]); - const onOpenContext = useCallback((row: LogRowModel, onClose: () => void) => { - setContextRow(row); - setCloseCallback(onClose); - }, []); + const onOpenContext = useCallback( + (row: LogRowModel, onClose: () => void) => { + setContextRow(row); + closeCallback.current = onClose; + }, + [closeCallback] + ); const onPermalinkClick = useCallback( async (row: LogRowModel) => { @@ -150,6 +154,31 @@ export const LogsPanel = ({ [data.request?.targets, dataSourcesMap] ); + const getLogRowContextUi = useCallback( + (origRow: LogRowModel, runContextQuery?: () => void): React.ReactNode => { + if (!origRow.dataFrame.refId || !dataSourcesMap) { + return <>; + } + + const query = data.request?.targets[0]; + if (!query) { + return <>; + } + + const dataSource = dataSourcesMap.get(origRow.dataFrame.refId); + if (!hasLogsContextUiSupport(dataSource)) { + return <>; + } + + if (!dataSource.getLogRowContextUi) { + return <>; + } + + return dataSource.getLogRowContextUi(origRow, runContextQuery, query); + }, + [data.request?.targets, dataSourcesMap] + ); + // Important to memoize stuff here, as panel rerenders a lot for example when resizing. const [logRows, deduplicatedRows, commonLabels] = useMemo(() => { const logs = data @@ -210,6 +239,7 @@ export const LogsPanel = ({ getRowContext={(row, options) => getLogRowContext(row, contextRow, options)} logsSortOrder={sortOrder} timeZone={timeZone} + getLogRowContextUi={getLogRowContextUi} /> )} Date: Wed, 21 Feb 2024 13:25:06 +0200 Subject: [PATCH 002/138] [v10.4.x] Alerting docs: adds simplified alert routing (#83159) Alerting docs: adds simplified alert routing (#82158) * Alerting docs: adds simplified alert routing * adds to preview section * adds numbering * adds indent * deletes fullstop * ran prettier * adds feature toggle notes * fixes spelling error (cherry picked from commit d091e4c264fa66dd8387628ff3f09c9d89c334cf) Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> --- .../create-grafana-managed-rule.md | 61 +++++++++++++++++-- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/docs/sources/alerting/alerting-rules/create-grafana-managed-rule.md b/docs/sources/alerting/alerting-rules/create-grafana-managed-rule.md index 4f691345da3b..ae03719e210c 100644 --- a/docs/sources/alerting/alerting-rules/create-grafana-managed-rule.md +++ b/docs/sources/alerting/alerting-rules/create-grafana-managed-rule.md @@ -123,11 +123,15 @@ To do this, you need to make sure that your alert rule is in the right evaluatio ## Configure notifications -Add labels to your alert rules to set which notification policy should handle your firing alert instances. +{{< admonition type="note" >}} +To try out a simplified version of routing your alerts, enable the alertingSimplifiedRouting feature toggle and refer to the following section Configure notifications (simplified). +{{< /admonition >}} -All alert rules and instances, irrespective of their labels, match the default notification policy. If there are no nested policies, or no nested policies match the labels in the alert rule or alert instance, then the default notification policy is the matching policy. +1. Add labels to your alert rules to set which notification policy should handle your firing alert instances. -1. Add labels if you want to change the way your notifications are routed. + All alert rules and instances, irrespective of their labels, match the default notification policy. If there are no nested policies, or no nested policies match the labels in the alert rule or alert instance, then the default notification policy is the matching policy. + + Add labels if you want to change the way your notifications are routed. Add custom labels by selecting existing key-value pairs from the drop down, or add new labels by entering the new key or value. @@ -137,7 +141,56 @@ All alert rules and instances, irrespective of their labels, match the default n Expand each notification policy below to view more details. -1. Click **See details** to view alert routing details and an email preview. +1. Click See details to view alert routing details and an email preview. + +1. Click **Save rule**. + +## Configure notifications (simplified) + +{{< admonition type="note" >}} +To try this out, enable the alertingSimplifiedRouting feature toggle. + +This feature is currently not available for Grafana Cloud. +{{< /admonition >}} + +In the **Labels** section, you can optionally choose whether to add labels to organize your alert rules, make searching easier, as well as set which notification policy should handle your firing alert instance. + +In the **Configure notifications** section, you can choose to select a contact point directly from the alert rule form or choose to use notification policy routing as well as set up mute timings and groupings. + +Complete the following steps to set up labels and notifications. + +1. Add labels, if required. + + Add custom labels by selecting existing key-value pairs from the drop down, or add new labels by entering the new key or value. + +2. Configure who receives a notification when an alert rule fires by either choosing **Select contact point** or **Use notification policy**. + + **Select contact point** + + 1. Choose this option to select an existing contact point. + + All notifications for this alert rule are sent to this contact point automatically and notification policies are not used. + + 2. You can also optionally select a mute timing as well as groupings and timings to define when not to send notifications. + + {{% admonition type="note" %}} + An auto-generated notification policy is generated. Only admins can view these auto-generated policies from the **Notification policies** list view. Any changes have to be made in the alert rules form. {{% /admonition %}} + + **Use notification policy** + + 3. Choose this option to use the notification policy tree to direct your notifications. + + {{% admonition type="note" %}} + All alert rules and instances, irrespective of their labels, match the default notification policy. If there are no nested policies, or no nested policies match the labels in the alert rule or alert instance, then the default notification policy is the matching policy. + {{% /admonition %}} + + 4. Preview your alert instance routing set up. + + Based on the labels added, alert instances are routed to the following notification policies displayed. + + 5. Expand each notification policy below to view more details. + + 6. Click **See details** to view alert routing details and an email preview. ## Add annotations From f6ab4e1323340f1b6ed887d10159654695374f70 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 21 Feb 2024 14:10:24 +0200 Subject: [PATCH 003/138] [v10.4.x] Alerting docs: Fix migrating alert links (#83165) Alerting docs: Fix migrating alert links (#83141) * Alerting docs: fixes migrating links * Fixes underscores and stars * Corrects numbering * ran prettier * Fix links Signed-off-by: Jack Baldry * Update docs/sources/alerting/set-up/migrating-alerts/_index.md Co-authored-by: Jack Baldry --------- Signed-off-by: Jack Baldry Co-authored-by: Jack Baldry (cherry picked from commit 4720c99bd513d9ba2dde350654bf6be5aa1c9839) Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> --- .../set-up/migrating-alerts/_index.md | 20 +++++++++++----- .../export-alerting-resources/index.md | 24 +++++++++++-------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/docs/sources/alerting/set-up/migrating-alerts/_index.md b/docs/sources/alerting/set-up/migrating-alerts/_index.md index 55a5568cbee5..abb489c723f3 100644 --- a/docs/sources/alerting/set-up/migrating-alerts/_index.md +++ b/docs/sources/alerting/set-up/migrating-alerts/_index.md @@ -72,17 +72,17 @@ Alerts generated by the new alerting system are visible in the **Alerting** sect 1. **Preview the Upgrade**: - **Initiate the process**: Access the upgrade functionality within Grafana by visiting the **Alerting upgrade** page in the **Alerting (legacy)** section of the navigation panel. From this page you can upgrade your existing alert rules and notification channels to the new Grafana Alerting system. - **Review the summary table:** Review the detailed table outlining how your existing alert rules and notification channels were upgraded to resources in the new Grafana Alerting system. -2. **Investigate and Resolve Errors**: +1. **Investigate and Resolve Errors**: - **Identify errors**: Carefully examine the previewed upgrade: - Any alert rules or notification channels that couldn't be automatically upgraded will be highlighted with error indicators. - New or removed alert rules and notification channels will be highlighted with warning indicators. - **Address errors**: You have two options to resolve these issues: - **Fix legacy issues**: If possible, address the problems within your legacy alerting setup and attempt to upgrade the specific resource again. - **Create new resources**: If fixing legacy issues isn't viable, create new alert rules, notification policies, or contact points manually within the new Grafana Alerting system to replace the problematic ones. -3. **Update As-Code Setup** (Optional): +1. **Update As-Code Setup** (Optional): - **Export upgraded resources**: If you use provisioning methods to manage alert rules and notification channels, you can export the upgraded versions to generate provisioning files compatible with Grafana Alerting. - **Test new provisioning definitions**: Ensure your as-code setup aligns with the new system before completing the upgrade process. Both legacy and Grafana Alerting alerts can be provisioned simultaneously to facilitate a smooth transition. -4. **Finalize the Upgrade**: +1. **Finalize the Upgrade**: - **Contact your Grafana server administrator**: Once you're confident in the state of your previewed upgrade, request to [enable Grafana Alerting]({{< relref "#enable-grafana-alerting" >}}). - **Continued use for upgraded organizations**: Organizations that have already completed the preview upgrade will seamlessly continue using their configured setup. - **Automatic upgrade for others**: Organizations that haven't initiated the upgrade with preview process will undergo the traditional automatic upgrade during this restart. @@ -117,7 +117,7 @@ Any errors encountered during the upgrade process will fail the upgrade and prev 1. **Upgrade to Grafana Alerting**: - **Enable Grafana Alerting**: [Modify custom configuration file]({{< relref "#enable-grafana-alerting" >}}). - **Restart Grafana**: Restart Grafana for the configuration changes to take effect. Grafana will automatically upgrade your existing alert rules and notification channels to the new Grafana Alerting system. -2. **Review and Adjust Upgraded Alerts**: +1. **Review and Adjust Upgraded Alerts**: - **Review the upgraded alerts**: Go to the `Alerting` section of the navigation panel to review the upgraded alerts. - **Export upgraded resources**: If you use provisioning methods to manage alert rules and notification channels, you can export the upgraded versions to generate provisioning files compatible with Grafana Alerting. @@ -180,8 +180,8 @@ There are some differences between Grafana Alerting and legacy dashboard alerts, 1. `NoData` and `Error` settings are upgraded as is to the corresponding settings in Grafana Alerting, except in two situations: - - As there is no `Keep Last State` option in Grafana Alerting, this option becomes either [`NoData` or `Error`](/docs/sources/alerting/alerting-rules/create-grafana-managed-rule/#configure-no-data-and-error-handling). If using the `Simple Upgrade Method` Grafana automatically creates a 1 year silence for each alert rule with this configuration. If the alert evaluation returns no data or fails (error or timeout), then it creates a [special alert](/docs/sources/alerting/fundamentals/alert-rules/state-and-health/#special-alerts-for-nodata-and-error), which will be silenced by the silence created during the upgrade. - - Due to lack of validation, legacy alert rules imported via JSON or provisioned along with dashboards can contain arbitrary values for [`NoData` or `Error`](/docs/sources/alerting/alerting-rules/create-grafana-managed-rule/#configure-no-data-and-error-handling). In this situation, Grafana will use the default setting: `NoData` for No data, and `Error` for Error. + - As there is no `Keep Last State` option in Grafana Alerting, this option becomes either [`NoData` or `Error`][alerting_config_error_handling]. If using the `Simple Upgrade Method` Grafana automatically creates a 1 year silence for each alert rule with this configuration. If the alert evaluation returns no data or fails (error or timeout), then it creates a [special alert][special_alert], which will be silenced by the silence created during the upgrade. + - Due to lack of validation, legacy alert rules imported via JSON or provisioned along with dashboards can contain arbitrary values for [`NoData` or `Error`][alerting_config_error_handling]. In this situation, Grafana will use the default setting: `NoData` for No data, and `Error` for Error. 1. Notification channels are upgraded to an Alertmanager configuration with the appropriate routes and receivers. @@ -194,3 +194,11 @@ There are some differences between Grafana Alerting and legacy dashboard alerts, **Limitations** 1. Since `Hipchat` and `Sensu` notification channels are no longer supported, legacy alerts associated with these channels are not automatically upgraded to Grafana Alerting. Assign the legacy alerts to a supported notification channel so that you continue to receive notifications for those alerts. + +{{% docs/reference %}} +[alerting_config_error_handling]: "/docs/grafana/ -> /docs/grafana//alerting/alerting-rules/create-grafana-managed-rule#configure-no-data-and-error-handling" +[alerting_config_error_handling]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/alerting-rules/create-grafana-managed-rule#configure-no-data-and-error-handling" + +[special_alert]: "/docs/grafana/ -> /docs/grafana//alerting/fundamentals/alert-rules/state-and-health#special-alerts-for-nodata-and-error" +[special_alert]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/fundamentals/alert-rules/state-and-health#special-alerts-for-nodata-and-error" +{{% /docs/reference %}} diff --git a/docs/sources/alerting/set-up/provision-alerting-resources/export-alerting-resources/index.md b/docs/sources/alerting/set-up/provision-alerting-resources/export-alerting-resources/index.md index d01f54a9fc7a..82c82706ad7d 100644 --- a/docs/sources/alerting/set-up/provision-alerting-resources/export-alerting-resources/index.md +++ b/docs/sources/alerting/set-up/provision-alerting-resources/export-alerting-resources/index.md @@ -82,6 +82,8 @@ Note that most Alerting endpoints return a JSON format that is not compatible fo These endpoints accept a `download` parameter to download a file containing the exported resources. + + {{% docs/reference %}} [alerting_tf_provisioning]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/terraform-provisioning" [alerting_tf_provisioning]: "/docs/grafana-cloud/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/terraform-provisioning" @@ -89,18 +91,20 @@ These endpoints accept a `download` parameter to download a file containing the [alerting_http_provisioning]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning" [alerting_http_provisioning]: "/docs/grafana-cloud/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning" -[export_rule]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-alert-rule-exportspan-export-an-alert-rule-in-provisioning-file-format-\_routegetalertruleexport*" -[export_rule]: "/docs/grafana-cloud/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-alert-rule-exportspan-export-an-alert-rule-in-provisioning-file-format-\_routegetalertruleexport*" +[export_rule]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-alert-rule-exportspan-export-an-alert-rule-in-provisioning-file-format-_routegetalertruleexport_" +[export_rule]: "/docs/grafana-cloud/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-alert-rule-exportspan-export-an-alert-rule-in-provisioning-file-format-_routegetalertruleexport_" -[export_rule_group]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-alert-rule-group-exportspan-export-an-alert-rule-group-in-provisioning-file-format-\_routegetalertrulegroupexport*" -[export_rule_group]: "/docs/grafana-cloud/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-alert-rule-group-exportspan-export-an-alert-rule-group-in-provisioning-file-format-\_routegetalertrulegroupexport*" +[export_rule_group]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-alert-rule-group-exportspan-export-an-alert-rule-group-in-provisioning-file-format-_routegetalertrulegroupexport_" +[export_rule_group]: "/docs/grafana-cloud/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-alert-rule-group-exportspan-export-an-alert-rule-group-in-provisioning-file-format-_routegetalertrulegroupexport_" -[export_rules]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-alert-rules-exportspan-export-all-alert-rules-in-provisioning-file-format-\_routegetalertrulesexport*" -[export_rules]: "/docs/grafana-cloud/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-alert-rules-exportspan-export-all-alert-rules-in-provisioning-file-format-\_routegetalertrulesexport*" +[export_rules]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-alert-rules-exportspan-export-all-alert-rules-in-provisioning-file-format-_routegetalertrulesexport_" +[export_rules]: "/docs/grafana-cloud/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-alert-rules-exportspan-export-all-alert-rules-in-provisioning-file-format-_routegetalertrulesexport_" -[export_contacts]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-contactpoints-exportspan-export-all-contact-points-in-provisioning-file-format-\_routegetcontactpointsexport*" -[export_contacts]: "/docs/grafana-cloud/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-contactpoints-exportspan-export-all-contact-points-in-provisioning-file-format-\_routegetcontactpointsexport*" +[export_contacts]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-contactpoints-exportspan-export-all-contact-points-in-provisioning-file-format-_routegetcontactpointsexport_" +[export_contacts]: "/docs/grafana-cloud/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-contactpoints-exportspan-export-all-contact-points-in-provisioning-file-format-_routegetcontactpointsexport_" -[export_notifications]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-policy-tree-exportspan-export-the-notification-policy-tree-in-provisioning-file-format-\_routegetpolicytreeexport*" -[export_notifications]: "/docs/grafana-cloud/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-policy-tree-exportspan-export-the-notification-policy-tree-in-provisioning-file-format-\_routegetpolicytreeexport*" +[export_notifications]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-policy-tree-exportspan-export-the-notification-policy-tree-in-provisioning-file-format-_routegetpolicytreeexport_" +[export_notifications]: "/docs/grafana-cloud/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-policy-tree-exportspan-export-the-notification-policy-tree-in-provisioning-file-format-_routegetpolicytreeexport_" {{% /docs/reference %}} + + From 6e7ba7c593d59f67c67493126c15ce2fda36f032 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 21 Feb 2024 14:12:44 +0200 Subject: [PATCH 004/138] [v10.4.x] Alerting docs: fixes oncall broken links (#83167) Alerting docs: fixes oncall broken links (#83139) (cherry picked from commit 4b2ef3616571445c1bd1cf33fc596a77f03c4c34) Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> --- .../manage-contact-points/integrations/configure-oncall.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sources/alerting/alerting-rules/manage-contact-points/integrations/configure-oncall.md b/docs/sources/alerting/alerting-rules/manage-contact-points/integrations/configure-oncall.md index fba69536708a..f71e5053036e 100644 --- a/docs/sources/alerting/alerting-rules/manage-contact-points/integrations/configure-oncall.md +++ b/docs/sources/alerting/alerting-rules/manage-contact-points/integrations/configure-oncall.md @@ -69,6 +69,6 @@ To set up the Grafana OnCall integration using the Grafana Alerting application, [oncall-integration]: "/docs/grafana/ -> /docs/oncall/latest/integrations/grafana-alerting" [oncall-integration]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/integrations/grafana-alerting" -[escalation-chain]: "/docs/grafana/ -> /docs/oncall/latest/escalation-chains-and-routes" -[escalation-chain]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/escalation-chains-and-routes" +[escalation-chain]: "/docs/grafana/ -> /docs/oncall/latest/configure/escalation-chains-and-routes" +[escalation-chain]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/configure/escalation-chains-and-routes" {{% /docs/reference %}} From 2fbc070fd10db827d520b37b21090bb0e37d7860 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 21 Feb 2024 15:20:17 +0200 Subject: [PATCH 005/138] [v10.4.x] Snapshots: delete from same org (#83170) Snapshots: delete from same org (#83111) delete in org (cherry picked from commit 809c1eaddb7f66260c799b402486a19748c65108) Co-authored-by: Ryan McKinley --- pkg/api/dashboard_snapshot.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pkg/api/dashboard_snapshot.go b/pkg/api/dashboard_snapshot.go index b217d854a5f3..f5fc19de817a 100644 --- a/pkg/api/dashboard_snapshot.go +++ b/pkg/api/dashboard_snapshot.go @@ -192,10 +192,9 @@ func (hs *HTTPServer) DeleteDashboardSnapshot(c *contextmodel.ReqContext) respon return response.Error(http.StatusNotFound, "Failed to get dashboard snapshot", nil) } - // TODO: enforce org ID same - // if queryResult.OrgID != c.OrgID { - // return response.Error(http.StatusUnauthorized, "OrgID mismatch", nil) - // } + if queryResult.OrgID != c.OrgID { + return response.Error(http.StatusUnauthorized, "OrgID mismatch", nil) + } if queryResult.External { err := dashboardsnapshots.DeleteExternalDashboardSnapshot(queryResult.ExternalDeleteURL) From fedf3e2e6e1a86fbb7c231f685faa537f277aed5 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 21 Feb 2024 18:02:06 +0000 Subject: [PATCH 006/138] [v10.4.x] Alerting: Protect possible undefined (#83186) Alerting: Protect possible undefined (#83128) Protect possible undefined (cherry picked from commit 16dee3cf1c540f9cffbc1a01aa275fb15a143300) Co-authored-by: Sonia Aguilar <33540275+soniaAguilarPeiron@users.noreply.github.com> --- public/app/core/components/TimelineChart/TimelineChart.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/core/components/TimelineChart/TimelineChart.tsx b/public/app/core/components/TimelineChart/TimelineChart.tsx index 524296eefba3..9fb1c4ed7480 100644 --- a/public/app/core/components/TimelineChart/TimelineChart.tsx +++ b/public/app/core/components/TimelineChart/TimelineChart.tsx @@ -59,7 +59,7 @@ export class TimelineChart extends React.Component { rowHeight: alignedFrame.fields.length > 2 ? this.props.rowHeight : 1, getValueColor: this.getValueColor, // @ts-ignore - hoverMulti: this.props.tooltip.mode === TooltipDisplayMode.Multi, + hoverMulti: this.props.tooltip?.mode === TooltipDisplayMode.Multi, }); }; From e3d8fca42a45d34e33587841196bf5e64c52b769 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 21 Feb 2024 16:34:05 -0500 Subject: [PATCH 007/138] [v10.4.x] Docs: add information about filtering for annotations (#83194) Docs: add information about filtering for annotations (#82957) * Added information about filtering for annotations * Update generate-transformations.ts (cherry picked from commit f18b9ddac6ec46ed5eee5fda727e99322616123f) Co-authored-by: Isabel <76437239+imatwawana@users.noreply.github.com> --- .../query-transform-data/transform-data/index.md | 4 +++- scripts/docs/generate-transformations.ts | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/sources/panels-visualizations/query-transform-data/transform-data/index.md b/docs/sources/panels-visualizations/query-transform-data/transform-data/index.md index b7afd6ef355f..e23162e27777 100644 --- a/docs/sources/panels-visualizations/query-transform-data/transform-data/index.md +++ b/docs/sources/panels-visualizations/query-transform-data/transform-data/index.md @@ -101,7 +101,9 @@ You can disable or hide one or more transformations by clicking on the eye icon If your panel uses more than one query, you can filter these and apply the selected transformation to only one of the queries. To do this, click the filter icon on the top right of the transformation row. This opens a drop-down with a list of queries used on the panel. From here, you can select the query you want to transform. -Note that the filter icon is always displayed if your panel has more than one query, but it may not work if previous transformations for merging the queries' outputs are applied. This is because one transformation takes the output of the previous one. +You can also filter by annotations (which includes exemplars) to apply transformations to them. When you do so, the list of fields changes to reflect those in the annotation or exemplar tooltip. + +The filter icon is always displayed if your panel has more than one query or source of data (that is, panel or annotation data) but it may not work if previous transformations for merging the queries’ outputs are applied. This is because one transformation takes the output of the previous one. ## Delete a transformation diff --git a/scripts/docs/generate-transformations.ts b/scripts/docs/generate-transformations.ts index 321344c731fc..0e9cabcb02c4 100644 --- a/scripts/docs/generate-transformations.ts +++ b/scripts/docs/generate-transformations.ts @@ -107,7 +107,9 @@ You can disable or hide one or more transformations by clicking on the eye icon If your panel uses more than one query, you can filter these and apply the selected transformation to only one of the queries. To do this, click the filter icon on the top right of the transformation row. This opens a drop-down with a list of queries used on the panel. From here, you can select the query you want to transform. -Note that the filter icon is always displayed if your panel has more than one query, but it may not work if previous transformations for merging the queries' outputs are applied. This is because one transformation takes the output of the previous one. +You can also filter by annotations (which includes exemplars) to apply transformations to them. When you do so, the list of fields changes to reflect those in the annotation or exemplar tooltip. + +The filter icon is always displayed if your panel has more than one query or source of data (that is, panel or annotation data) but it may not work if previous transformations for merging the queries’ outputs are applied. This is because one transformation takes the output of the previous one. ## Delete a transformation From 13e7099cc3f82fa9864ce04a1275eeb2525d9466 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 21 Feb 2024 22:35:14 +0100 Subject: [PATCH 008/138] [v10.4.x] QueryVariableEditor: Select a variable ds does not work (#83181) QueryVariableEditor: Select a variable ds does not work (#83144) (cherry picked from commit 5460d75e74b0f6f477deed177683a2160477a8ba) Co-authored-by: Ivan Ortega Alba --- .../components/QueryVariableForm.test.tsx | 41 +++++---- .../components/QueryVariableForm.tsx | 24 ++++-- .../variables/editors/QueryVariableEditor.tsx | 16 +--- .../query/QueryVariableEditor.test.tsx | 85 ++++++++----------- .../variables/query/QueryVariableEditor.tsx | 6 +- public/test/mocks/datasource_srv.ts | 6 +- 6 files changed, 83 insertions(+), 95 deletions(-) diff --git a/public/app/features/dashboard-scene/settings/variables/components/QueryVariableForm.test.tsx b/public/app/features/dashboard-scene/settings/variables/components/QueryVariableForm.test.tsx index 9590377e41a0..0e154ed447d9 100644 --- a/public/app/features/dashboard-scene/settings/variables/components/QueryVariableForm.test.tsx +++ b/public/app/features/dashboard-scene/settings/variables/components/QueryVariableForm.test.tsx @@ -1,8 +1,7 @@ -import { render, screen, waitFor } from '@testing-library/react'; +import { act, render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React, { FormEvent } from 'react'; import { of } from 'rxjs'; -import { MockDataSourceApi } from 'test/mocks/datasource_srv'; import { LoadingState, @@ -17,6 +16,7 @@ import { setRunRequest } from '@grafana/runtime'; import { VariableRefresh, VariableSort } from '@grafana/schema'; import { mockDataSource } from 'app/features/alerting/unified/mocks'; import { LegacyVariableQueryEditor } from 'app/features/variables/editor/LegacyVariableQueryEditor'; +import { getVariableQueryEditor } from 'app/features/variables/editor/getVariableQueryEditor'; import { QueryVariableEditorForm } from './QueryVariableForm'; @@ -42,7 +42,7 @@ jest.mock('@grafana/runtime/src/services/dataSourceSrv', () => ({ }, }), getList: () => [defaultDatasource, promDatasource], - getInstanceSettings: () => ({ ...defaultDatasource }), + getInstanceSettings: (uid: string) => (uid === promDatasource.uid ? promDatasource : defaultDatasource), }), })); @@ -60,6 +60,11 @@ const runRequestMock = jest.fn().mockReturnValue( setRunRequest(runRequestMock); +jest.mock('app/features/variables/editor/getVariableQueryEditor', () => ({ + ...jest.requireActual('app/features/variables/editor/getVariableQueryEditor'), + getVariableQueryEditor: jest.fn(), +})); + describe('QueryVariableEditorForm', () => { const mockOnDataSourceChange = jest.fn(); const mockOnQueryChange = jest.fn(); @@ -71,14 +76,13 @@ describe('QueryVariableEditorForm', () => { const mockOnIncludeAllChange = jest.fn(); const mockOnAllValueChange = jest.fn(); - const defaultProps = { - datasource: new MockDataSourceApi(promDatasource.name, undefined, promDatasource.meta), + const defaultProps: React.ComponentProps = { + datasource: { uid: defaultDatasource.uid, type: defaultDatasource.type }, onDataSourceChange: mockOnDataSourceChange, query: 'my-query', onQueryChange: mockOnQueryChange, onLegacyQueryChange: mockOnLegacyQueryChange, timeRange: getDefaultTimeRange(), - VariableQueryEditor: LegacyVariableQueryEditor, regex: '.*', onRegExChange: mockOnRegExChange, sort: VariableSort.alphabeticalAsc, @@ -93,9 +97,10 @@ describe('QueryVariableEditorForm', () => { onAllValueChange: mockOnAllValueChange, }; - function setup(props?: React.ComponentProps) { + async function setup(props?: React.ComponentProps) { + jest.mocked(getVariableQueryEditor).mockResolvedValue(LegacyVariableQueryEditor); return { - renderer: render(), + renderer: await act(() => render()), user: userEvent.setup(), }; } @@ -104,10 +109,10 @@ describe('QueryVariableEditorForm', () => { jest.clearAllMocks(); }); - it('should render the component with initializing the components correctly', () => { + it('should render the component with initializing the components correctly', async () => { const { renderer: { getByTestId, getByRole }, - } = setup(); + } = await setup(); const dataSourcePicker = getByTestId(selectors.components.DataSourcePicker.inputV2); //const queryEditor = getByTestId('query-editor'); const regexInput = getByTestId( @@ -149,7 +154,7 @@ describe('QueryVariableEditorForm', () => { it('should call onDataSourceChange when changing the datasource', async () => { const { renderer: { getByTestId }, - } = setup(); + } = await setup(); const dataSourcePicker = getByTestId(selectors.components.DataSourcePicker.inputV2); await userEvent.click(dataSourcePicker); await userEvent.click(screen.getByText(/prometheus/i)); @@ -161,7 +166,7 @@ describe('QueryVariableEditorForm', () => { it('should call onQueryChange when changing the query', async () => { const { renderer: { getByTestId }, - } = setup(); + } = await setup(); const queryEditor = getByTestId( selectors.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsQueryInput ); @@ -178,7 +183,7 @@ describe('QueryVariableEditorForm', () => { it('should call onRegExChange when changing the regex', async () => { const { renderer: { getByTestId }, - } = setup(); + } = await setup(); const regexInput = getByTestId( selectors.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsRegExInputV2 ); @@ -193,7 +198,7 @@ describe('QueryVariableEditorForm', () => { it('should call onSortChange when changing the sort', async () => { const { renderer: { getByTestId }, - } = setup(); + } = await setup(); const sortSelect = getByTestId( selectors.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsSortSelectV2 ); @@ -211,7 +216,7 @@ describe('QueryVariableEditorForm', () => { it('should call onRefreshChange when changing the refresh', async () => { const { renderer: { getByTestId }, - } = setup(); + } = await setup(); const refreshSelect = getByTestId( selectors.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsRefreshSelectV2 ); @@ -226,7 +231,7 @@ describe('QueryVariableEditorForm', () => { it('should call onMultiChange when changing the multi switch', async () => { const { renderer: { getByTestId }, - } = setup(); + } = await setup(); const multiSwitch = getByTestId( selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsMultiSwitch ); @@ -240,7 +245,7 @@ describe('QueryVariableEditorForm', () => { it('should call onIncludeAllChange when changing the include all switch', async () => { const { renderer: { getByTestId }, - } = setup(); + } = await setup(); const includeAllSwitch = getByTestId( selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsIncludeAllSwitch ); @@ -254,7 +259,7 @@ describe('QueryVariableEditorForm', () => { it('should call onAllValueChange when changing the all value', async () => { const { renderer: { getByTestId }, - } = setup(); + } = await setup(); const allValueInput = getByTestId( selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsCustomAllInput ); diff --git a/public/app/features/dashboard-scene/settings/variables/components/QueryVariableForm.tsx b/public/app/features/dashboard-scene/settings/variables/components/QueryVariableForm.tsx index 0e7d86740cc1..a1a9cfbc3f48 100644 --- a/public/app/features/dashboard-scene/settings/variables/components/QueryVariableForm.tsx +++ b/public/app/features/dashboard-scene/settings/variables/components/QueryVariableForm.tsx @@ -1,16 +1,18 @@ import React, { FormEvent } from 'react'; +import { useAsync } from 'react-use'; -import { DataSourceApi, DataSourceInstanceSettings, SelectableValue, TimeRange } from '@grafana/data'; +import { DataSourceInstanceSettings, SelectableValue, TimeRange } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; +import { getDataSourceSrv } from '@grafana/runtime'; import { QueryVariable } from '@grafana/scenes'; -import { VariableRefresh, VariableSort } from '@grafana/schema'; +import { DataSourceRef, VariableRefresh, VariableSort } from '@grafana/schema'; import { Field } from '@grafana/ui'; import { QueryEditor } from 'app/features/dashboard-scene/settings/variables/components/QueryEditor'; import { SelectionOptionsForm } from 'app/features/dashboard-scene/settings/variables/components/SelectionOptionsForm'; import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker'; +import { getVariableQueryEditor } from 'app/features/variables/editor/getVariableQueryEditor'; import { QueryVariableRefreshSelect } from 'app/features/variables/query/QueryVariableRefreshSelect'; import { QueryVariableSortSelect } from 'app/features/variables/query/QueryVariableSortSelect'; -import { VariableQueryEditorType } from 'app/features/variables/types'; import { VariableLegend } from './VariableLegend'; import { VariableTextAreaField } from './VariableTextAreaField'; @@ -18,12 +20,11 @@ import { VariableTextAreaField } from './VariableTextAreaField'; type VariableQueryType = QueryVariable['state']['query']; interface QueryVariableEditorFormProps { - datasource: DataSourceApi | undefined; + datasource?: DataSourceRef; onDataSourceChange: (dsSettings: DataSourceInstanceSettings) => void; query: VariableQueryType; onQueryChange: (query: VariableQueryType) => void; onLegacyQueryChange: (query: VariableQueryType, definition: string) => void; - VariableQueryEditor: VariableQueryEditorType | undefined; timeRange: TimeRange; regex: string | null; onRegExChange: (event: FormEvent) => void; @@ -40,12 +41,11 @@ interface QueryVariableEditorFormProps { } export function QueryVariableEditorForm({ - datasource, + datasource: datasourceRef, onDataSourceChange, query, onQueryChange, onLegacyQueryChange, - VariableQueryEditor, timeRange, regex, onRegExChange, @@ -60,11 +60,19 @@ export function QueryVariableEditorForm({ allValue, onAllValueChange, }: QueryVariableEditorFormProps) { + const { value: dsConfig } = useAsync(async () => { + const datasource = await getDataSourceSrv().get(datasourceRef ?? ''); + const VariableQueryEditor = await getVariableQueryEditor(datasource); + + return { datasource, VariableQueryEditor }; + }, [datasourceRef]); + const { datasource, VariableQueryEditor } = dsConfig ?? {}; + return ( <> Query options - + {datasource && VariableQueryEditor && ( diff --git a/public/app/features/dashboard-scene/settings/variables/editors/QueryVariableEditor.tsx b/public/app/features/dashboard-scene/settings/variables/editors/QueryVariableEditor.tsx index 0c577d74b6b7..259c69bcbd82 100644 --- a/public/app/features/dashboard-scene/settings/variables/editors/QueryVariableEditor.tsx +++ b/public/app/features/dashboard-scene/settings/variables/editors/QueryVariableEditor.tsx @@ -1,11 +1,8 @@ import React, { FormEvent } from 'react'; -import { useAsync } from 'react-use'; import { SelectableValue, DataSourceInstanceSettings } from '@grafana/data'; -import { getDataSourceSrv } from '@grafana/runtime'; import { QueryVariable, sceneGraph } from '@grafana/scenes'; import { DataSourceRef, VariableRefresh, VariableSort } from '@grafana/schema'; -import { getVariableQueryEditor } from 'app/features/variables/editor/getVariableQueryEditor'; import { QueryVariableEditorForm } from '../components/QueryVariableForm'; @@ -16,17 +13,9 @@ interface QueryVariableEditorProps { type VariableQueryType = QueryVariable['state']['query']; export function QueryVariableEditor({ variable, onRunQuery }: QueryVariableEditorProps) { - const { datasource: datasourceRef, regex, sort, refresh, isMulti, includeAll, allValue, query } = variable.useState(); + const { datasource, regex, sort, refresh, isMulti, includeAll, allValue, query } = variable.useState(); const { value: timeRange } = sceneGraph.getTimeRange(variable).useState(); - const { value: dsConfig } = useAsync(async () => { - const datasource = await getDataSourceSrv().get(datasourceRef ?? ''); - const VariableQueryEditor = await getVariableQueryEditor(datasource); - - return { datasource, VariableQueryEditor }; - }, [datasourceRef]); - const { datasource, VariableQueryEditor } = dsConfig ?? {}; - const onRegExChange = (event: React.FormEvent) => { variable.setState({ regex: event.currentTarget.value }); }; @@ -56,12 +45,11 @@ export function QueryVariableEditor({ variable, onRunQuery }: QueryVariableEdito return ( ) => { +const mockDS = mockDataSource({ + name: 'CloudManager', + type: DataSourceType.Alertmanager, +}); +const ds = new MockDataSourceApi(mockDS); +const editor = jest.fn().mockImplementation(LegacyVariableQueryEditor); + +ds.variables = { + getType: () => VariableSupportType.Custom, + query: jest.fn(), + editor: editor, + getDefaultQuery: jest.fn(), +}; + +const setupTestContext = async (options: Partial) => { const variableDefaults: Partial = { rootStateKey: 'key' }; const extended = { VariableQueryEditor: LegacyVariableQueryEditor, - dataSource: {} as unknown as DataSourceApi, + dataSource: ds, }; const defaults: Props = { @@ -33,20 +48,15 @@ const setupTestContext = (options: Partial) => { }; const props: Props & Record = { ...defaults, ...options }; - const { rerender } = render(); + const { rerender } = await act(() => render()); return { rerender, props }; }; -const mockDS = mockDataSource({ - name: 'CloudManager', - type: DataSourceType.Alertmanager, -}); - jest.mock('@grafana/runtime/src/services/dataSourceSrv', () => { return { getDataSourceSrv: () => ({ - get: () => Promise.resolve(mockDS), + get: async () => ds, getList: () => [mockDS], getInstanceSettings: () => mockDS, }), @@ -57,8 +67,8 @@ const defaultIdentifier: KeyedVariableIdentifier = { type: 'query', rootStateKey describe('QueryVariableEditor', () => { describe('when the component is mounted', () => { - it('then it should call initQueryVariableEditor', () => { - const { props } = setupTestContext({}); + it('then it should call initQueryVariableEditor', async () => { + const { props } = await setupTestContext({}); expect(props.initQueryVariableEditor).toHaveBeenCalledTimes(1); expect(props.initQueryVariableEditor).toHaveBeenCalledWith(defaultIdentifier); @@ -66,50 +76,29 @@ describe('QueryVariableEditor', () => { }); describe('when the editor is rendered', () => { - const extendedCustom = { - extended: { - VariableQueryEditor: jest.fn().mockImplementation(LegacyVariableQueryEditor), - dataSource: { - variables: { - getType: () => VariableSupportType.Custom, - query: jest.fn(), - editor: jest.fn(), - }, - } as unknown as DataSourceApi, - }, - }; - it('should pass down the query with default values if the datasource config defines it', () => { - const extended = { ...extendedCustom }; - extended.extended.dataSource.variables!.getDefaultQuery = jest - .fn() - .mockImplementation(() => 'some default query'); - const { props } = setupTestContext(extended); - expect(props.extended?.dataSource?.variables?.getDefaultQuery).toBeDefined(); - expect(props.extended?.dataSource?.variables?.getDefaultQuery).toHaveBeenCalledTimes(1); - expect(props.extended?.VariableQueryEditor).toHaveBeenCalledWith( - expect.objectContaining({ query: 'some default query' }), - expect.anything() - ); + beforeEach(() => { + jest.clearAllMocks(); }); - it('should not pass down a default query if the datasource config doesnt define it', () => { - extendedCustom.extended.dataSource.variables!.getDefaultQuery = undefined; - const { props } = setupTestContext(extendedCustom); - expect(props.extended?.dataSource?.variables?.getDefaultQuery).not.toBeDefined(); - expect(props.extended?.VariableQueryEditor).toHaveBeenCalledWith( - expect.objectContaining({ query: '' }), - expect.anything() - ); + + it('should pass down the query with default values if the datasource config defines it', async () => { + ds.variables!.getDefaultQuery = jest.fn().mockImplementationOnce(() => 'some default query'); + + await setupTestContext({}); + expect(ds.variables?.getDefaultQuery).toBeDefined(); + expect(ds.variables?.getDefaultQuery).toHaveBeenCalledTimes(1); + expect(editor.mock.calls[0][0].query).toBe('some default query'); }); }); + describe('when the user changes', () => { it.each` fieldName | propName | expectedArgs - ${'query'} | ${'changeQueryVariableQuery'} | ${[defaultIdentifier, 't', 't']} + ${'query'} | ${'changeQueryVariableQuery'} | ${[defaultIdentifier, 't', '']} ${'regex'} | ${'onPropChange'} | ${[{ propName: 'regex', propValue: 't', updateOptions: true }]} `( '$fieldName field and tabs away then $propName should be called with correct args', async ({ fieldName, propName, expectedArgs }) => { - const { props } = setupTestContext({}); + const { props } = await setupTestContext({}); const propUnderTest = props[propName]; const fieldAccessor = fieldAccessors[fieldName]; @@ -130,7 +119,7 @@ describe('QueryVariableEditor', () => { `( '$fieldName field but reverts the change and tabs away then $propName should not be called', async ({ fieldName, propName }) => { - const { props } = setupTestContext({}); + const { props } = await setupTestContext({}); const propUnderTest = props[propName]; const fieldAccessor = fieldAccessors[fieldName]; diff --git a/public/app/features/variables/query/QueryVariableEditor.tsx b/public/app/features/variables/query/QueryVariableEditor.tsx index 1f4e0016815c..24ad37c2a641 100644 --- a/public/app/features/variables/query/QueryVariableEditor.tsx +++ b/public/app/features/variables/query/QueryVariableEditor.tsx @@ -125,23 +125,19 @@ export class QueryVariableEditorUnConnected extends PureComponent render() { const { extended, variable } = this.props; - if (!extended || !extended.dataSource || !extended.VariableQueryEditor) { return null; } - const datasource = extended.dataSource; - const VariableQueryEditor = extended.VariableQueryEditor; const timeRange = getTimeSrv().timeRange(); return ( Date: Thu, 22 Feb 2024 12:14:12 +0100 Subject: [PATCH 009/138] [v10.4.x] Alerting: Fix dashboard nav drawers disappearing (#83205) Alerting: Fix dashboard nav drawers disappearing (#82890) Add DashNav modal renderer to handle modals rendered from Toolbar buttons (cherry picked from commit b02183e9ac415c2305875f68597ecea19e4e5a24) Co-authored-by: Konrad Lalik --- .../integration/AlertRulesToolbarButton.tsx | 19 ++++++-------- .../dashboard/components/DashNav/DashNav.tsx | 25 +++++++++++++++++-- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/public/app/features/alerting/unified/integration/AlertRulesToolbarButton.tsx b/public/app/features/alerting/unified/integration/AlertRulesToolbarButton.tsx index a71ce470234b..963ceec182d7 100644 --- a/public/app/features/alerting/unified/integration/AlertRulesToolbarButton.tsx +++ b/public/app/features/alerting/unified/integration/AlertRulesToolbarButton.tsx @@ -1,9 +1,9 @@ import React from 'react'; -import { useToggle } from 'react-use'; import { ToolbarButton } from '@grafana/ui'; import { t } from '../../../../core/internationalization'; +import { useDashNavModalController } from '../../../dashboard/components/DashNav/DashNav'; import { alertRuleApi } from '../api/alertRuleApi'; import { GRAFANA_RULES_SOURCE_NAME } from '../utils/datasource'; @@ -14,7 +14,7 @@ interface AlertRulesToolbarButtonProps { } export default function AlertRulesToolbarButton({ dashboardUid }: AlertRulesToolbarButtonProps) { - const [showDrawer, toggleShowDrawer] = useToggle(false); + const { showModal, hideModal } = useDashNavModalController(); const { data: namespaces = [] } = alertRuleApi.endpoints.prometheusRuleNamespaces.useQuery({ ruleSourceName: GRAFANA_RULES_SOURCE_NAME, @@ -26,14 +26,11 @@ export default function AlertRulesToolbarButton({ dashboardUid }: AlertRulesTool } return ( - <> - - {showDrawer && } - + showModal()} + key="button-alerting" + /> ); } diff --git a/public/app/features/dashboard/components/DashNav/DashNav.tsx b/public/app/features/dashboard/components/DashNav/DashNav.tsx index 57fa6be05593..c2d9fd8e8a2f 100644 --- a/public/app/features/dashboard/components/DashNav/DashNav.tsx +++ b/public/app/features/dashboard/components/DashNav/DashNav.tsx @@ -2,6 +2,7 @@ import { css } from '@emotion/css'; import React, { ReactNode } from 'react'; import { connect, ConnectedProps } from 'react-redux'; import { useLocation } from 'react-router-dom'; +import { createStateContext } from 'react-use'; import { textUtil } from '@grafana/data'; import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src'; @@ -48,6 +49,25 @@ const mapDispatchToProps = { updateTimeZoneForSession, }; +const [useDashNavModelContext, DashNavModalContextProvider] = createStateContext<{ component: React.ReactNode }>({ + component: null, +}); + +export function useDashNavModalController() { + const [_, setContextState] = useDashNavModelContext(); + + return { + showModal: (component: React.ReactNode) => setContextState({ component }), + hideModal: () => setContextState({ component: null }), + }; +} + +function DashNavModalRoot() { + const [contextState] = useDashNavModelContext(); + + return <>{contextState.component}; +} + const connector = connect(null, mapDispatchToProps); const selectors = e2eSelectors.pages.Dashboard.DashNav; @@ -341,11 +361,12 @@ export const DashNav = React.memo((props) => { return ( + {renderLeftActions()} {renderRightActions()} - + + } /> ); From e229eef365d3b947ef618152309ff3b3b0d652a7 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 22 Feb 2024 15:34:26 +0100 Subject: [PATCH 010/138] [v10.4.x] Alerting: Fix saving evaluation group. (#83234) Alerting: Fix saving evaluation group. (#83188) fix saving evaluation group (cherry picked from commit 2a1873f03815f5ea26da31be7e5157a2c3f171a4) Co-authored-by: Sonia Aguilar <33540275+soniaAguilarPeiron@users.noreply.github.com> --- .../rule-editor/GrafanaEvaluationBehavior.tsx | 2 +- .../app/features/alerting/unified/state/actions.ts | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/public/app/features/alerting/unified/components/rule-editor/GrafanaEvaluationBehavior.tsx b/public/app/features/alerting/unified/components/rule-editor/GrafanaEvaluationBehavior.tsx index d0f6672c41ca..22953dbb9204 100644 --- a/public/app/features/alerting/unified/components/rule-editor/GrafanaEvaluationBehavior.tsx +++ b/public/app/features/alerting/unified/components/rule-editor/GrafanaEvaluationBehavior.tsx @@ -18,7 +18,7 @@ import { } from '@grafana/ui'; import { CombinedRuleGroup, CombinedRuleNamespace } from '../../../../../types/unified-alerting'; -import { logInfo, LogMessages } from '../../Analytics'; +import { LogMessages, logInfo } from '../../Analytics'; import { useCombinedRuleNamespaces } from '../../hooks/useCombinedRuleNamespaces'; import { useUnifiedAlertingSelector } from '../../hooks/useUnifiedAlertingSelector'; import { RuleFormValues } from '../../types/rule-form'; diff --git a/public/app/features/alerting/unified/state/actions.ts b/public/app/features/alerting/unified/state/actions.ts index a609c09e06e7..0035acdcecf2 100644 --- a/public/app/features/alerting/unified/state/actions.ts +++ b/public/app/features/alerting/unified/state/actions.ts @@ -65,6 +65,7 @@ import { FetchRulerRulesFilter, setRulerRuleGroup, } from '../api/ruler'; +import { encodeGrafanaNamespace } from '../components/expressions/util'; import { RuleFormType, RuleFormValues } from '../types/rule-form'; import { addDefaultsToAlertmanagerConfig, removeMuteTimingFromRoute } from '../utils/alertmanager'; import { @@ -803,11 +804,14 @@ export const updateLotexNamespaceAndGroupAction: AsyncThunk< } const newNamespaceAlreadyExists = Boolean(rulesResult[newNamespaceName]); - if (newNamespaceName !== namespaceName && newNamespaceAlreadyExists) { + const isGrafanaManagedGroup = rulesSourceName === GRAFANA_RULES_SOURCE_NAME; + const originalNamespace = isGrafanaManagedGroup ? encodeGrafanaNamespace(namespaceName) : namespaceName; + + if (newNamespaceName !== originalNamespace && newNamespaceAlreadyExists) { throw new Error(`Namespace "${newNamespaceName}" already exists.`); } if ( - newNamespaceName === namespaceName && + newNamespaceName === originalNamespace && groupName === newGroupName && groupInterval === existingGroup.interval ) { @@ -829,8 +833,8 @@ export const updateLotexNamespaceAndGroupAction: AsyncThunk< } } // if renaming namespace - make new copies of all groups, then delete old namespace - - if (newNamespaceName !== namespaceName) { + // this is only possible for cloud rules + if (newNamespaceName !== originalNamespace) { for (const group of rulesResult[namespaceName]) { await setRulerRuleGroup( rulerConfig, From fed9e2f361ca3e46faa5ff65ea719dce8c615cc4 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 22 Feb 2024 09:46:47 -0500 Subject: [PATCH 011/138] [v10.4.x] Docs: update import troubleshoot dashboards links (#83245) Docs: update import troubleshoot dashboards links (#83124) * Updated links to former manage dashboards content * Removed links to manage dashboards and added export content to Sharing page * Replaced grafana links with cloud docs links * Removed trailing slash from link * trigger CI --------- Co-authored-by: Jack Baldry (cherry picked from commit 5f41cc632ea404f5b6adf6b60a021fc75182d63c) Co-authored-by: Isabel <76437239+imatwawana@users.noreply.github.com> --- docs/sources/dashboards/_index.md | 34 +++++++++++-------- .../dashboards/create-reports/index.md | 8 ++--- .../share-dashboards-panels/index.md | 24 ++++++++++--- 3 files changed, 42 insertions(+), 24 deletions(-) diff --git a/docs/sources/dashboards/_index.md b/docs/sources/dashboards/_index.md index 297c26cd7a80..0207994cd736 100644 --- a/docs/sources/dashboards/_index.md +++ b/docs/sources/dashboards/_index.md @@ -28,46 +28,50 @@ Before you begin, ensure that you have configured a data source. See also: - [Playlist][] - [Reporting][] - [Version history][] -- [Export and import][] +- [Import][] +- [Export and share][] - [JSON model][] {{% docs/reference %}} [data source]: "/docs/grafana/ -> /docs/grafana//datasources" -[data source]: "/docs/grafana-cloud/ -> /docs/grafana//datasources" +[data source]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/connect-externally-hosted/data-sources" [Reporting]: "/docs/grafana/ -> /docs/grafana//dashboards/create-reports" -[Reporting]: "/docs/grafana-cloud/ -> /docs/grafana//dashboards/create-reports" +[Reporting]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/create-reports" [Public dashboards]: "/docs/grafana/ -> /docs/grafana//dashboards/dashboard-public" -[Public dashboards]: "/docs/grafana-cloud/ -> /docs/grafana//dashboards/dashboard-public" +[Public dashboards]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/dashboard-public" [Version history]: "/docs/grafana/ -> /docs/grafana//dashboards/build-dashboards/manage-version-history" -[Version history]: "/docs/grafana-cloud/ -> /docs/grafana//dashboards/build-dashboards/manage-version-history" +[Version history]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/build-dashboards/manage-version-history" [panels]: "/docs/grafana/ -> /docs/grafana//panels-visualizations" -[panels]: "/docs/grafana-cloud/ -> /docs/grafana//panels-visualizations" +[panels]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations" [Annotations]: "/docs/grafana/ -> /docs/grafana//dashboards/build-dashboards/annotate-visualizations" -[Annotations]: "/docs/grafana-cloud/ -> /docs/grafana//dashboards/build-dashboards/annotate-visualizations" +[Annotations]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/build-dashboards/annotate-visualizations" [Create dashboard folders]: "/docs/grafana/ -> /docs/grafana//dashboards/manage-dashboards#create-a-dashboard-folder" -[Create dashboard folders]: "/docs/grafana-cloud/ -> /docs/grafana//dashboards/manage-dashboards#create-a-dashboard-folder" +[Create dashboard folders]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/manage-dashboards#create-a-dashboard-folder" [JSON model]: "/docs/grafana/ -> /docs/grafana//dashboards/build-dashboards/view-dashboard-json-model" -[JSON model]: "/docs/grafana-cloud/ -> /docs/grafana//dashboards/build-dashboards/view-dashboard-json-model" +[JSON model]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/build-dashboards/view-dashboard-json-model" -[Export and import]: "/docs/grafana/ -> /docs/grafana//dashboards/manage-dashboards#export-and-import-dashboards" -[Export and import]: "/docs/grafana-cloud/ -> /docs/grafana//dashboards/manage-dashboards#export-and-import-dashboards" +[Import]: "/docs/grafana/ -> /docs/grafana//dashboards/build-dashboards/import-dashboards" +[Import]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/build-dashboards/import-dashboards" + +[Export and share]: "/docs/grafana/ -> /docs/grafana//dashboards/share-dashboards-panels" +[Export and share]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/share-dashboards-panels" [Manage dashboards]: "/docs/grafana/ -> /docs/grafana//dashboards/manage-dashboards" -[Manage dashboards]: "/docs/grafana-cloud/ -> /docs/grafana//dashboards/manage-dashboards" +[Manage dashboards]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/manage-dashboards" [Build dashboards]: "/docs/grafana/ -> /docs/grafana//dashboards/build-dashboards" -[Build dashboards]: "/docs/grafana-cloud/ -> /docs/grafana//dashboards/build-dashboards" +[Build dashboards]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/build-dashboards" [Use dashboards]: "/docs/grafana/ -> /docs/grafana//dashboards/use-dashboards" -[Use dashboards]: "/docs/grafana-cloud/ -> /docs/grafana//dashboards/use-dashboards" +[Use dashboards]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/use-dashboards" [Playlist]: "/docs/grafana/ -> /docs/grafana//dashboards/create-manage-playlists" -[Playlist]: "/docs/grafana-cloud/ -> /docs/grafana//dashboards/create-manage-playlists" +[Playlist]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/create-manage-playlists" {{% /docs/reference %}} diff --git a/docs/sources/dashboards/create-reports/index.md b/docs/sources/dashboards/create-reports/index.md index e0026f905501..aebdae63d01d 100644 --- a/docs/sources/dashboards/create-reports/index.md +++ b/docs/sources/dashboards/create-reports/index.md @@ -284,8 +284,8 @@ filters = report:debug ``` {{% docs/reference %}} -[time range controls]: "/docs/grafana/ -> /docs/grafana//dashboards/manage-dashboards" -[time range controls]: "/docs/grafana-cloud/ -> /docs/grafana//dashboards/manage-dashboards" +[time range controls]: "/docs/grafana/ -> /docs/grafana//dashboards/use-dashboards#set-dashboard-time-range" +[time range controls]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/use-dashboards#set-dashboard-time-range" [image rendering]: "/docs/grafana/ -> /docs/grafana//setup-grafana/image-rendering" [image rendering]: "/docs/grafana-cloud/ -> /docs/grafana//setup-grafana/image-rendering" @@ -306,10 +306,10 @@ filters = report:debug [SMTP]: "/docs/grafana-cloud/ -> /docs/grafana//setup-grafana/configure-grafana#smtp" [Repeat panels or rows]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/configure-panel-options#configure-repeating-rows-or-panels" -[Repeat panels or rows]: "/docs/grafana-cloud/ -> /docs/grafana//panels-visualizations/configure-panel-options#configure-repeating-rows-or-panels" +[Repeat panels or rows]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/configure-panel-options#configure-repeating-rows-or-panels" [Templates and variables]: "/docs/grafana/ -> /docs/grafana//dashboards/variables" -[Templates and variables]: "/docs/grafana-cloud/ -> /docs/grafana//dashboards/variables" +[Templates and variables]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/variables" [temp-data-lifetime]: "/docs/grafana/ -> /docs/grafana//setup-grafana/configure-grafana#temp-data-lifetime" [temp-data-lifetime]: "/docs/grafana-cloud/ -> /docs/grafana//setup-grafana/configure-grafana#temp-data-lifetime" diff --git a/docs/sources/dashboards/share-dashboards-panels/index.md b/docs/sources/dashboards/share-dashboards-panels/index.md index a6f66b8a5197..84ef03462993 100644 --- a/docs/sources/dashboards/share-dashboards-panels/index.md +++ b/docs/sources/dashboards/share-dashboards-panels/index.md @@ -93,9 +93,26 @@ You can publish snapshots to your local instance or to [snapshots.raintank.io](h If you created a snapshot by mistake, click **Delete snapshot** to remove the snapshot from your Grafana instance. -### Dashboard export +### Export a dashboard as JSON -Grafana dashboards can easily be exported and imported. For more information, refer to [Export and import dashboards][]. +The dashboard export action creates a Grafana JSON file that contains everything you need, including layout, variables, styles, data sources, queries, and so on, so that you can later import the dashboard. + +1. Click **Dashboards** in the main menu. +1. Open the dashboard you want to export. +1. Click the **Share** icon in the top navigation bar. +1. Click **Export**. + + If you're exporting the dashboard to use in another instance, with different data source UIDs, enable the **Export for sharing externally** switch. + +1. Click **Save to file**. + +Grafana downloads a JSON file to your local machine. + +#### Make a dashboard portable + +If you want to export a dashboard for others to use, you can add template variables for things like a metric prefix (use a constant variable) and server name. + +A template variable of the type `Constant` is automatically hidden in the dashboard, and is also added as a required input when the dashboard is imported. ## Export dashboard as PDF @@ -192,9 +209,6 @@ To create a library panel from the **Share Panel** dialog: 1. Save the dashboard. {{% docs/reference %}} -[Export and import dashboards]: "/docs/grafana/ -> /docs/grafana//dashboards/manage-dashboards#export-and-import-dashboards" -[Export and import dashboards]: "/docs/grafana-cloud/ -> /docs/grafana//dashboards/manage-dashboards#export-and-import-dashboards" - [Grafana Enterprise]: "/docs/grafana/ -> /docs/grafana//introduction/grafana-enterprise" [Grafana Enterprise]: "/docs/grafana-cloud/ -> /docs/grafana//introduction/grafana-enterprise" From a0c2fb1b8c13e96d0c0c11a24911f171a61cf46e Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Fri, 23 Feb 2024 10:01:12 +0100 Subject: [PATCH 012/138] [v10.4.x] AuthProxy: Invalidate previous cached item for user when changes are made to any header (#83287) AuthProxy: Invalidate previous cached item for user when changes are made to any header (#81445) * fix: sign in using auth_proxy with role a -> b -> a would end up with role b * Update pkg/services/authn/clients/proxy.go Co-authored-by: Karl Persson * Update pkg/services/authn/clients/proxy.go Co-authored-by: Karl Persson (cherry picked from commit 9282c7a7a409e19aa0295980fe97eba556143644) Co-authored-by: Klesh Wong --- pkg/services/authn/clients/proxy.go | 24 ++++++++- pkg/services/authn/clients/proxy_test.go | 64 +++++++++++++++++++++--- 2 files changed, 80 insertions(+), 8 deletions(-) diff --git a/pkg/services/authn/clients/proxy.go b/pkg/services/authn/clients/proxy.go index fd19789274d2..46c9ee1b0415 100644 --- a/pkg/services/authn/clients/proxy.go +++ b/pkg/services/authn/clients/proxy.go @@ -54,6 +54,7 @@ func ProvideProxy(cfg *setting.Cfg, cache proxyCache, userSrv user.Service, clie type proxyCache interface { Get(ctx context.Context, key string) ([]byte, error) Set(ctx context.Context, key string, value []byte, expire time.Duration) error + Delete(ctx context.Context, key string) error } type Proxy struct { @@ -146,13 +147,32 @@ func (c *Proxy) Hook(ctx context.Context, identity *authn.Identity, r *authn.Req c.log.Warn("Failed to cache proxy user", "error", err, "userId", identifier, "err", err) return nil } + + // User's role would not be updated if the cache hit. If requests arrive in the following order: + // 1. Name = x; Role = Admin # cache missed, new user created and cached with key Name=x;Role=Admin + // 2. Name = x; Role = Editor # cache missed, the user got updated and cached with key Name=x;Role=Editor + // 3. Name = x; Role = Admin # cache hit with key Name=x;Role=Admin, no update, the user stays with Role=Editor + // To avoid such a problem we also cache the key used using `prefix:[username]`. + // Then whenever we get a cache miss due to changes in any header we use it to invalidate the previous item. + username := getProxyHeader(r, c.cfg.AuthProxyHeaderName, c.cfg.AuthProxyHeadersEncoded) + userKey := fmt.Sprintf("%s:%s", proxyCachePrefix, username) + + // invalidate previously cached user id + if prevCacheKey, err := c.cache.Get(ctx, userKey); err == nil && len(prevCacheKey) > 0 { + if err := c.cache.Delete(ctx, string(prevCacheKey)); err != nil { + return err + } + } + c.log.FromContext(ctx).Debug("Cache proxy user", "userId", id) bytes := []byte(strconv.FormatInt(id, 10)) - if err := c.cache.Set(ctx, identity.ClientParams.CacheAuthProxyKey, bytes, time.Duration(c.cfg.AuthProxySyncTTL)*time.Minute); err != nil { + duration := time.Duration(c.cfg.AuthProxySyncTTL) * time.Minute + if err := c.cache.Set(ctx, identity.ClientParams.CacheAuthProxyKey, bytes, duration); err != nil { c.log.Warn("Failed to cache proxy user", "error", err, "userId", id) } - return nil + // store current cacheKey for the user + return c.cache.Set(ctx, userKey, []byte(identity.ClientParams.CacheAuthProxyKey), duration) } func (c *Proxy) isAllowedIP(r *authn.Request) bool { diff --git a/pkg/services/authn/clients/proxy_test.go b/pkg/services/authn/clients/proxy_test.go index a0b19dc1a0d9..408f5b32004f 100644 --- a/pkg/services/authn/clients/proxy_test.go +++ b/pkg/services/authn/clients/proxy_test.go @@ -3,6 +3,7 @@ package clients import ( "context" "errors" + "fmt" "net/http" "testing" "time" @@ -112,7 +113,7 @@ func TestProxy_Authenticate(t *testing.T) { calledAdditional = additional return nil, nil }} - c, err := ProvideProxy(cfg, fakeCache{expectedErr: errors.New("")}, usertest.NewUserServiceFake(), proxyClient) + c, err := ProvideProxy(cfg, &fakeCache{expectedErr: errors.New("")}, usertest.NewUserServiceFake(), proxyClient) require.NoError(t, err) _, err = c.Authenticate(context.Background(), tt.req) @@ -177,14 +178,65 @@ func TestProxy_Test(t *testing.T) { var _ proxyCache = new(fakeCache) type fakeCache struct { - expectedErr error - expectedItem []byte + data map[string][]byte + expectedErr error } -func (f fakeCache) Get(ctx context.Context, key string) ([]byte, error) { - return f.expectedItem, f.expectedErr +func (f *fakeCache) Get(ctx context.Context, key string) ([]byte, error) { + return f.data[key], f.expectedErr } -func (f fakeCache) Set(ctx context.Context, key string, value []byte, expire time.Duration) error { +func (f *fakeCache) Set(ctx context.Context, key string, value []byte, expire time.Duration) error { + f.data[key] = value return f.expectedErr } + +func (f fakeCache) Delete(ctx context.Context, key string) error { + delete(f.data, key) + return f.expectedErr +} + +func TestProxy_Hook(t *testing.T) { + cfg := setting.NewCfg() + cfg.AuthProxyHeaderName = "X-Username" + cfg.AuthProxyHeaders = map[string]string{ + proxyFieldRole: "X-Role", + } + cache := &fakeCache{data: make(map[string][]byte)} + userId := 1 + userID := fmt.Sprintf("%s:%d", authn.NamespaceUser, userId) + + // withRole creates a test case for a user with a specific role. + withRole := func(role string) func(t *testing.T) { + cacheKey := fmt.Sprintf("users:johndoe-%s", role) + return func(t *testing.T) { + c, err := ProvideProxy(cfg, cache, usertest.NewUserServiceFake(), authntest.MockProxyClient{}) + require.NoError(t, err) + userIdentity := &authn.Identity{ + ID: userID, + ClientParams: authn.ClientParams{ + CacheAuthProxyKey: cacheKey, + }, + } + userReq := &authn.Request{ + HTTPRequest: &http.Request{ + Header: map[string][]string{ + "X-Username": {"johndoe"}, + "X-Role": {role}, + }, + }, + } + err = c.Hook(context.Background(), userIdentity, userReq) + assert.NoError(t, err) + expectedCache := map[string][]byte{ + cacheKey: []byte(fmt.Sprintf("%d", userId)), + fmt.Sprintf("%s:%s", proxyCachePrefix, "johndoe"): []byte(fmt.Sprintf("users:johndoe-%s", role)), + } + assert.Equal(t, expectedCache, cache.data) + } + } + + t.Run("step 1: new user with role Admin", withRole("Admin")) + t.Run("step 2: cached user with new Role Viewer", withRole("Viewer")) + t.Run("step 3: cached user get changed back to Admin", withRole("Admin")) +} From deb12d4e94eadc5cd998d3d08d714bacbd5d26bb Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Fri, 23 Feb 2024 14:14:05 +0200 Subject: [PATCH 013/138] [v10.4.x] DataQuery: Track panel plugin id not type (#83164) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DataQuery: Track panel plugin id not type (#83091) (cherry picked from commit 64e0a4282ef57d0d3efdf989fec67d21fbeac524) Co-authored-by: Torkel Ödegaard --- packages/grafana-data/src/types/datasource.ts | 2 +- packages/grafana-runtime/src/analytics/types.ts | 2 +- .../src/utils/DataSourceWithBackend.ts | 6 +++--- pkg/api/pluginproxy/ds_proxy.go | 4 ++-- .../clientmiddleware/tracing_header_middleware.go | 2 +- pkg/services/query/query.go | 14 +++++++------- .../dashboard-scene/scene/DashboardScene.test.tsx | 4 ++-- .../dashboard-scene/scene/DashboardScene.tsx | 2 +- public/app/features/dashboard/state/PanelModel.ts | 2 +- .../app/features/query/state/PanelQueryRunner.ts | 6 +++--- .../features/query/state/queryAnalytics.test.ts | 12 ++++++------ public/app/features/query/state/queryAnalytics.ts | 2 +- .../app/plugins/datasource/graphite/datasource.ts | 6 +++--- 13 files changed, 32 insertions(+), 32 deletions(-) diff --git a/packages/grafana-data/src/types/datasource.ts b/packages/grafana-data/src/types/datasource.ts index 82232b4991d6..7f20cb9273dd 100644 --- a/packages/grafana-data/src/types/datasource.ts +++ b/packages/grafana-data/src/types/datasource.ts @@ -555,7 +555,7 @@ export interface DataQueryRequest { rangeRaw?: RawTimeRange; timeInfo?: string; // The query time description (blue text in the upper right) panelId?: number; - panelPluginType?: string; + panelPluginId?: string; dashboardUID?: string; /** Filters to dynamically apply to all queries */ diff --git a/packages/grafana-runtime/src/analytics/types.ts b/packages/grafana-runtime/src/analytics/types.ts index 07cfd4756b6e..b67b5ef3d270 100644 --- a/packages/grafana-runtime/src/analytics/types.ts +++ b/packages/grafana-runtime/src/analytics/types.ts @@ -29,7 +29,7 @@ export interface DataRequestInfo extends Partial { datasourceUid: string; datasourceType: string; panelId?: number; - panelPluginType?: string; + panelPluginId?: string; panelName?: string; duration: number; error?: string; diff --git a/packages/grafana-runtime/src/utils/DataSourceWithBackend.ts b/packages/grafana-runtime/src/utils/DataSourceWithBackend.ts index 65d80f784754..204fc4bec2c0 100644 --- a/packages/grafana-runtime/src/utils/DataSourceWithBackend.ts +++ b/packages/grafana-runtime/src/utils/DataSourceWithBackend.ts @@ -80,7 +80,7 @@ enum PluginRequestHeaders { DatasourceUID = 'X-Datasource-Uid', // can be used for routing/ load balancing DashboardUID = 'X-Dashboard-Uid', // mainly useful for debugging slow queries PanelID = 'X-Panel-Id', // mainly useful for debugging slow queries - PanelPluginType = 'X-Panel-Plugin-Type', + PanelPluginId = 'X-Panel-Plugin-Id', QueryGroupID = 'X-Query-Group-Id', // mainly useful to find related queries with query splitting FromExpression = 'X-Grafana-From-Expr', // used by datasources to identify expression queries SkipQueryCache = 'X-Cache-Skip', // used by datasources to skip the query cache @@ -227,8 +227,8 @@ class DataSourceWithBackend< if (request.panelId) { headers[PluginRequestHeaders.PanelID] = `${request.panelId}`; } - if (request.panelPluginType) { - headers[PluginRequestHeaders.PanelPluginType] = `${request.panelPluginType}`; + if (request.panelPluginId) { + headers[PluginRequestHeaders.PanelPluginId] = `${request.panelPluginId}`; } if (request.queryGroupId) { headers[PluginRequestHeaders.QueryGroupID] = `${request.queryGroupId}`; diff --git a/pkg/api/pluginproxy/ds_proxy.go b/pkg/api/pluginproxy/ds_proxy.go index 651d61bb1ce4..8037c79a1236 100644 --- a/pkg/api/pluginproxy/ds_proxy.go +++ b/pkg/api/pluginproxy/ds_proxy.go @@ -344,7 +344,7 @@ func (proxy *DataSourceProxy) logRequest() { } } - panelPluginType := proxy.ctx.Req.Header.Get("X-Panel-Plugin-Type") + panelPluginId := proxy.ctx.Req.Header.Get("X-Panel-Plugin-Id") ctxLogger := logger.FromContext(proxy.ctx.Req.Context()) ctxLogger.Info("Proxying incoming request", @@ -354,7 +354,7 @@ func (proxy *DataSourceProxy) logRequest() { "datasource", proxy.ds.Type, "uri", proxy.ctx.Req.RequestURI, "method", proxy.ctx.Req.Method, - "panelPluginType", panelPluginType, + "panelPluginId", panelPluginId, "body", body) } diff --git a/pkg/services/pluginsintegration/clientmiddleware/tracing_header_middleware.go b/pkg/services/pluginsintegration/clientmiddleware/tracing_header_middleware.go index 9cfcd07b48c8..06003fe502d4 100644 --- a/pkg/services/pluginsintegration/clientmiddleware/tracing_header_middleware.go +++ b/pkg/services/pluginsintegration/clientmiddleware/tracing_header_middleware.go @@ -34,7 +34,7 @@ func (m *TracingHeaderMiddleware) applyHeaders(ctx context.Context, req backend. return } - var headersList = []string{query.HeaderQueryGroupID, query.HeaderPanelID, query.HeaderDashboardUID, query.HeaderDatasourceUID, query.HeaderFromExpression, `X-Grafana-Org-Id`, query.HeaderPanelPluginType} + var headersList = []string{query.HeaderQueryGroupID, query.HeaderPanelID, query.HeaderDashboardUID, query.HeaderDatasourceUID, query.HeaderFromExpression, `X-Grafana-Org-Id`, query.HeaderPanelPluginId} for _, headerName := range headersList { gotVal := reqCtx.Req.Header.Get(headerName) diff --git a/pkg/services/query/query.go b/pkg/services/query/query.go index 328d730db215..90b6c9eb8920 100644 --- a/pkg/services/query/query.go +++ b/pkg/services/query/query.go @@ -28,13 +28,13 @@ import ( ) const ( - HeaderPluginID = "X-Plugin-Id" // can be used for routing - HeaderDatasourceUID = "X-Datasource-Uid" // can be used for routing/ load balancing - HeaderDashboardUID = "X-Dashboard-Uid" // mainly useful for debugging slow queries - HeaderPanelID = "X-Panel-Id" // mainly useful for debugging slow queries - HeaderPanelPluginType = "X-Panel-Plugin-Type" - HeaderQueryGroupID = "X-Query-Group-Id" // mainly useful for finding related queries with query chunking - HeaderFromExpression = "X-Grafana-From-Expr" // used by datasources to identify expression queries + HeaderPluginID = "X-Plugin-Id" // can be used for routing + HeaderDatasourceUID = "X-Datasource-Uid" // can be used for routing/ load balancing + HeaderDashboardUID = "X-Dashboard-Uid" // mainly useful for debugging slow queries + HeaderPanelID = "X-Panel-Id" // mainly useful for debugging slow queries + HeaderPanelPluginId = "X-Panel-Plugin-Id" + HeaderQueryGroupID = "X-Query-Group-Id" // mainly useful for finding related queries with query chunking + HeaderFromExpression = "X-Grafana-From-Expr" // used by datasources to identify expression queries ) func ProvideService( diff --git a/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx b/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx index 320fa0d7c41c..adf94e3d033e 100644 --- a/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx @@ -125,13 +125,13 @@ describe('DashboardScene', () => { scene.onEnterEditMode(); }); - it('Should add app, uid, panelId and panelPluginType', () => { + it('Should add app, uid, panelId and panelPluginId', () => { const queryRunner = sceneGraph.findObject(scene, (o) => o.state.key === 'data-query-runner')!; expect(scene.enrichDataRequest(queryRunner)).toEqual({ app: CoreApp.Dashboard, dashboardUID: 'dash-1', panelId: 1, - panelPluginType: 'table', + panelPluginId: 'table', }); }); diff --git a/public/app/features/dashboard-scene/scene/DashboardScene.tsx b/public/app/features/dashboard-scene/scene/DashboardScene.tsx index 701cdbfc7096..1ae57aa7e294 100644 --- a/public/app/features/dashboard-scene/scene/DashboardScene.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardScene.tsx @@ -555,7 +555,7 @@ export class DashboardScene extends SceneObjectBase { app: CoreApp.Dashboard, dashboardUID: this.state.uid, panelId, - panelPluginType: panel?.state.pluginId, + panelPluginId: panel?.state.pluginId, }; } diff --git a/public/app/features/dashboard/state/PanelModel.ts b/public/app/features/dashboard/state/PanelModel.ts index 2bf12614a0d5..fcf1307a2844 100644 --- a/public/app/features/dashboard/state/PanelModel.ts +++ b/public/app/features/dashboard/state/PanelModel.ts @@ -377,7 +377,7 @@ export class PanelModel implements DataConfigSource, IPanelModel { datasource: this.datasource, queries: this.targets, panelId: this.id, - panelPluginType: this.type, + panelPluginId: this.type, dashboardUID: dashboardUID, timezone: dashboardTimezone, timeRange: timeData.timeRange, diff --git a/public/app/features/query/state/PanelQueryRunner.ts b/public/app/features/query/state/PanelQueryRunner.ts index 5a79e3d00149..940894c04600 100644 --- a/public/app/features/query/state/PanelQueryRunner.ts +++ b/public/app/features/query/state/PanelQueryRunner.ts @@ -50,7 +50,7 @@ export interface QueryRunnerOptions< datasource: DataSourceRef | DataSourceApi | null; queries: TQuery[]; panelId?: number; - panelPluginType?: string; + panelPluginId?: string; dashboardUID?: string; timezone: TimeZone; timeRange: TimeRange; @@ -258,7 +258,7 @@ export class PanelQueryRunner { timezone, datasource, panelId, - panelPluginType, + panelPluginId, dashboardUID, timeRange, timeInfo, @@ -280,7 +280,7 @@ export class PanelQueryRunner { requestId: getNextRequestId(), timezone, panelId, - panelPluginType, + panelPluginId, dashboardUID, range: timeRange, timeInfo, diff --git a/public/app/features/query/state/queryAnalytics.test.ts b/public/app/features/query/state/queryAnalytics.test.ts index b71f3d893a44..2d0dadf99d8b 100644 --- a/public/app/features/query/state/queryAnalytics.test.ts +++ b/public/app/features/query/state/queryAnalytics.test.ts @@ -103,7 +103,7 @@ function getTestData( scopedVars: {}, targets: [], timezone: 'utc', - panelPluginType: 'timeseries', + panelPluginId: 'timeseries', ...overrides, }, series: series || [], @@ -135,7 +135,7 @@ describe('emitDataRequestEvent', () => { duration: 1, totalQueries: 0, cachedQueries: 0, - panelPluginType: 'timeseries', + panelPluginId: 'timeseries', }) ); }); @@ -163,7 +163,7 @@ describe('emitDataRequestEvent', () => { duration: 1, totalQueries: 2, cachedQueries: 1, - panelPluginType: 'timeseries', + panelPluginId: 'timeseries', }) ); }); @@ -191,7 +191,7 @@ describe('emitDataRequestEvent', () => { duration: 1, totalQueries: 1, cachedQueries: 1, - panelPluginType: 'timeseries', + panelPluginId: 'timeseries', }) ); }); @@ -238,7 +238,7 @@ describe('emitDataRequestEvent', () => { dataSize: 0, duration: 1, totalQueries: 0, - panelPluginType: 'timeseries', + panelPluginId: 'timeseries', }) ); }); @@ -275,7 +275,7 @@ describe('emitDataRequestEvent', () => { dataSize: 0, duration: 1, totalQueries: 0, - panelPluginType: 'timeseries', + panelPluginId: 'timeseries', }) ); }); diff --git a/public/app/features/query/state/queryAnalytics.ts b/public/app/features/query/state/queryAnalytics.ts index f8bb3afae5cd..337fe6d4b00a 100644 --- a/public/app/features/query/state/queryAnalytics.ts +++ b/public/app/features/query/state/queryAnalytics.ts @@ -29,7 +29,7 @@ export function emitDataRequestEvent(datasource: DataSourceApi) { datasourceType: datasource.type, dataSize: 0, panelId: 0, - panelPluginType: data.request?.panelPluginType, + panelPluginId: data.request?.panelPluginId, duration: data.request.endTime! - data.request.startTime, }; diff --git a/public/app/plugins/datasource/graphite/datasource.ts b/public/app/plugins/datasource/graphite/datasource.ts index 34b8165641a7..90ce33533e39 100644 --- a/public/app/plugins/datasource/graphite/datasource.ts +++ b/public/app/plugins/datasource/graphite/datasource.ts @@ -248,7 +248,7 @@ export class GraphiteDatasource addTracingHeaders( httpOptions: { headers: any }, - options: { dashboardId?: number; panelId?: number; panelPluginType?: string } + options: { dashboardId?: number; panelId?: number; panelPluginId?: string } ) { const proxyMode = !this.url.match(/^http/); if (proxyMode) { @@ -258,8 +258,8 @@ export class GraphiteDatasource if (options.panelId) { httpOptions.headers['X-Panel-Id'] = options.panelId; } - if (options.panelPluginType) { - httpOptions.headers['X-Panel-Plugin-Id'] = options.panelPluginType; + if (options.panelPluginId) { + httpOptions.headers['X-Panel-Plugin-Id'] = options.panelPluginId; } } } From dadc81b0e9f25f5fa135c2b1a3c64cef2806bf50 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Fri, 23 Feb 2024 11:07:24 -0600 Subject: [PATCH 014/138] [v10.4.x] remove oss from security config docs (#83326) remove oss from security config docs (#82936) (cherry picked from commit 92fa868a77e91ab517d7ff81ef683a89319a1342) Co-authored-by: Kristina --- .../configure-security/configure-request-security.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/sources/setup-grafana/configure-security/configure-request-security.md b/docs/sources/setup-grafana/configure-security/configure-request-security.md index 9a2fb05cb9a0..437786ed07fb 100644 --- a/docs/sources/setup-grafana/configure-security/configure-request-security.md +++ b/docs/sources/setup-grafana/configure-security/configure-request-security.md @@ -8,7 +8,6 @@ labels: products: - cloud - enterprise - - oss title: Configure request security weight: 1100 --- From 58d6e0b3d273ed311b64b7ab372824df5d61b9ce Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Fri, 23 Feb 2024 16:55:42 -0500 Subject: [PATCH 015/138] [v10.4.x] Docs: restructure Configure field overrides (#83348) Docs: restructure Configure field overrides (#81833) * Removed view and delete overrides sections * Added examples heading and moved examples down one heading level * Added override rules section and removed rule definitions from task * Added supported visualizations section and table and docs ref links * Docs: edit Configure field overrides (#81834) * Formatted note * Added missing content and general edits * Updated screenshots and examples and general edits * Fix small formatting issues * Fixed links * Uploaded images to admin, updated image links, and removed local images * Swapped figure shortcode for simple Markdown (cherry picked from commit dfeb33fe5594195f039ef83884002e4773a6b60e) Co-authored-by: Isabel <76437239+imatwawana@users.noreply.github.com> --- .../configure-overrides/index.md | 187 ++++++++++++++---- 1 file changed, 145 insertions(+), 42 deletions(-) diff --git a/docs/sources/panels-visualizations/configure-overrides/index.md b/docs/sources/panels-visualizations/configure-overrides/index.md index 6f875238ee59..64472b81107d 100644 --- a/docs/sources/panels-visualizations/configure-overrides/index.md +++ b/docs/sources/panels-visualizations/configure-overrides/index.md @@ -21,13 +21,61 @@ weight: 110 # Configure field overrides -Overrides allow you to customize visualization settings for specific fields or series. This is accomplished by adding an override rule that targets a particular set of fields and that can each define multiple options. +Overrides allow you to customize visualization settings for specific fields or series. When you add an override rule, it targets a particular set of fields and lets you define multiple options for how that field is displayed. -For example, you set the unit for all fields that include the text 'bytes' by adding an override using the `Fields with name matching regex` matcher and then add the Unit option to the override rule. +For example, you can override the default unit measurement for all fields that include the text "bytes" by adding an override using the **Fields with name matching regex** matcher and then the **Standard options > Unit** setting to the override rule: -## Example 1: Format temperature +![Field with unit override](/media/docs/grafana/panels-visualizations/screenshot-unit-override-v10.3.png) -Let’s assume that our result set is a data frame that consists of two fields: time and temperature. +After you've set them, your overrides appear in both the **All** and **Overrides** tabs of the panel editor pane: + +![All and Overrides tabs of panel editor pane](/media/docs/grafana/panels-visualizations/screenshot-all-overrides-tabs-v11.png) + +## Supported visualizations + +You can configure field overrides for the following visualizations: + +| | | | +| -------------------------- | ---------------------- | -------------------------------- | +| [Bar chart][bar chart] | [Geomap][geomap] | [State timeline][state timeline] | +| [Bar gauge][bar gauge] | [Heatmap][heatmap] | [Status history][status history] | +| [Candlestick][candlestick] | [Histogram][histogram] | [Table][table] | +| [Canvas][canvas] | [Pie chart][pie chart] | [Time series][time series] | +| [Gauge][gauge] | [Stat][stat] | [Trend][trend] | + + + +## Override rules + +You can choose from five types of override rules, which are described in the following sections. + +### Fields with name + +Select a field from the list of all available fields. Properties you add to this type of rule are only applied to this single field. + +### Fields with name matching regex + +Specify fields to override with a regular expression. Properties you add to this type of rule are applied to all fields where the field name matches the regular expression. This override doesn't rename the field; to do this, use the [Rename by regex transformation][]. + +### Fields with type + +Select fields by type, such as string, numeric, or time. Properties you add to this type of rule are applied to all fields that match the selected type. + +### Fields returned by query + +Select all fields returned by a specific query, such as A, B, or C. Properties you add to this type of rule are applied to all fields returned by the selected query. + +### Fields with values + +Select all fields returned by your defined reducer condition, such as **Min**, **Max**, **Count**, **Total**. Properties you add to this type of rule are applied to all fields returned by the selected condition. + +## Examples + +The following examples demonstrate how you can use override rules to alter the display of fields in visualizations. + +### Example 1: Format temperature + +The following result set is a data frame that consists of two fields: time and temperature. | time | temperature | | :-----------------: | :---------: | @@ -35,7 +83,14 @@ Let’s assume that our result set is a data frame that consists of two fields: | 2020-01-02 03:05:00 | 47.0 | | 2020-01-02 03:06:00 | 48.0 | -Each field (column) of this structure can have field options applied that alter the way its values are displayed. This means that you can, for example, set the Unit to Temperature > Celsius, resulting in the following table: +You can apply field options to each field (column) of this structure to alter the way its values are displayed. For example, you can set the following override rule: + +- Rule: **Fields with type** +- Field: temperature +- Override property: **Standard options > Unit** + - Selection: **Temperature > Celsius** + +This results in the following table: | time | temperature | | :-----------------: | :---------: | @@ -43,7 +98,7 @@ Each field (column) of this structure can have field options applied that alter | 2020-01-02 03:05:00 | 47.0 °C | | 2020-01-02 03:06:00 | 48.0 °C | -In addition, the decimal place is not required, so we can remove it. You can change the Decimals from `auto` to zero (`0`), resulting in the following table: +In addition, the decimal place isn't required, so you can remove it by adding another override property that changes the **Standard options > Decimals** setting from **auto** to `0`. That results in the following table: | time | temperature | | :-----------------: | :---------: | @@ -51,9 +106,9 @@ In addition, the decimal place is not required, so we can remove it. You can cha | 2020-01-02 03:05:00 | 47 °C | | 2020-01-02 03:06:00 | 48 °C | -## Example 2: Format temperature and humidity +### Example 2: Format temperature and humidity -Let’s assume that our result set is a data frame that consists of four fields: time, high temp, low temp, and humidity. +The following result set is a data frame that consists of four fields: time, high temp, low temp, and humidity. | time | high temp | low temp | humidity | | ------------------- | --------- | -------- | -------- | @@ -61,7 +116,16 @@ Let’s assume that our result set is a data frame that consists of four fields: | 2020-01-02 03:05:00 | 47.0 | 34.0 | 68 | | 2020-01-02 03:06:00 | 48.0 | 31.0 | 68 | -Let's add the Celsius unit and get rid of the decimal place. This results in the following table: +Use the following override rule and properties to add the **Celsius** unit option and remove the decimal place: + +- Rule: **Fields with type** +- Field: temperature +- Override property: **Standard options > Unit** + - Selection: **Temperature > Celsius** +- Override property: **Standard options > Decimals** + -Change setting from **auto** to `0` + +This results in the following table: | time | high temp | low temp | humidity | | ------------------- | --------- | -------- | -------- | @@ -69,7 +133,7 @@ Let's add the Celsius unit and get rid of the decimal place. This results in the | 2020-01-02 03:05:00 | 47 °C | 34 °C | 68 °C | | 2020-01-02 03:06:00 | 48 °C | 31 °C | 68 °C | -The temperature fields look good, but the humidity must now be changed. We can fix this by applying a field option override to the humidity field and change the unit to Misc > percent (0-100). +The temperature fields are displaying correctly, but the humidity has incorrect units. You can fix this by applying a **Misc > Percent (0-100)** override to the humidity field. This results in the following table: | time | high temp | low temp | humidity | | ------------------- | --------- | -------- | -------- | @@ -79,47 +143,86 @@ The temperature fields look good, but the humidity must now be changed. We can f ## Add a field override -A field override rule can customize the visualization settings for a specific field or series. - -1. Edit the panel to which you want to add an override. -1. In the panel options side pane, click **Add field override** at the bottom of the pane. - -1. Select which fields an override rule will be applied to: - - **Fields with name:** Select a field from the list of all available fields. Properties you add to a rule with this selector are only applied to this single field. - - **Fields with name matching regex:** Specify fields to override with a regular expression. Properties you add to a rule with this selector are applied to all fields where the field name match the regex. This override doesn't rename the field; to do this, use the [Rename by regex transformation]({{< relref "../query-transform-data/transform-data/#rename-by-regex" >}}). - - **Fields with type:** Select fields by type, such as string, numeric, and so on. Properties you add to a rule with this selector are applied to all fields that match the selected type. - - **Fields returned by query:** Select all fields returned by a specific query, such as A, B, or C. Properties you add to a rule with this selector are applied to all fields returned by the selected query. +To add a field override, follow these steps: + +1. Navigate to the panel to which you want to add the data link. +1. Hover over any part of the panel to display the menu icon in the upper-right corner. +1. Click the menu icon and select **Edit** to open the panel editor. +1. At the bottom of the panel editor pane, click **Add field override**. +1. Select the fields to which the override will be applied: + - **Fields with name** + - **Fields with name matching regex** + - **Fields with type** + - **Fields returned by query** + - **Fields with values** 1. Click **Add override property**. 1. Select the field option that you want to apply. -1. Enter options by adding values in the fields. To return options to default values, delete the white text in the fields. -1. Continue to add overrides to this field by clicking **Add override property**, or you can click **Add override** and select a different field to add overrides to. -1. When finished, click **Save** to save all panel edits to the dashboard. +1. Continue to add overrides to this field by clicking **Add override property**. +1. Add as many overrides as you need. +1. When you're finished, click **Save** to save all panel edits to the dashboard. -## Delete a field override +## Edit a field override -Delete a field override when you no longer need it. When you delete an override, the appearance of value defaults to its original format. This change impacts dashboards and dashboard users that rely on an affected panel. +To edit a field override, follow these steps: -1. Edit the panel that contains the override you want to delete. -1. In panel options side pane, scroll down until you see the overrides. -1. Click the override you want to delete and then click the associated trash icon. +1. Navigate to the panel to which you want to add the data link. +1. Hover over any part of the panel to display the menu icon in the upper-right corner. +1. Click the menu icon and select **Edit** to open the panel editor. +1. In the panel editor pane, click the **Overrides** tab. +1. Locate the override you want to change. +1. Perform any of the following tasks: + - Edit settings on existing overrides or field selection parameters. + - Delete existing override properties by clicking the **X** next to the property. + - Delete an override entirely by clicking the trash icon at the top-right corner. -## View field overrides +The changes you make take effect immediately. -You can view field overrides in the panel display options. +{{% docs/reference %}} +[bar chart]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/bar-chart" +[bar chart]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/bar-chart" -1. Edit the panel that contains the overrides you want to view. -1. In panel options side pane, scroll down until you see the overrides. +[bar gauge]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/bar-gauge" +[bar gauge]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/bar-gauge" -> The override settings that appear on the **All** tab are the same as the settings that appear on the **Overrides** tab. +[candlestick]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/candlestick" +[candlestick]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/candlestick" -## Edit a field override +[canvas]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/canvas" +[canvas]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/canvas" -Edit a field override when you want to make changes to an override setting. The change you make takes effect immediately. +[gauge]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/gauge" +[gauge]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/gauge" -1. Edit the panel that contains the overrides you want to edit. -1. In panel options side pane, scroll down until you see the overrides. -1. Locate the override that you want to change. -1. Perform any of the following: - - Edit settings on existing overrides or field selection parameters. - - Delete existing override properties by clicking the **X** next to the property. - - Add an override properties by clicking **Add override property**. +[geomap]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/geomap" +[geomap]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/geomap" + +[heatmap]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/heatmap" +[heatmap]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/heatmap" + +[histogram]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/histogram" +[histogram]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/histogram" + +[pie chart]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/pie-chart" +[pie chart]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/pie-chart" + +[stat]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/stat" +[stat]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/stat" + +[state timeline]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/state-timeline" +[state timeline]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/state-timeline" + +[status history]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/status-history" +[status history]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/status-history" + +[table]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/table" +[table]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/table" + +[time series]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/time-series" +[time series]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/time-series" + +[trend]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/trend" +[trend]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/trend" + +[Rename by regex transformation]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/query-transform-data/transform-data#rename-by-regex" +[Rename by regex transformation]: "/docs/grafana-cloud -> /docs/grafana-cloud/visualizations/panels-visualizations/query-transform-data/transform-data#rename-by-regex" +{{% /docs/reference %}} From 09663d856ddef659cc4170186db374c89c5b344e Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Mon, 26 Feb 2024 11:40:19 -0600 Subject: [PATCH 016/138] [v10.4.x] Docs/grafana helm (#83429) Docs/grafana helm (#80390) * added the helm project * added page metadata * added the intro section * fixed menuTitle * added section i.e. Setting up the Grafana Helm repository * added the deployment section * finished the deploying grafana section * completed access grafana section * updating changes * added persistent storage section * added debugging section * fixed typos * fixed headings * fixed numerious typos * Apply suggestions from code review looks good now !! Co-authored-by: Christopher Moyer <35463610+chri2547@users.noreply.github.com> * Apply suggestions from code review Thanks for the changes. It looks much better now Co-authored-by: Christopher Moyer <35463610+chri2547@users.noreply.github.com> * fixed the suggested changes and fixed minor typos * Apply suggestions from code review thanks for the improvements. looks polished now!! Co-authored-by: Christopher Moyer <35463610+chri2547@users.noreply.github.com> * fixed download link * fixed typo * final adjustments * corrects spelling * makes prettier --------- Co-authored-by: Christopher Moyer <35463610+chri2547@users.noreply.github.com> Co-authored-by: Chris Moyer (cherry picked from commit 9f88a883032bf53205fd2f0b941d18727f67676e) Co-authored-by: Usman Ahmad --- .../setup-grafana/installation/helm/index.md | 381 ++++++++++++++++++ 1 file changed, 381 insertions(+) create mode 100644 docs/sources/setup-grafana/installation/helm/index.md diff --git a/docs/sources/setup-grafana/installation/helm/index.md b/docs/sources/setup-grafana/installation/helm/index.md new file mode 100644 index 000000000000..b49c8271ca8c --- /dev/null +++ b/docs/sources/setup-grafana/installation/helm/index.md @@ -0,0 +1,381 @@ +--- +aliases: + - ../../installation/helm/ +description: Guide for deploying Grafana using Helm Charts +labels: + products: + - enterprise + - oss +menuTitle: Grafana on Helm Charts +title: Deploy Grafana using Helm Charts +weight: 500 +--- + +# Deploy Grafana using Helm Charts + +This topic includes instructions for installing and running Grafana on Kubernetes using Helm Charts. + +[Helm](https://helm.sh/) is an open-source command line tool used for managing Kubernetes applications. It is a graduate project in the [CNCF Landscape](https://www.cncf.io/projects/helm/). + +{{% admonition type="note" %}} +The Grafana open-source community offers Helm Charts for running it on Kubernetes. Please be aware that the code is provided without any warranties. If you encounter any problems, you can report them to the [Official GitHub repository](https://github.com/grafana/helm-charts/). +{{% /admonition %}} + +## Before you begin + +To install Grafana using Helm, ensure you have completed the following: + +- Install a Kubernetes server on your machine. For information about installing Kubernetes, refer to [Install Kubernetes](https://kubernetes.io/docs/setup/). +- Install the latest stable version of Helm. For information on installing Helm, refer to [Install Helm](https://helm.sh/docs/intro/install/). + +## Install Grafana using Helm + +When you install Grafana using Helm, you complete the following tasks: + +1. Set up the Grafana Helm repository, which provides a space in which you will install Grafana. + +1. Deploy Grafana using Helm, which installs Grafana into a namespace. + +1. Accessing Grafana, which provides steps to sign into Grafana. + +### Set up the Grafana Helm repository + +To set up the Grafana Helm repository so that you download the correct Grafana Helm charts on your machine, complete the following steps: + +1. To add the Grafana repository, use the following command syntax: + + `helm repo add ` + + The following example adds the `grafana` Helm repository. + + ```bash + helm repo add grafana https://grafana.github.io/helm-charts + ``` + +1. Run the following command to verify the repository was added: + + ```bash + helm repo list + ``` + + After you add the repository, you should see an output similar to the following: + + ```bash + NAME URL + grafana https://grafana.github.io/helm-charts + ``` + +1. Run the following command to update the repository to download the latest Grafana Helm charts: + + ```bash + helm repo update + ``` + +### Deploy the Grafana Helm charts + +After you have set up the Grafana Helm repository, you can start to deploy it on your Kubernetes cluster. + +When you deploy Grafana Helm charts, use a separate namespace instead of relying on the default namespace. The default namespace might already have other applications running, which can lead to conflicts and other potential issues. + +When you create a new namespace in Kubernetes, you can better organize, allocate, and manage cluster resources. For more information, refer to [Namespaces](https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/). + +1. To create a namespace, run the following command: + + ```bash + kubectl create namespace monitoring + ``` + + You will see an output similar to this, which means that the namespace has been successfully created: + + ```bash + namespace/monitoring created + ``` + +1. Search for the official `grafana/grafana` repository using the command: + + `helm search repo ` + + For example, the following command provides a list of the Grafana Helm Charts from which you will install the latest version of the Grafana chart. + + ```bash + helm search repo grafana/grafana + ``` + +1. Run the following command to deploy the Grafana Helm Chart inside your namespace. + + ```bash + helm install my-grafana grafana/grafana --namespace monitoring + ``` + + Where: + + - `helm install`: Installs the chart by deploying it on the Kubernetes cluster + - `my-grafana`: The logical chart name that you provided + - `grafana/grafana`: The repository and package name to install + - `--namespace`: The Kubernetes namespace (i.e. `monitoring`) where you want to deploy the chart + +1. To verify the deployment status, run the following command and verify that `deployed` appears in the **STATUS** column: + + ```bash + helm list -n monitoring + ``` + + You should see an output similar to the following: + + ```bash + NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION + my-grafana monitoring 1 2024-01-13 23:06:42.737989554 +0000 UTC deployed grafana-6.59.0 10.1.0 + ``` + +1. To check the overall status of all the objects in the namespace, run the following command: + + ```bash + kubectl get all -n monitoring + ``` + + If you encounter errors or warnings in the **STATUS** column, check the logs and refer to the Troubleshooting section of this documentation. + +### Access Grafana + +This section describes the steps you must complete to access Grafana via web browser. + +1. Run the following `helm get notes` command: + + ```bash + helm get notes my-grafana -n monitoring + ``` + + This command will print out the chart notes. You will the output `NOTES` that provide the complete instructions about: + + - How to decode the login password for the Grafana admin account + - Access Grafana service to the web browser + +1. To get the Grafana admin password, run the command as follows: + + ```bash + kubectl get secret --namespace monitoring my-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo + ``` + + It will give you a decoded `base64` string output which is the password for the admin account. + +1. Save the decoded password to a file on your machine. + +1. To access Grafana service on the web browser, run the following command: + + ```bash + export POD_NAME=$(kubectl get pods --namespace monitoring -l "app.kubernetes.io/name=grafana,app.kubernetes.io/instance=my-grafana" -o jsonpath="{.items[0].metadata.name}") + ``` + + The above command will export a shell variable named `POD_NAME` that will save the complete name of the pod which got deployed. + +1. Run the following port forwarding command to direct the Grafana pod to listen to port `3000`: + + ```bash + kubectl --namespace monitoring port-forward $POD_NAME 3000 + ``` + + For more information about port-forwarding, refer to [Use Port Forwarding to Access Applications in a Cluster](https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/). + +1. Navigate to `127.0.0.1:3000` in your browser. + +1. The Grafana sign-in page appears. + +1. To sign in, enter `admin` for the username. + +1. For the password paste it which you have saved to a file after decoding it earlier. + +## Customize Grafana default configuration + +Helm is a popular package manager for Kubernetes. It bundles Kubernetes resource manifests to be re-used across different environments. These manifests are written in a templating language, allowing you to provide configuration values via `values.yaml` file, or in-line using Helm, to replace the placeholders in the manifest where these configurations should reside. + +The `values.yaml` file allows you to customize the chart's configuration by specifying values for various parameters such as image versions, resource limits, service configurations, etc. + +By modifying the values in the `values.yaml` file, you can tailor the deployment of a Helm chart to your specific requirements by using the helm install or upgrade commands. For more information about configuring Helm, refer to [Values Files](https://helm.sh/docs/chart_template_guide/values_files/). + +### Download the values.yaml file + +In order to make any configuration changes, download the `values.yaml` file from the Grafana Helm Charts repository: + +https://github.com/grafana/helm-charts/edit/main/charts/grafana/values.yaml + +{{% admonition type="note" %}} +Depending on your use case requirements, you can use a single YAML file that contains your configuration changes or you can create multiple YAML files. +{{% /admonition %}} + +### Enable persistent storage **(recommended)** + +By default, persistent storage is disabled, which means that Grafana uses ephemeral storage, and all data will be stored within the container's file system. This data will be lost if the container is stopped, restarted, or if the container crashes. + +It is highly recommended that you enable persistent storage in Grafana Helm charts if you want to ensure that your data persists and is not lost in case of container restarts or failures. + +Enabling persistent storage in Grafana Helm charts ensures a reliable solution for running Grafana in production environments. + +To enable the persistent storage in the Grafana Helm charts, complete the following steps: + +1. Open the `values.yaml` file in your favorite editor. + +1. Edit the values and under the section of `persistence`, change the `enable` flag from `false` to `true` + + ```yaml + ....... + ............ + ...... + persistence: + type: pvc + enabled: true + # storageClassName: default + ....... + ............ + ...... + ``` + +1. Run the following `helm upgrade` command by specifying the `values.yaml` file to make the changes take effect: + + ```bash + helm upgrade my-grafana grafana/grafana -f values.yaml -n monitoring + ``` + +The PVC will now store all your data such as dashboards, data sources, and so on. + +### Install plugins (e.g. Zabbix app, Clock panel, etc.) + +You can install plugins in Grafana from the official and community [plugins page](https://grafana.com/grafana/plugins). These plugins allow you to add new visualization types, data sources, and applications to help you better visualize your data. + +Grafana currently supports three types of plugins: panel, data source, and app. For more information on managing plugins, refer to [Plugin Management](https://grafana.com/docs/grafana/latest/administration/plugin-management/). + +To install plugins in the Grafana Helm Charts, complete the following steps: + +1. Open the `values.yaml` file in your favorite editor. + +1. Find the line that says `plugins:` and under that section, define the plugins that you want to install. + + ```yaml + ....... + ............ + ...... + plugins: + # here we are installing two plugins, make sure to keep the indentation correct as written here. + + - alexanderzobnin-zabbix-app + - grafana-clock-panel + ....... + ............ + ...... + ``` + +1. Save the changes and use the `helm upgrade` command to get these plugins installed: + + ```bash + helm upgrade my-grafana grafana/grafana -f values.yaml -n monitoring + ``` + +1. Navigate to `127.0.0.1:3000` in your browser. + +1. Login with admin credentials when the Grafana sign-in page appears. + +1. Navigate to UI -> Administration -> Plugins + +1. Search for the above plugins and they should be marked as installed. + +## Troubleshooting + +This section includes troubleshooting tips you might find helpful when deploying Grafana on Kubernetes via Helm. + +### Collect logs + +It is important to view the Grafana server logs while troubleshooting any issues. + +To check the Grafana logs, run the following command: + +```bash +# dump Pod logs for a Deployment (single-container case) + +kubectl logs --namespace=monitoring deploy/my-grafana +``` + +If you have multiple containers running in the deployment, run the following command to obtain the logs only for the Grafana deployment: + +```bash +# dump Pod logs for a Deployment (multi-container case) + +kubectl logs --namespace=monitoring deploy/grafana -c my-grafana +``` + +For more information about accessing Kubernetes application logs, refer to [Pods](https://kubernetes.io/docs/reference/kubectl/cheatsheet/#interacting-with-running-pods) and [Deployments](https://kubernetes.io/docs/reference/kubectl/cheatsheet/#interacting-with-deployments-and-services). + +### Increase log levels + +By default, the Grafana log level is set to `info`, but you can increase it to `debug` mode to fetch information needed to diagnose and troubleshoot a problem. For more information about Grafana log levels, refer to [Configuring logs](https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana#log). + +To increase log level to `debug` mode, use the following steps: + +1. Open the `values.yaml` file in your favorite editor and search for the string `grafana.ini` and there you will find a section about log mode. + +1. Add level: `debug` just below the line `mode: console` + + ```yaml + # This is the values.yaml file + ..... + ....... + .... + grafana.ini: + paths: + data: /var/lib/grafana/ + ..... + ....... + .... + mode: console + level: debug + ``` + + Make sure to keep the indentation level the same otherwise it will not work. + +1. Now to apply this, run the `helm upgrade` command as follows: + + ```bash + helm upgrade my-grafana grafana/grafana -f values.yaml -n monitoring + ``` + +1. To verify it, access the Grafana UI in the browser using the provided `IP:Port`. The Grafana sign-in page appears. + +1. To sign in to Grafana, enter `admin` for the username and paste the password which was decoded earlier. Navigate to Server Admin > Settings and then search for log. You should see the level to `debug` mode. + +### Reset Grafana admin secrets (login credentials) + +By default the login credentials for the super admin account are generated via `secrets`. However, this can be changed easily. To achieve this, use the following steps: + +1. Edit the `values.yaml` file and search for the string `adminPassword`. There you can define a new password: + + ```yaml + # Administrator credentials when not using an existing secret (see below) + adminUser: admin + adminPassword: admin + ``` + +1. Then use the `helm upgrade` command as follows: + + ```bash + helm upgrade my-grafana grafana/grafana -f values.yaml -n monitoring + ``` + + This command will now make your super admin login credentials as `admin` for both username and password. + +1. To verify it, sign in to Grafana, enter `admin` for both username and password. You should be able to login as super admin. + +## Uninstall the Grafana deployment + +To uninstall the Grafana deployment, run the command: + +`helm uninstall ` + +```bash +helm uninstall my-grafana -n monitoring +``` + +This deletes all of the objects from the given namespace monitoring. + +If you want to delete the namespace `monitoring`, then run the command: + +```bash +kubectl delete namespace monitoring +``` From 8290d41f4bad9ce52d6e0a1a3d60803615744e0f Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Tue, 27 Feb 2024 15:52:01 +0100 Subject: [PATCH 017/138] [v10.4.x] Plugins: Angular deprecation: Fix AngularDeprecationNotice not being rendered on first page load (#83526) Plugins: Angular deprecation: Fix AngularDeprecationNotice not being rendered on first page load (#83221) * Plugins: Angular deprecation: Wait for plugins to be inizialized before rendering AngularDeprecationNotice * use then * fix tests * mockCleanUpDashboardAndVariables.mockReset(); * Handle plugin not found * PR review feedback * Add comment * removed unnecessary return * PR review feedback * Use grafanaBootData * Removed comments * fix tests * Use config for hideDeprecation as well (cherry picked from commit e068804a9e4844283322105d5be0987bca9ba924) Co-authored-by: Giuseppe Guerra --- public/app/features/dashboard/state/DashboardModel.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/public/app/features/dashboard/state/DashboardModel.ts b/public/app/features/dashboard/state/DashboardModel.ts index e406dae52066..b4b5d3376ad0 100644 --- a/public/app/features/dashboard/state/DashboardModel.ts +++ b/public/app/features/dashboard/state/DashboardModel.ts @@ -1342,7 +1342,9 @@ export class DashboardModel implements TimeModel { hasAngularPlugins(): boolean { return this.panels.some((panel) => { // Return false for plugins that are angular but have angular.hideDeprecation = false - const isAngularPanel = panel.isAngularPlugin() && !panel.plugin?.meta.angular?.hideDeprecation; + // We cannot use panel.plugin.isAngularPlugin() because panel.plugin may not be initialized at this stage. + const isAngularPanel = + config.panels[panel.type]?.angular?.detected && !config.panels[panel.type]?.angular?.hideDeprecation; let isAngularDs = false; if (panel.datasource?.uid) { isAngularDs = isAngularDatasourcePluginAndNotHidden(panel.datasource?.uid); From ff860eb5d0efd1c172b72cb67e2220cd38b13fe5 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Tue, 27 Feb 2024 17:02:07 +0100 Subject: [PATCH 018/138] [v10.4.x] Annotations: Improve query performance when using dashboard filter (#83404) Annotations: Improve query performance when using dashboard filter (#83112) * Annotations: Improve query performance when using dashboard filter * Add dashboard id filter (cherry picked from commit e7a1ecca289a17a56d6c175a9ff073e1ae61ee1a) Co-authored-by: Alexander Zobnin --- .../accesscontrol/accesscontrol.go | 21 ++++++++++++++----- .../accesscontrol/accesscontrol_test.go | 7 +++++-- .../annotationsimpl/annotations.go | 2 +- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/pkg/services/annotations/accesscontrol/accesscontrol.go b/pkg/services/annotations/accesscontrol/accesscontrol.go index 071cf21e8707..9102e62b9fa4 100644 --- a/pkg/services/annotations/accesscontrol/accesscontrol.go +++ b/pkg/services/annotations/accesscontrol/accesscontrol.go @@ -6,7 +6,6 @@ import ( "github.com/grafana/grafana/pkg/infra/db" ac "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/annotations" - "github.com/grafana/grafana/pkg/services/auth/identity" "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/sqlstore/permissions" @@ -40,7 +39,8 @@ func NewAuthService(db db.DB, features featuremgmt.FeatureToggles) *AuthService } // Authorize checks if the user has permission to read annotations, then returns a struct containing dashboards and scope types that the user has access to. -func (authz *AuthService) Authorize(ctx context.Context, orgID int64, user identity.Requester) (*AccessResources, error) { +func (authz *AuthService) Authorize(ctx context.Context, orgID int64, query *annotations.ItemQuery) (*AccessResources, error) { + user := query.SignedInUser if user == nil || user.IsNil() { return nil, ErrReadForbidden.Errorf("missing user") } @@ -59,7 +59,7 @@ func (authz *AuthService) Authorize(ctx context.Context, orgID int64, user ident var visibleDashboards map[string]int64 var err error if canAccessDashAnnotations { - visibleDashboards, err = authz.dashboardsWithVisibleAnnotations(ctx, user, orgID) + visibleDashboards, err = authz.dashboardsWithVisibleAnnotations(ctx, query, orgID) if err != nil { return nil, ErrAccessControlInternal.Errorf("failed to fetch dashboards: %w", err) } @@ -72,7 +72,7 @@ func (authz *AuthService) Authorize(ctx context.Context, orgID int64, user ident }, nil } -func (authz *AuthService) dashboardsWithVisibleAnnotations(ctx context.Context, user identity.Requester, orgID int64) (map[string]int64, error) { +func (authz *AuthService) dashboardsWithVisibleAnnotations(ctx context.Context, query *annotations.ItemQuery, orgID int64) (map[string]int64, error) { recursiveQueriesSupported, err := authz.db.RecursiveQueriesAreSupported() if err != nil { return nil, err @@ -84,10 +84,21 @@ func (authz *AuthService) dashboardsWithVisibleAnnotations(ctx context.Context, } filters := []any{ - permissions.NewAccessControlDashboardPermissionFilter(user, dashboardaccess.PERMISSION_VIEW, filterType, authz.features, recursiveQueriesSupported), + permissions.NewAccessControlDashboardPermissionFilter(query.SignedInUser, dashboardaccess.PERMISSION_VIEW, filterType, authz.features, recursiveQueriesSupported), searchstore.OrgFilter{OrgId: orgID}, } + if query.DashboardUID != "" { + filters = append(filters, searchstore.DashboardFilter{ + UIDs: []string{query.DashboardUID}, + }) + } + if query.DashboardID != 0 { + filters = append(filters, searchstore.DashboardIDFilter{ + IDs: []int64{query.DashboardID}, + }) + } + sb := &searchstore.Builder{Dialect: authz.db.GetDialect(), Filters: filters, Features: authz.features} visibleDashboards := make(map[string]int64) diff --git a/pkg/services/annotations/accesscontrol/accesscontrol_test.go b/pkg/services/annotations/accesscontrol/accesscontrol_test.go index 12ece80dd2c6..02674e42b246 100644 --- a/pkg/services/annotations/accesscontrol/accesscontrol_test.go +++ b/pkg/services/annotations/accesscontrol/accesscontrol_test.go @@ -5,15 +5,17 @@ import ( "fmt" "testing" + "github.com/stretchr/testify/require" + "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/services/accesscontrol" + "github.com/grafana/grafana/pkg/services/annotations" "github.com/grafana/grafana/pkg/services/annotations/testutil" "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/tests/testsuite" - "github.com/stretchr/testify/require" ) func TestMain(m *testing.M) { @@ -173,7 +175,8 @@ func TestIntegrationAuthorize(t *testing.T) { authz := NewAuthService(sql, featuremgmt.WithFeatures(tc.featureToggle)) - resources, err := authz.Authorize(context.Background(), 1, u) + query := &annotations.ItemQuery{SignedInUser: u} + resources, err := authz.Authorize(context.Background(), 1, query) require.NoError(t, err) if tc.expectedResources.Dashboards != nil { diff --git a/pkg/services/annotations/annotationsimpl/annotations.go b/pkg/services/annotations/annotationsimpl/annotations.go index 42ff9d20cf85..f9640a51e976 100644 --- a/pkg/services/annotations/annotationsimpl/annotations.go +++ b/pkg/services/annotations/annotationsimpl/annotations.go @@ -68,7 +68,7 @@ func (r *RepositoryImpl) Update(ctx context.Context, item *annotations.Item) err } func (r *RepositoryImpl) Find(ctx context.Context, query *annotations.ItemQuery) ([]*annotations.ItemDTO, error) { - resources, err := r.authZ.Authorize(ctx, query.OrgID, query.SignedInUser) + resources, err := r.authZ.Authorize(ctx, query.OrgID, query) if err != nil { return make([]*annotations.ItemDTO, 0), err } From ceb30ce23c8db58553d4469562cce8edea403efc Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Tue, 27 Feb 2024 17:16:59 -0500 Subject: [PATCH 019/138] [v10.4.x] Docs: Add missing visualizations to Grafana vizualization index page (#83554) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docs: Add missing visualizations to Grafana vizualization index page (#83351) Co-authored-by: Nathan Marrs Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> Co-authored-by: jev forsberg (cherry picked from commit e8df62941ba12c9a3b2e189f3e4d849b109d5522) Co-authored-by: Señor Performo - Leandro Melendez <54183040+srperf@users.noreply.github.com> --- .../panels-visualizations/visualizations/_index.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/sources/panels-visualizations/visualizations/_index.md b/docs/sources/panels-visualizations/visualizations/_index.md index 10042851d851..6e17cc7c64df 100644 --- a/docs/sources/panels-visualizations/visualizations/_index.md +++ b/docs/sources/panels-visualizations/visualizations/_index.md @@ -33,6 +33,7 @@ If you are unsure which visualization to pick, Grafana can provide visualization - [Heatmap][] visualizes data in two dimensions, used typically for the magnitude of a phenomenon. - [Pie chart][] is typically used where proportionality is important. - [Candlestick][] is typically for financial data where the focus is price/data movement. + - [Gauge][] is the traditional rounded visual showing how far a single metric is from a threshold. - Stats & numbers - [Stat][] for big stats and optional sparkline. - [Bar gauge][] is a horizontal or vertical bar gauge. @@ -42,6 +43,8 @@ If you are unsure which visualization to pick, Grafana can provide visualization - [Node graph][] for directed graphs or networks. - [Traces][] is the main visualization for traces. - [Flame graph][] is the main visualization for profiling. + - [Canvas][] allows you to explicitly place elements within static and dynamic layouts. + - [Geomap][] helps you visualize geospatial data. - Widgets - [Dashboard list][] can list dashboards. - [Alert list][] can list alerts. @@ -122,6 +125,12 @@ A state timeline shows discrete state changes over time. When used with time ser [Flame graph]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/flame-graph" [Flame graph]: "/docs/grafana-cloud/ -> /docs/grafana//panels-visualizations/visualizations/flame-graph" +[Canvas]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/canvas" +[Canvas]: "/docs/grafana-cloud/ -> /docs/grafana//panels-visualizations/visualizations/canvas" + +[Geomap]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/geomap" +[Geomap]: "/docs/grafana-cloud/ -> /docs/grafana//panels-visualizations/visualizations/geomap" + [Status history]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/status-history" [Status history]: "/docs/grafana-cloud/ -> /docs/grafana//panels-visualizations/visualizations/status-history" From 01d742fd883468ca1e9acab9f4bcc2f63dadf649 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:47:28 +0200 Subject: [PATCH 020/138] [v10.4.x] Elasticsearch: Fix adhoc filters not applied in frontend mode (#83597) Elasticsearch: Fix adhoc filters not applied in frontend mode (#83592) (cherry picked from commit 411c89012febe13323e4b8aafc8d692f4460e680) Co-authored-by: Sven Grossmann --- .../plugins/datasource/elasticsearch/LegacyQueryRunner.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/public/app/plugins/datasource/elasticsearch/LegacyQueryRunner.ts b/public/app/plugins/datasource/elasticsearch/LegacyQueryRunner.ts index c70a6ee60b2a..efb9d1259171 100644 --- a/public/app/plugins/datasource/elasticsearch/LegacyQueryRunner.ts +++ b/public/app/plugins/datasource/elasticsearch/LegacyQueryRunner.ts @@ -151,7 +151,11 @@ export class LegacyQueryRunner { query(request: DataQueryRequest): Observable { let payload = ''; - const targets = this.datasource.interpolateVariablesInQueries(cloneDeep(request.targets), request.scopedVars); + const targets = this.datasource.interpolateVariablesInQueries( + cloneDeep(request.targets), + request.scopedVars, + request.filters + ); const sentTargets: ElasticsearchQuery[] = []; let targetsContainsLogsQuery = targets.some((target) => hasMetricOfType(target, 'logs')); From f30ffd85fb49fed4cb89e6e40e356e4a8ea34959 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 28 Feb 2024 11:57:25 -0500 Subject: [PATCH 021/138] [v10.4.x] docs: link annotation queries video to documentation (#83622) docs: link annotation queries video to documentation (#83586) (cherry picked from commit ba4470dd7d39b3561ca25fda6f716fe5853ee5dd) Co-authored-by: Marie Cruz --- .../build-dashboards/annotate-visualizations/index.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/sources/dashboards/build-dashboards/annotate-visualizations/index.md b/docs/sources/dashboards/build-dashboards/annotate-visualizations/index.md index 3481be9f6d9a..d9711ffffab5 100644 --- a/docs/sources/dashboards/build-dashboards/annotate-visualizations/index.md +++ b/docs/sources/dashboards/build-dashboards/annotate-visualizations/index.md @@ -86,6 +86,10 @@ Alternatively, to add an annotation, press Ctrl/Cmd and click the panel, and the In the dashboard settings, under **Annotations**, you can add new queries to fetch annotations using any data source, including the built-in data annotation data source. Annotation queries return events that can be visualized as event markers in graphs across the dashboard. +Check out the video below for a quick tutorial. + +{{< youtube id="2istdJpPj2Y" >}} + ### Add new annotation queries To add a new annotation query to a dashboard, take the following steps: From a8ef92b04cbef044ed1ddcba6a503de8d1965ccf Mon Sep 17 00:00:00 2001 From: Eric Leijonmarck Date: Thu, 29 Feb 2024 08:30:06 +0000 Subject: [PATCH 022/138] [v10.4.x] Review "Team LBAC" page (#83627) Co-authored-by: Jack Baldry --- .../{index.md => _index.md} | 0 .../data-source-management/teamlbac/_index.md | 72 +++++++++---------- 2 files changed, 35 insertions(+), 37 deletions(-) rename docs/sources/administration/data-source-management/{index.md => _index.md} (100%) diff --git a/docs/sources/administration/data-source-management/index.md b/docs/sources/administration/data-source-management/_index.md similarity index 100% rename from docs/sources/administration/data-source-management/index.md rename to docs/sources/administration/data-source-management/_index.md diff --git a/docs/sources/administration/data-source-management/teamlbac/_index.md b/docs/sources/administration/data-source-management/teamlbac/_index.md index bf20999b20e7..1d87bdbb06d3 100644 --- a/docs/sources/administration/data-source-management/teamlbac/_index.md +++ b/docs/sources/administration/data-source-management/teamlbac/_index.md @@ -14,57 +14,55 @@ weight: 100 # Team LBAC -{{% admonition type="note" %}} -Creating Team LBAC rules is available for preview preview for logs with Loki in Grafana Cloud. Report any unexpected behavior to the Grafana Support team. -{{% /admonition %}} +Team Label Based Access Control (LBAC) simplifies and streamlines data source access management based on team memberships. -**Current Limitation:** +{{< admonition type="note" >}} +Creating Team LBAC rules is available for preview for logs with Loki in Grafana Cloud. +Report any unexpected behavior to the Grafana Support team. +{{< /admonition >}} -- Any user with `query` permissions for a Loki data source can query all logs if there are no Team LBAC rules configured for any of the users team. -- An admin that is part of a team, would have it's Team LBAC rules applied to the request. +You can configure user access based upon team memberships using LogQL. +Team LBAC controls access to logs depending on the rules set for each team. -Grafana's new **Team LBAC** (Label Based Access Control) feature for Loki is a significant enhancement that simplifies and streamlines data source access management based on team memberships. +This feature addresses two common challenges faced by Grafana users: -**Team LBAC** in the context of Loki, is a way to control access to logs based on labels present depending on the rules set for each team. Users wanting fine grained access to their logs in Loki, can now configure their users access based on their team memberships via **LogQL**. +1. Having a high number of Grafana Cloud data sources. + Team LBAC lets Grafana administrators reduce the total number of data sources per instance from hundreds, to one. +1. Using the same dashboard across multiple teams. + Team LBAC lets Grafana Teams use the same dashboard with different access control rules. -This feature addresses two common challenge faced by Grafana users: +To set up Team LBAC for a Loki data source, refer to [Configure Team LBAC](https://grafana.com/docs/grafana//administration/data-source-management/teamlbac/configure-teamlbac-for-loki/). -1. High volume of Grafana Cloud datasource. Team LBAC lets Grafana Admins reduce the total volume of data sources per instance from hundreds, to one. -1. Hard for teams to share dashboard. Team LBAC lets Grafana Teams share the same dashboard despite different access control rules. +## Limitations -For setting up Team LBAC for a Loki data source, refer to [Configure Team LBAC]({{< relref "./configure-teamlbac-for-loki/" >}}). +- If there are no Team LBAC rules for a user's team, that user can query all logs. +- If an administrator is part of a team with Team LBAC rules, those rules are applied to the administrator requests. +- Cloud Access Policies (CAP) LBAC rules override Team LBAC rules. + Cloud Access Policies are the access controls from Grafana Cloud. + If there are any CAP LBAC rules configured for the same data source, then only the CAP LBAC rules are applied. -#### Datasource Permissions + You must remove any label selectors from your Cloud Access Policies to use Team LBAC. + For more information about CAP label selectors, refer to [Use label-based access control (LBAC) with access policies](https://grafana.com/docs/grafana-cloud/account-management/authentication-and-permissions/access-policies/label-access-policies/). -Datasource permissions allow the users access to query the datasource. The permissions are set at the datasource level and are inherited by all the teams and users that are part of the datasource. +## Data source permissions -We recommend to create a new loki datasource for Team LBAC rules with only teams having `query` permission. This will allow you to have a clear separation of datasources for Team LBAC and the datasources that are not using Team LBAC. +Data source permissions allow the users access to query the data source. +Administrators set the permissions at the data source level. +All the teams and users that are part of the data source inherit those permissions. -## Team LBAC rules - -Team LBAC rules are added to the http request to Loki data source. Setting up Team LBAC rules for any team will apply those rules to the teams. -Users who want teams with a specific set of label selectors can add rules for each team. - -Configuring multiple rules for a team, each rule is evaluated separately. If a team has `X` number of rules configured for it, all rules will be applied to the request and the result will be the an "OR" operation of the `X` number of rules. - -Only users with data source Admin permissions can edit LBAC rules at the data source permissions tab. Changing LBAC rules requires the same access level as editing data source permissions (admin permission for data source). - -For setting up Team LBAC Rules for the data source, refer to [Create Team LBAC rules]({{< relref "./create-teamlbac-rules/" >}}). +## Recommended setup -### FAQ +It's recommended that you create a single Loki data source for using Team LBAC rules so you have a clear separation of data sources using Team LBAC and those that aren't. +All teams should have with only teams having `query` permission. +You should create another Loki data source configured without Team LBAC for full access to the logs. -> #### "If a team does not have a rule, what happens?" - -If a team does not have a rule; any users that are part of that team having query permissions for loki will have access to **all** logs. - -> #### "Can I use CAPs (cloud access policies) together with TeamLBAC rules?" - -No, CAP (cloud access policies) always have precedence. If there are any CAP LBAC configured for the same datasource and there are TeamLBAC rules configured, then only the CAP LBAC will be applied. +## Team LBAC rules -Cloud access policies are the access controls from Grafana Cloud, the CAP configured for loki should only to be used to gain read access to the logs. +Grafana adds Team LBAC rules to the HTTP request via the Loki data source. -> #### "If administrator forget to add rule for a team, what happens?" +If you configure multiple rules for a team, each rule is evaluated separately. +Query results include lines that match any of the rules. -The teams that does not have a rule applied to it, would be able to query all logs if `query` permissions are setup for their role within Grafana. +Only users with data source `Admin` permissions can edit Team LBAC rules in the **Data source permissions** tab because changing LBAC rules requires the same access level as editing data source permissions. -**Note:** A user who is part of a team within Grafana without a rule will be able to query all logs if there are role based queriying setup. +To set up Team LBAC for a Loki data source, refer to [Configure Team LBAC](https://grafana.com/docs/grafana//administration/data-source-management/teamlbac/configure-teamlbac-for-loki/). From cc010b657ab419b363e939fff899f1034719b750 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 29 Feb 2024 10:27:12 +0000 Subject: [PATCH 023/138] [v10.4.x] Anonymous: Add docs for anon users charged on enterprise (#83628) Anonymous: Add docs for anon users charged on enterprise (#83626) add anon users enterprise (cherry picked from commit b89de96681f10cbced9d0aaa5d811bf5670e0d4c) Co-authored-by: Eric Leijonmarck --- .../configure-authentication/grafana/index.md | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/docs/sources/setup-grafana/configure-security/configure-authentication/grafana/index.md b/docs/sources/setup-grafana/configure-security/configure-authentication/grafana/index.md index 17630be98554..05db6153133b 100644 --- a/docs/sources/setup-grafana/configure-security/configure-authentication/grafana/index.md +++ b/docs/sources/setup-grafana/configure-security/configure-authentication/grafana/index.md @@ -60,6 +60,25 @@ api_key_max_seconds_to_live = -1 You can make Grafana accessible without any login required by enabling anonymous access in the configuration file. For more information, refer to [Anonymous authentication]({{< relref "../../configure-authentication#anonymous-authentication" >}}). +#### Anonymous devices + +The anonymous devices feature enhances the management and monitoring of anonymous access within your Grafana instance. This feature is part of ongoing efforts to provide more control and transparency over anonymous usage. + +Users can now view anonymous usage statistics, including the count of devices and users over the last 30 days. + +- Go to **Administration -> Users** to access the anonymous devices tab. +- A new stat for the usage stats page -> Usage & Stats page shows the active anonymous devices last 30 days. + +The number of anonymous devices is not limited by default. The configuration option `device_limit` allows you to enforce a limit on the number of anonymous devices. This enables you to have greater control over the usage within your Grafana instance and keep the usage within the limits of your environment. Once the limit is reached, any new devices that try to access Grafana will be denied access. + +#### Anonymous users + +{{< admonition type="note" >}} +Anonymous users are charged as active users in Grafana Enterprise +{{< /admonition >}} + +#### Configuration + Example: ```bash @@ -81,17 +100,6 @@ device_limit = If you change your organization name in the Grafana UI this setting needs to be updated to match the new name. -#### Anonymous devices - -The anonymous devices feature enhances the management and monitoring of anonymous access within your Grafana instance. This feature is part of ongoing efforts to provide more control and transparency over anonymous usage. - -Users can now view anonymous usage statistics, including the count of devices and users over the last 30 days. - -- Go to **Administration -> Users** to access the anonymous devices tab. -- A new stat for the usage stats page -> Usage & Stats page shows the active anonymous devices last 30 days. - -The number of anonymous devices is not limited by default. The configuration option `device_limit` allows you to enforce a limit on the number of anonymous devices. This enables you to have greater control over the usage within your Grafana instance and keep the usage within the limits of your environment. Once the limit is reached, any new devices that try to access Grafana will be denied access. - ### Basic authentication Basic auth is enabled by default and works with the built in Grafana user password authentication system and LDAP From e74ffd58172855c83a5295cfd699489cad3b6354 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 29 Feb 2024 14:57:33 +0200 Subject: [PATCH 024/138] [v10.4.x] Tempo: Better fallbacks for metrics query (#83688) Tempo: Better fallbacks for metrics query (#83619) * Use query as fallback when there's one series and no labels. Use "" as the fallback for empty label values. Stop using the `promLabels` value from the Tempo response * Set refId to remove mentions of promLabels * Add quotes around the string value, add space after comma separator * Use name as refId when possible (cherry picked from commit 036e19037ed702bf4b63f16cc8b3b6f9d7b785db) Co-authored-by: Andre Pereira --- .../plugins/datasource/tempo/datasource.ts | 2 +- .../datasource/tempo/resultTransformer.ts | 32 ++++++++++++------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/public/app/plugins/datasource/tempo/datasource.ts b/public/app/plugins/datasource/tempo/datasource.ts index 398fd25f1857..6db96f89cdc3 100644 --- a/public/app/plugins/datasource/tempo/datasource.ts +++ b/public/app/plugins/datasource/tempo/datasource.ts @@ -677,7 +677,7 @@ export class TempoDatasource extends DataSourceWithBackend { return { - data: formatTraceQLMetrics(response.data), + data: formatTraceQLMetrics(queryValue, response.data), }; }), catchError((err) => { diff --git a/public/app/plugins/datasource/tempo/resultTransformer.ts b/public/app/plugins/datasource/tempo/resultTransformer.ts index 187c20b711a4..fd47cdd3b0fb 100644 --- a/public/app/plugins/datasource/tempo/resultTransformer.ts +++ b/public/app/plugins/datasource/tempo/resultTransformer.ts @@ -633,21 +633,31 @@ function transformToTraceData(data: TraceSearchMetadata) { } const metricsValueToString = (value: ProtoValue): string => { - return '' + (value.stringValue || value.intValue || value.doubleValue || value.boolValue || ''); + if (value.stringValue) { + return `"${value.stringValue}"`; + } + return '' + (value.intValue || value.doubleValue || value.boolValue || '""'); }; -export function formatTraceQLMetrics(data: TraceqlMetricsResponse) { - const frames = data.series.map((series) => { +export function formatTraceQLMetrics(query: string, data: TraceqlMetricsResponse) { + const frames = data.series.map((series, index) => { const labels: Labels = {}; - series.labels.forEach((label) => { + series.labels?.forEach((label) => { labels[label.key] = metricsValueToString(label.value); }); - const displayName = - series.labels.length === 1 - ? metricsValueToString(series.labels[0].value) - : `{${series.labels.map((label) => `${label.key}=${metricsValueToString(label.value)}`).join(',')}}`; + // If it's a single series, use the query as the displayName fallback + let name = data.series.length === 1 ? query : ''; + if (series.labels) { + if (series.labels.length === 1) { + // For single label series, use the label value as the displayName to improve readability + name = metricsValueToString(series.labels[0].value); + } else { + // otherwise build a string using the label keys and values + name = `{${series.labels.map((label) => `${label.key}=${metricsValueToString(label.value)}`).join(', ')}}`; + } + } return createDataFrame({ - refId: series.promLabels, + refId: name || `A${index}`, fields: [ { name: 'time', @@ -655,12 +665,12 @@ export function formatTraceQLMetrics(data: TraceqlMetricsResponse) { values: series.samples.map((sample) => parseInt(sample.timestampMs, 10)), }, { - name: series.promLabels, + name: name, labels, type: FieldType.number, values: series.samples.map((sample) => sample.value), config: { - displayNameFromDS: displayName, + displayNameFromDS: name, }, }, ], From e31e447c5e22925f1d634ae5af6145748031360b Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 29 Feb 2024 13:22:29 +0000 Subject: [PATCH 025/138] [v10.4.x] Tempo: Add template variable interpolation for filters (#83667) Tempo: Add template variable interpolation for filters (#83213) * Interpolate template variables in filters * Add tests (cherry picked from commit 1631e4130393a2ccea8159ac99e8ebf1d0a726a0) Co-authored-by: Joey <90795735+joey-grafana@users.noreply.github.com> --- .../datasource/tempo/datasource.test.ts | 29 ++++++++++++-- .../plugins/datasource/tempo/datasource.ts | 39 ++++++++++++++----- 2 files changed, 55 insertions(+), 13 deletions(-) diff --git a/public/app/plugins/datasource/tempo/datasource.test.ts b/public/app/plugins/datasource/tempo/datasource.test.ts index ac8dc49f37b9..0ed1d22114ed 100644 --- a/public/app/plugins/datasource/tempo/datasource.test.ts +++ b/public/app/plugins/datasource/tempo/datasource.test.ts @@ -93,7 +93,24 @@ describe('Tempo data source', () => { minDuration: '$interpolationVar', maxDuration: '$interpolationVar', serviceMapQuery, - filters: [], + filters: [ + { + id: 'service-name', + operator: '=', + scope: TraceqlSearchScope.Resource, + tag: 'service.name', + value: '$interpolationVarWithPipe', + valueType: 'string', + }, + { + id: 'tagId', + operator: '=', + scope: TraceqlSearchScope.Span, + tag: '$interpolationVar', + value: '$interpolationVar', + valueType: 'string', + }, + ], }; } let templateSrv: TemplateSrv; @@ -110,7 +127,7 @@ describe('Tempo data source', () => { templateSrv = initTemplateSrv([{ name: 'templateVariable1' }, { name: 'templateVariable2' }], expectedValues); }); - it('when traceId query for dashboard->explore', async () => { + it('when moving from dashboard to explore', async () => { const expectedValues = { interpolationVar: 'interpolationText', interpolationText: 'interpolationText', @@ -129,9 +146,12 @@ describe('Tempo data source', () => { expect(queries[0].minDuration).toBe(text); expect(queries[0].maxDuration).toBe(text); expect(queries[0].serviceMapQuery).toBe(text); + expect(queries[0].filters[0].value).toBe(textWithPipe); + expect(queries[0].filters[1].value).toBe(text); + expect(queries[0].filters[1].tag).toBe(text); }); - it('when traceId query for template variable', async () => { + it('when applying template variables', async () => { const scopedText = 'scopedInterpolationText'; const ds = new TempoDatasource(defaultSettings, templateSrv); const resp = ds.applyTemplateVariables(getQuery(), { @@ -144,6 +164,9 @@ describe('Tempo data source', () => { expect(resp.search).toBe(scopedText); expect(resp.minDuration).toBe(scopedText); expect(resp.maxDuration).toBe(scopedText); + expect(resp.filters[0].value).toBe(textWithPipe); + expect(resp.filters[1].value).toBe(scopedText); + expect(resp.filters[1].tag).toBe(scopedText); }); it('when serviceMapQuery is an array', async () => { diff --git a/public/app/plugins/datasource/tempo/datasource.ts b/public/app/plugins/datasource/tempo/datasource.ts index 6db96f89cdc3..c65b51fa4aea 100644 --- a/public/app/plugins/datasource/tempo/datasource.ts +++ b/public/app/plugins/datasource/tempo/datasource.ts @@ -377,9 +377,12 @@ export class TempoDatasource extends DataSourceWithBackend this.hasGroupBy(t)); - if (groupBy) { - subQueries.push(this.handleMetricsSummary(groupBy, generateQueryFromFilters(groupBy.filters), options)); + const target = targets.traceqlSearch.find((t) => this.hasGroupBy(t)); + if (target) { + const appliedQuery = this.applyVariables(target, options.scopedVars); + subQueries.push( + this.handleMetricsSummary(appliedQuery, generateQueryFromFilters(appliedQuery.filters), options) + ); } } @@ -387,25 +390,23 @@ export class TempoDatasource extends DataSourceWithBackend !this.hasGroupBy(t)) : targets.traceqlSearch; if (traceqlSearchTargets.length > 0) { - const queryValueFromFilters = generateQueryFromFilters(traceqlSearchTargets[0].filters); - - // We want to support template variables also in Search for consistency with other data sources - const queryValue = this.templateSrv.replace(queryValueFromFilters, options.scopedVars); + const appliedQuery = this.applyVariables(traceqlSearchTargets[0], options.scopedVars); + const queryValueFromFilters = generateQueryFromFilters(appliedQuery.filters); reportInteraction('grafana_traces_traceql_search_queried', { datasourceType: 'tempo', app: options.app ?? '', grafana_version: config.buildInfo.version, - query: queryValue ?? '', + query: queryValueFromFilters ?? '', streaming: config.featureToggles.traceQLStreaming, }); if (config.featureToggles.traceQLStreaming && this.isFeatureAvailable(FeatureName.streaming)) { - subQueries.push(this.handleStreamingSearch(options, traceqlSearchTargets, queryValue)); + subQueries.push(this.handleStreamingSearch(options, traceqlSearchTargets, queryValueFromFilters)); } else { subQueries.push( this._request('/api/search', { - q: queryValue, + q: queryValueFromFilters, limit: options.targets[0].limit ?? DEFAULT_LIMIT, spss: options.targets[0].spss ?? DEFAULT_SPSS, start: options.range.from.unix(), @@ -522,6 +523,24 @@ export class TempoDatasource extends DataSourceWithBackend { + const updatedFilter = { + ...filter, + tag: this.templateSrv.replace(filter.tag ?? '', scopedVars), + }; + + if (filter.value) { + updatedFilter.value = + typeof filter.value === 'string' + ? this.templateSrv.replace(filter.value ?? '', scopedVars, VariableFormatID.Pipe) + : filter.value.map((v) => this.templateSrv.replace(v ?? '', scopedVars, VariableFormatID.Pipe)); + } + + return updatedFilter; + }); + } + return { ...expandedQuery, query: this.templateSrv.replace(query.query ?? '', scopedVars, VariableFormatID.Pipe), From 14982f109571badae291518a9195de528cb4142e Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 29 Feb 2024 09:34:27 -0500 Subject: [PATCH 026/138] [v10.4.x] Docs: restructure Configure panel options (#83655) Docs: restructure Configure panel options (#83438) * Moved view json panel content from configure panel options to panel inspect view * Converted add title and description task to reference section * Removed edit panel section * Updated bullet list to match content * Removed view json content to be integrated later * Ran prettier * Docs: Edit Configure panel options (#83439) * Updated intro * Updated intro, descriptions, and repeating panels task * Reformatted sections of task and updated wording of LLM info * Copy edits * Added Cloud links and updated version syntax * Fixed link * Fixed formatting and removed vestigial sentence (cherry picked from commit 2c95782b101db95d9e4deac29032ec5d987617f7) Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --- .../configure-panel-options/index.md | 119 ++++++------------ 1 file changed, 37 insertions(+), 82 deletions(-) diff --git a/docs/sources/panels-visualizations/configure-panel-options/index.md b/docs/sources/panels-visualizations/configure-panel-options/index.md index e6946c8567d1..72483d4e456e 100644 --- a/docs/sources/panels-visualizations/configure-panel-options/index.md +++ b/docs/sources/panels-visualizations/configure-panel-options/index.md @@ -25,111 +25,66 @@ weight: 50 # Configure panel options -A Grafana panel is a visual representation of data that you can customize by defining a data source query, transforming and formatting data, and configuring visualization settings. +There are settings common to all visualizations, which you set in the **Panel options** section of the panel editor pane. The following sections describe these options as well as how to set them. -A panel editor includes a query builder and a series of options that you can use to transform data and add information to your panels. +## Panel options -This topic describes how to: +Set the following options to provide basic information about a panel and define basic display elements: -- Open a panel for editing -- Add a panel title and description -- View a panel JSON model -- Configure repeating rows and panels +| Option | Description | +| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Title | Text entered in this field appears at the top of your panel in the panel editor and in the dashboard. You can use [variables you have defined][] in the **Title** field, but not [global variables][]. | +| Description | Text entered in this field appears in a tooltip in the upper-left corner of the panel. Add a description to a panel to share with users any important information about it, such as its purpose. You can use [variables you have defined][] in the **Description** field, but not [global variables][]. | +| Transparent background | Toggle this switch on and off to control whether or not the panel has the same background color as the dashboard. | +| Panel links | Add [links to the panel][] to create shortcuts to other dashboards, panels, and external websites. Access panel links by clicking the icon next to the panel title. | +| Repeat options | Set whether to repeat the panel for each value in the selected variable. For more information, refer to [Configure repeating panels](#configure-repeating-panels). | -## Edit a panel - -After you add a panel to a dashboard, you can open it at any time to change or update queries, add data transformation, and change visualization settings. - -1. Open the dashboard that contains the panel you want to edit. - -1. Hover over any part of the panel to display the actions menu on the top right corner. - -1. Click the menu and select **Edit**. - - ![Panel with menu displayed](/media/docs/grafana/screenshot-panel-menu.png) - - To use a keyboard shortcut to open the panel, hover over the panel and press `e`. - - The panel opens in edit mode. - -## Add a title and description to a panel - -You can use generative AI to create panel titles and descriptions with the [Grafana LLM plugin][], which is currently in public preview. To enable this, refer to the [Set up generative AI features for dashboards documentation][]. Alternatively, you can take the following steps to create them yourself. - -Add a title and description to a panel to share with users any important information about the visualization. For example, use the description to document the purpose of the visualization. - -1. [Edit a panel](#edit-a-panel). - -1. In the panel display options pane, locate the **Panel options** section. - -1. Enter a **Title**. - - Text entered in this field appears at the top of your panel in the panel editor and in the dashboard. - -1. Write a description of the panel and the data you are displaying. - - Text entered in this field appears in a tooltip in the upper-left corner of the panel. - - You can use [variables you have defined][] in the **Title** and **Description** field, but not [global variables][]. - - ![Panel editor pane with Panel options section expanded](/static/img/docs/panels/panel-options-8-0.png) - -## View a panel JSON model - -Explore and export panel, panel data, and data frame JSON models. - -1. Open the dashboard that contains the panel. - -1. Hover over any part of the panel to display the actions menu on the top right corner. -1. Click the menu and select **Inspect > Panel JSON**. -1. In the **Select source** field, select one of the following options: - - - **Panel JSON:** Displays a JSON object representing the panel. - - **Panel data:** Displays a JSON object representing the data that was passed to the panel. - - **DataFrame structure:** Displays the data structure of the panel, including any transformations, field configurations, and override configurations that have been applied. - -1. To explore the JSON, click `>` to expand or collapse portions of the JSON model. +You can use generative AI to populate the **Title** and **Description** fields with the [Grafana LLM plugin][], which is currently in public preview. To enable this, refer to [Set up generative AI features for dashboards][]. ## Configure repeating panels You can configure Grafana to dynamically add panels or rows to a dashboard. A dynamic panel is a panel that the system creates based on the value of a variable. Variables dynamically change your queries across all panels in a dashboard. For more information about repeating rows, refer to [Configure repeating rows][]. -{{% admonition type="note" %}} -Repeating panels require variables to have one or more items selected; you can't repeat a panel zero times to hide it. -{{% /admonition %}} - To see an example of repeating panels, refer to [this dashboard with repeating panels](https://play.grafana.org/d/testdata-repeating/testdata-repeating-panels?orgId=1). **Before you begin:** - Ensure that the query includes a multi-value variable. -**To configure repeating panels:** - -1. [Edit the panel](#edit-a-panel) you want to repeat. - -1. On the display options pane, click **Panel options > Repeat options**. +To configure repeating panels, follow these steps: -1. Select a `direction`. +1. Navigate to the panel you want to update. +1. Hover over any part of the panel to display the menu on the top right corner. +1. Click the menu and select **Edit**. +1. Open the **Panel options** section of the panel editor pane. +1. Under **Repeat options**, select a variable in the **Repeat by variable** drop-down list. +1. Under **Repeat direction**, choose one of the following: - - Choose `horizontal` to arrange panels side-by-side. Grafana adjusts the width of a repeated panel. Currently, you can't mix other panels on a row with a repeated panel. - - Choose `vertical` to arrange panels in a column. The width of repeated panels is the same as the original, repeated panel. + - **Horizontal** - Arrange panels side-by-side. Grafana adjusts the width of a repeated panel. You can't mix other panels on a row with a repeated panel. + - **Vertical** - Arrange panels in a column. The width of repeated panels is the same as the original, repeated panel. +1. If you selected **Horizontal** in the previous step, select a value in the **Max per row** drop-down list to control the maximum number of panels that can be in a row. +1. Click **Save**. 1. To propagate changes to all panels, reload the dashboard. +You can stop a panel from repeating by selecting **Disable repeating** in the **Repeat by variable** drop-down list. + {{% docs/reference %}} -[variables you have defined]: "/docs/grafana/ -> /docs/grafana//dashboards/variables" -[variables you have defined]: "/docs/grafana-cloud/ -> /docs/grafana//dashboards/variables" +[variables you have defined]: "/docs/grafana/ -> /docs/grafana//dashboards/variables" +[variables you have defined]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/variables" + +[global variables]: "/docs/grafana/ -> /docs/grafana//dashboards/variables/add-template-variables#global-variables" +[global variables]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/variables/add-template-variables#global-variables" -[global variables]: "/docs/grafana/ -> /docs/grafana//dashboards/variables/add-template-variables#global-variables" -[global variables]: "/docs/grafana-cloud/ -> /docs/grafana//dashboards/variables/add-template-variables#global-variables" +[Configure repeating rows]: "/docs/grafana/ -> /docs/grafana//dashboards/build-dashboards/create-dashboard#configure-repeating-rows" +[Configure repeating rows]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/build-dashboards/create-dashboard#configure-repeating-rows" -[Configure repeating rows]: "/docs/grafana/ -> /docs/grafana//dashboards/build-dashboards/create-dashboard#configure-repeating-rows" -[Configure repeating rows]: "/docs/grafana-cloud/ -> /docs/grafana//dashboards/build-dashboards/create-dashboard#configure-repeating-rows" +[Grafana LLM plugin]: "/docs/grafana/ -> /docs/grafana-cloud/alerting-and-irm/machine-learning/configure/llm-plugin" +[Grafana LLM plugin]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/machine-learning/configure/llm-plugin" -[Grafana LLM plugin]: "/docs/grafana/ -> /docs/grafana-cloud/alerting-and-irm/machine-learning/llm-plugin" -[Grafana LLM plugin]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/machine-learning/llm-plugin" +[Set up generative AI features for dashboards]: "/docs/grafana/ -> /docs/grafana//dashboards/manage-dashboards#set-up-generative-ai-features-for-dashboards" +[Set up generative AI features for dashboards]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/manage-dashboards#set-up-generative-ai-features-for-dashboards" -[Set up generative AI features for dashboards documentation]: "/docs/grafana/ -> /docs/grafana//dashboards/manage-dashboards#set-up-generative-ai-features-for-dashboards" -[Set up generative AI features for dashboards documentation]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/manage-dashboards#set-up-generative-ai-features-for-dashboards" +[links to the panel]: "/docs/grafana/ -> /docs/grafana//dashboards/build-dashboards/manage-dashboard-links#panel-links" +[links to the panel]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/build-dashboards/manage-dashboard-links#panel-links" {{% /docs/reference %}} From 6263884192bee3748ac2171918e91ad189dff65b Mon Sep 17 00:00:00 2001 From: Andreas Christou Date: Thu, 29 Feb 2024 18:34:08 +0000 Subject: [PATCH 027/138] [v10.4.x] CI: Bump `alpine` image version (#83723) CI: Bump `alpine` image version (#83716) Bump image version (cherry picked from commit c9d8d8713b6046024f33a527427a47674b754255) --- .drone.yml | 70 ++++++++++++++++----------------- scripts/drone/utils/images.star | 2 +- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/.drone.yml b/.drone.yml index 5b8437b52aa0..8a5b62dba71c 100644 --- a/.drone.yml +++ b/.drone.yml @@ -18,7 +18,7 @@ services: [] steps: - commands: - echo $DRONE_RUNNER_NAME - image: alpine:3.18.5 + image: alpine:3.19.1 name: identify-runner - commands: - go build -o ./bin/build -ldflags '-extldflags -static' ./pkg/build/cmd @@ -69,7 +69,7 @@ services: [] steps: - commands: - echo $DRONE_RUNNER_NAME - image: alpine:3.18.5 + image: alpine:3.19.1 name: identify-runner - commands: - go build -o ./bin/build -ldflags '-extldflags -static' ./pkg/build/cmd @@ -120,7 +120,7 @@ services: [] steps: - commands: - echo $DRONE_RUNNER_NAME - image: alpine:3.18.5 + image: alpine:3.19.1 name: identify-runner - commands: - apk add --update g++ make python3 && ln -sf /usr/bin/python3 /usr/bin/python @@ -222,7 +222,7 @@ steps: name: clone-enterprise - commands: - echo $DRONE_RUNNER_NAME - image: alpine:3.18.5 + image: alpine:3.19.1 name: identify-runner - commands: - apk add --update g++ make python3 && ln -sf /usr/bin/python3 /usr/bin/python @@ -313,7 +313,7 @@ steps: name: clone-enterprise - commands: - echo $DRONE_RUNNER_NAME - image: alpine:3.18.5 + image: alpine:3.19.1 name: identify-runner - commands: - '# It is required that code generated from Thema/CUE be committed and in sync @@ -399,7 +399,7 @@ services: [] steps: - commands: - echo $DRONE_RUNNER_NAME - image: alpine:3.18.5 + image: alpine:3.19.1 name: identify-runner - commands: - go build -o ./bin/build -ldflags '-extldflags -static' ./pkg/build/cmd @@ -495,7 +495,7 @@ services: [] steps: - commands: - echo $DRONE_RUNNER_NAME - image: alpine:3.18.5 + image: alpine:3.19.1 name: identify-runner - commands: - mkdir -p bin @@ -593,7 +593,7 @@ steps: GF_APP_MODE: development GF_SERVER_HTTP_PORT: "3001" GF_SERVER_ROUTER_LOGGING: "1" - image: alpine:3.18.5 + image: alpine:3.19.1 name: grafana-server - commands: - ./bin/build e2e-tests --port 3001 --suite dashboards-suite @@ -718,7 +718,7 @@ steps: - /src/grafana-build artifacts -a docker:grafana:linux/amd64 -a docker:grafana:linux/amd64:ubuntu -a docker:grafana:linux/arm64 -a docker:grafana:linux/arm64:ubuntu -a docker:grafana:linux/arm/v7 -a docker:grafana:linux/arm/v7:ubuntu --yarn-cache=$$YARN_CACHE_FOLDER --build-id=$$DRONE_BUILD_NUMBER - --go-version=1.21.6 --ubuntu-base=ubuntu:22.04 --alpine-base=alpine:3.18.5 --tag-format='{{ + --go-version=1.21.6 --ubuntu-base=ubuntu:22.04 --alpine-base=alpine:3.19.1 --tag-format='{{ .version_base }}-{{ .buildID }}-{{ .arch }}' --grafana-dir=$$PWD --ubuntu-tag-format='{{ .version_base }}-{{ .buildID }}-ubuntu-{{ .arch }}' > docker.txt - find ./dist -name '*docker*.tar.gz' -type f | xargs -n1 docker load -i @@ -866,7 +866,7 @@ steps: name: compile-build-cmd - commands: - echo $DRONE_RUNNER_NAME - image: alpine:3.18.5 + image: alpine:3.19.1 name: identify-runner - commands: - '# It is required that code generated from Thema/CUE be committed and in sync @@ -1052,7 +1052,7 @@ services: [] steps: - commands: - echo $DRONE_RUNNER_NAME - image: alpine:3.18.5 + image: alpine:3.19.1 name: identify-runner - commands: - apk add --update g++ make python3 && ln -sf /usr/bin/python3 /usr/bin/python @@ -1412,7 +1412,7 @@ services: [] steps: - commands: - echo $DRONE_RUNNER_NAME - image: alpine:3.18.5 + image: alpine:3.19.1 name: identify-runner - commands: - apk add --update g++ make python3 && ln -sf /usr/bin/python3 /usr/bin/python @@ -1489,7 +1489,7 @@ services: [] steps: - commands: - echo $DRONE_RUNNER_NAME - image: alpine:3.18.5 + image: alpine:3.19.1 name: identify-runner - commands: - apk add --update g++ make python3 && ln -sf /usr/bin/python3 /usr/bin/python @@ -1548,7 +1548,7 @@ services: [] steps: - commands: - echo $DRONE_RUNNER_NAME - image: alpine:3.18.5 + image: alpine:3.19.1 name: identify-runner - commands: - apk add --update g++ make python3 && ln -sf /usr/bin/python3 /usr/bin/python @@ -1617,7 +1617,7 @@ services: [] steps: - commands: - echo $DRONE_RUNNER_NAME - image: alpine:3.18.5 + image: alpine:3.19.1 name: identify-runner - commands: - '# It is required that code generated from Thema/CUE be committed and in sync @@ -1697,7 +1697,7 @@ services: [] steps: - commands: - echo $DRONE_RUNNER_NAME - image: alpine:3.18.5 + image: alpine:3.19.1 name: identify-runner - commands: - go build -o ./bin/build -ldflags '-extldflags -static' ./pkg/build/cmd @@ -1772,7 +1772,7 @@ services: [] steps: - commands: - echo $DRONE_RUNNER_NAME - image: alpine:3.18.5 + image: alpine:3.19.1 name: identify-runner - commands: - mkdir -p bin @@ -1869,7 +1869,7 @@ steps: GF_APP_MODE: development GF_SERVER_HTTP_PORT: "3001" GF_SERVER_ROUTER_LOGGING: "1" - image: alpine:3.18.5 + image: alpine:3.19.1 name: grafana-server - commands: - ./bin/build e2e-tests --port 3001 --suite dashboards-suite @@ -2030,7 +2030,7 @@ steps: - /src/grafana-build artifacts -a docker:grafana:linux/amd64 -a docker:grafana:linux/amd64:ubuntu -a docker:grafana:linux/arm64 -a docker:grafana:linux/arm64:ubuntu -a docker:grafana:linux/arm/v7 -a docker:grafana:linux/arm/v7:ubuntu --yarn-cache=$$YARN_CACHE_FOLDER --build-id=$$DRONE_BUILD_NUMBER - --go-version=1.21.6 --ubuntu-base=ubuntu:22.04 --alpine-base=alpine:3.18.5 --tag-format='{{ + --go-version=1.21.6 --ubuntu-base=ubuntu:22.04 --alpine-base=alpine:3.19.1 --tag-format='{{ .version_base }}-{{ .buildID }}-{{ .arch }}' --grafana-dir=$$PWD --ubuntu-tag-format='{{ .version_base }}-{{ .buildID }}-ubuntu-{{ .arch }}' > docker.txt - find ./dist -name '*docker*.tar.gz' -type f | xargs -n1 docker load -i @@ -2240,7 +2240,7 @@ steps: name: compile-build-cmd - commands: - echo $DRONE_RUNNER_NAME - image: alpine:3.18.5 + image: alpine:3.19.1 name: identify-runner - commands: - '# It is required that code generated from Thema/CUE be committed and in sync @@ -2555,7 +2555,7 @@ services: [] steps: - commands: - echo $DRONE_RUNNER_NAME - image: alpine:3.18.5 + image: alpine:3.19.1 name: identify-runner - commands: - mkdir -p bin @@ -2892,7 +2892,7 @@ steps: environment: _EXPERIMENTAL_DAGGER_CLOUD_TOKEN: from_secret: dagger_token - ALPINE_BASE: alpine:3.18.5 + ALPINE_BASE: alpine:3.19.1 CDN_DESTINATION: from_secret: rgm_cdn_destination DESTINATION: @@ -3009,7 +3009,7 @@ services: [] steps: - commands: - echo $DRONE_RUNNER_NAME - image: alpine:3.18.5 + image: alpine:3.19.1 name: identify-runner - commands: - apk add --update g++ make python3 && ln -sf /usr/bin/python3 /usr/bin/python @@ -3066,7 +3066,7 @@ services: [] steps: - commands: - echo $DRONE_RUNNER_NAME - image: alpine:3.18.5 + image: alpine:3.19.1 name: identify-runner - commands: - '# It is required that code generated from Thema/CUE be committed and in sync @@ -3148,7 +3148,7 @@ steps: environment: _EXPERIMENTAL_DAGGER_CLOUD_TOKEN: from_secret: dagger_token - ALPINE_BASE: alpine:3.18.5 + ALPINE_BASE: alpine:3.19.1 CDN_DESTINATION: from_secret: rgm_cdn_destination DESTINATION: @@ -3331,7 +3331,7 @@ steps: environment: _EXPERIMENTAL_DAGGER_CLOUD_TOKEN: from_secret: dagger_token - ALPINE_BASE: alpine:3.18.5 + ALPINE_BASE: alpine:3.19.1 CDN_DESTINATION: from_secret: rgm_cdn_destination DESTINATION: @@ -3433,7 +3433,7 @@ services: [] steps: - commands: - echo $DRONE_RUNNER_NAME - image: alpine:3.18.5 + image: alpine:3.19.1 name: identify-runner - commands: - apk add --update g++ make python3 && ln -sf /usr/bin/python3 /usr/bin/python @@ -3488,7 +3488,7 @@ services: [] steps: - commands: - echo $DRONE_RUNNER_NAME - image: alpine:3.18.5 + image: alpine:3.19.1 name: identify-runner - commands: - '# It is required that code generated from Thema/CUE be committed and in sync @@ -3568,7 +3568,7 @@ steps: environment: _EXPERIMENTAL_DAGGER_CLOUD_TOKEN: from_secret: dagger_token - ALPINE_BASE: alpine:3.18.5 + ALPINE_BASE: alpine:3.19.1 CDN_DESTINATION: from_secret: rgm_cdn_destination DESTINATION: @@ -3715,7 +3715,7 @@ steps: environment: _EXPERIMENTAL_DAGGER_CLOUD_TOKEN: from_secret: dagger_token - ALPINE_BASE: alpine:3.18.5 + ALPINE_BASE: alpine:3.19.1 CDN_DESTINATION: from_secret: rgm_cdn_destination DESTINATION: @@ -3824,7 +3824,7 @@ steps: environment: _EXPERIMENTAL_DAGGER_CLOUD_TOKEN: from_secret: dagger_token - ALPINE_BASE: alpine:3.18.5 + ALPINE_BASE: alpine:3.19.1 CDN_DESTINATION: from_secret: rgm_cdn_destination DESTINATION: @@ -4027,7 +4027,7 @@ steps: name: grabpl - commands: - echo $DRONE_RUNNER_NAME - image: alpine:3.18.5 + image: alpine:3.19.1 name: identify-runner - commands: - '# It is required that code generated from Thema/CUE be committed and in sync @@ -4520,7 +4520,7 @@ steps: - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM node:20.9.0-alpine - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM google/cloud-sdk:431.0.0 - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM grafana/grafana-ci-deploy:1.3.3 - - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM alpine:3.18.5 + - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM alpine:3.19.1 - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM ubuntu:22.04 - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM byrnedo/alpine-curl:0.1.8 - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM plugins/slack @@ -4554,7 +4554,7 @@ steps: - trivy --exit-code 1 --severity HIGH,CRITICAL node:20.9.0-alpine - trivy --exit-code 1 --severity HIGH,CRITICAL google/cloud-sdk:431.0.0 - trivy --exit-code 1 --severity HIGH,CRITICAL grafana/grafana-ci-deploy:1.3.3 - - trivy --exit-code 1 --severity HIGH,CRITICAL alpine:3.18.5 + - trivy --exit-code 1 --severity HIGH,CRITICAL alpine:3.19.1 - trivy --exit-code 1 --severity HIGH,CRITICAL ubuntu:22.04 - trivy --exit-code 1 --severity HIGH,CRITICAL byrnedo/alpine-curl:0.1.8 - trivy --exit-code 1 --severity HIGH,CRITICAL plugins/slack @@ -4804,6 +4804,6 @@ kind: secret name: gcr_credentials --- kind: signature -hmac: 2a70d8442b85841e1b882c9562e8cc42b0c4b697a49ee03d086218f79cdff660 +hmac: b26b23c44efb37e0868731724ff9c86471347f942e6281c011f83830bfe4517f ... diff --git a/scripts/drone/utils/images.star b/scripts/drone/utils/images.star index 59068896df34..d229f997ccfe 100644 --- a/scripts/drone/utils/images.star +++ b/scripts/drone/utils/images.star @@ -14,7 +14,7 @@ images = { "node": "node:{}-alpine".format(nodejs_version), "cloudsdk": "google/cloud-sdk:431.0.0", "publish": "grafana/grafana-ci-deploy:1.3.3", - "alpine": "alpine:3.18.5", + "alpine": "alpine:3.19.1", "ubuntu": "ubuntu:22.04", "curl": "byrnedo/alpine-curl:0.1.8", "plugins_slack": "plugins/slack", From 676fd4c08ee7d879d53e772457b1cfb14fbad524 Mon Sep 17 00:00:00 2001 From: Jack Baldry Date: Thu, 29 Feb 2024 18:40:03 +0000 Subject: [PATCH 028/138] [v10.4.x] Fix typos (#83682) * Fix typos (#83621) Co-authored-by: Isabel Matwawana Co-authored-by: Jack Baldry (cherry picked from commit 2a429cd7db84d2783311b81c6334260107922fce) Signed-off-by: Jack Baldry * Fixed typo --------- Signed-off-by: Jack Baldry Co-authored-by: omahs <73983677+omahs@users.noreply.github.com> Co-authored-by: Isabel Matwawana --- .github/bot.md | 4 +-- contribute/style-guides/frontend.md | 2 +- .../file-provisioning/index.md | 2 +- .../dashboards/use-dashboards/index.md | 2 +- .../aws-authentication/index.md | 2 +- .../azure-monitor/query-editor/index.md | 24 ++++++++-------- .../developers/http_api/access_control.md | 28 +++++++++---------- .../configure-legend/index.md | 2 +- .../datasources/tempo-search-traceql.md | 2 +- .../visualizations/connect-null-values.md | 4 +-- .../visualizations/disconnect-values.md | 2 +- 11 files changed, 37 insertions(+), 37 deletions(-) diff --git a/.github/bot.md b/.github/bot.md index ec745bcf93aa..9477ab291e27 100644 --- a/.github/bot.md +++ b/.github/bot.md @@ -9,8 +9,8 @@ Comment commands: Label commands: -* Add label `bot/question` the the bot will close with standard question message and add label `type/question` -* Add label `bot/duplicate` the the bot will close with standard duplicate message and add label `type/duplicate` +* Add label `bot/question` the bot will close with standard question message and add label `type/question` +* Add label `bot/duplicate` the bot will close with standard duplicate message and add label `type/duplicate` * Add label `bot/needs more info` for bot to request more info (or use comment command mentioned above) * Add label `bot/close feature request` for bot to close a feature request with standard message and adds label `not implemented` * Add label `bot/no new info` for bot to close an issue where we asked for more info but has not received any updates in at least 14 days. diff --git a/contribute/style-guides/frontend.md b/contribute/style-guides/frontend.md index c25b671a8924..07055362fffc 100644 --- a/contribute/style-guides/frontend.md +++ b/contribute/style-guides/frontend.md @@ -180,7 +180,7 @@ const getStyles = (theme: GrafanaTheme2) => ({ }); ``` -Use hook useStyles2(getStyles) to memoize the styles generation and try to avoid passing props to the the getStyles function and instead compose classes using emotion cx function. +Use hook useStyles2(getStyles) to memoize the styles generation and try to avoid passing props to the getStyles function and instead compose classes using emotion cx function. #### Use `ALL_CAPS` for constants. diff --git a/docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md b/docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md index b817314bbf38..22066714f5fd 100644 --- a/docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md +++ b/docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md @@ -685,7 +685,7 @@ templates: - orgId: 1 # name of the template, must be unique name: my_first_template - # content of the the template + # content of the template template: Alerting with a custom text template ``` diff --git a/docs/sources/dashboards/use-dashboards/index.md b/docs/sources/dashboards/use-dashboards/index.md index baf5ad1a62f1..9bb1f9f52e35 100644 --- a/docs/sources/dashboards/use-dashboards/index.md +++ b/docs/sources/dashboards/use-dashboards/index.md @@ -197,7 +197,7 @@ Click the **Copy time range to clipboard** icon to copy the current time range t -You can also copy and paste a time range using the the keyboard shortcuts `t+c` and `t+v` respectively. +You can also copy and paste a time range using the keyboard shortcuts `t+c` and `t+v` respectively. #### Zoom out (Cmd+Z or Ctrl+Z) diff --git a/docs/sources/datasources/aws-cloudwatch/aws-authentication/index.md b/docs/sources/datasources/aws-cloudwatch/aws-authentication/index.md index f59b6493bdde..78d0021b2c67 100644 --- a/docs/sources/datasources/aws-cloudwatch/aws-authentication/index.md +++ b/docs/sources/datasources/aws-cloudwatch/aws-authentication/index.md @@ -159,7 +159,7 @@ To use the Grafana Assume Role: 1. Put in a request to Customer Support to enable`awsDatasourcesTempCredentials`. 2. Once the feature is enabled, create a new CloudWatch data source (or update an existing one) and select **Grafana Assume Role** as an authentication provider. 3. In the AWS Console, create a new IAM role, and under **Trusted entity type**, select **Another AWS account** as the trusted Entity. -4. Enter Grafana's account id (displayed in the instructions box on the the **Settings** tab of the CloudWatch data source configuration) and check the **Require external ID** box. +4. Enter Grafana's account id (displayed in the instructions box on the **Settings** tab of the CloudWatch data source configuration) and check the **Require external ID** box. 5. Enter the external ID specified in the instructions box on the **Settings** tab of the CloudWatch data source configuration in Grafana. This external ID will be unique to your Grafana instance. 6. Attach any required permissions you would like Grafana to be able to access on your behalf (for example, CloudWatch Logs and CloudWatch Metrics policies). 7. Give the role a name and description, and click **Create role**. diff --git a/docs/sources/datasources/azure-monitor/query-editor/index.md b/docs/sources/datasources/azure-monitor/query-editor/index.md index b7be89e709c5..7a27d2a2c6f1 100644 --- a/docs/sources/datasources/azure-monitor/query-editor/index.md +++ b/docs/sources/datasources/azure-monitor/query-editor/index.md @@ -86,17 +86,17 @@ For example: - `Blob Type: {{ blobtype }}` becomes `Blob Type: PageBlob`, `Blob Type: BlockBlob` - `{{ resourcegroup }} - {{ resourcename }}` becomes `production - web_server` -| Alias pattern | Description | -| ----------------------------- | ------------------------------------------------------------------------------------------------------ | -| `{{ subscriptionid }}` | Replaced with the subscription ID. | -| `{{ subscription }}` | Replaced with the subscription name. | -| `{{ resourcegroup }}` | Replaced with the the resource group. | -| `{{ namespace }}` | Replaced with the resource type or namespace, such as `Microsoft.Compute/virtualMachines`. | -| `{{ resourcename }}` | Replaced with the resource name. | -| `{{ metric }}` | Replaced with the metric name, such as "Percentage CPU". | -| _`{{ arbitaryDimensionID }}`_ | Replaced with the value of the specified dimension. For example, `{{ blobtype }}` becomes `BlockBlob`. | -| `{{ dimensionname }}` | _(Legacy for backward compatibility)_ Replaced with the name of the first dimension. | -| `{{ dimensionvalue }}` | _(Legacy for backward compatibility)_ Replaced with the value of the first dimension. | +| Alias pattern | Description | +| ------------------------------ | ------------------------------------------------------------------------------------------------------ | +| `{{ subscriptionid }}` | Replaced with the subscription ID. | +| `{{ subscription }}` | Replaced with the subscription name. | +| `{{ resourcegroup }}` | Replaced with the resource group. | +| `{{ namespace }}` | Replaced with the resource type or namespace, such as `Microsoft.Compute/virtualMachines`. | +| `{{ resourcename }}` | Replaced with the resource name. | +| `{{ metric }}` | Replaced with the metric name, such as "Percentage CPU". | +| _`{{ arbitraryDimensionID }}`_ | Replaced with the value of the specified dimension. For example, `{{ blobtype }}` becomes `BlockBlob`. | +| `{{ dimensionname }}` | _(Legacy for backward compatibility)_ Replaced with the name of the first dimension. | +| `{{ dimensionvalue }}` | _(Legacy for backward compatibility)_ Replaced with the value of the first dimension. | ### Filter using dimensions @@ -106,7 +106,7 @@ Grafana can display and filter metrics based on dimension values. The data source supports the `equals`, `not equals`, and `starts with` operators as detailed in the [Monitor Metrics API documentation](https://docs.microsoft.com/en-us/rest/api/monitor/metrics/list). -For more information onmulti-dimensional metrics, refer to the [Azure Monitor data platform metrics documentation](https://docs.microsoft.com/en-us/azure/azure-monitor/essentials/data-platform-metrics#multi-dimensional-metrics) and [Azure Monitor filtering documentation](https://docs.microsoft.com/en-us/azure/azure-monitor/essentials/metrics-charts#filters). +For more information on multi-dimensional metrics, refer to the [Azure Monitor data platform metrics documentation](https://docs.microsoft.com/en-us/azure/azure-monitor/essentials/data-platform-metrics#multi-dimensional-metrics) and [Azure Monitor filtering documentation](https://docs.microsoft.com/en-us/azure/azure-monitor/essentials/metrics-charts#filters). ## Query Azure Monitor Logs diff --git a/docs/sources/developers/http_api/access_control.md b/docs/sources/developers/http_api/access_control.md index 695f8d129e66..72c5aec8a767 100644 --- a/docs/sources/developers/http_api/access_control.md +++ b/docs/sources/developers/http_api/access_control.md @@ -383,12 +383,12 @@ Content-Type: application/json #### Status codes -| Code | Description | -| ---- | ------------------------------------------------------------------------------------- | -| 200 | Role is updated. | -| 400 | Bad request (invalid json, missing content-type, missing or invalid fields, etc.). | -| 403 | Access denied (one of the specified permissions is not assigned to the the requester) | -| 500 | Unexpected error. Refer to body and/or server logs for more details. | +| Code | Description | +| ---- | ---------------------------------------------------------------------------------- | +| 200 | Role is updated. | +| 400 | Bad request (invalid json, missing content-type, missing or invalid fields, etc.). | +| 403 | Access denied (one of the specified permissions is not assigned to the requester) | +| 500 | Unexpected error. Refer to body and/or server logs for more details. | ### Update a role @@ -498,13 +498,13 @@ For more information, refer to [Create role validation errors]({{< ref "#create- #### Status codes -| Code | Description | -| ---- | ------------------------------------------------------------------------------------- | -| 200 | Role is updated. | -| 400 | Bad request (invalid json, missing content-type, missing or invalid fields, etc.). | -| 403 | Access denied (one of the specified permissions is not assigned to the the requester) | -| 404 | Role was not found to update. | -| 500 | Unexpected error. Refer to body and/or server logs for more details. | +| Code | Description | +| ---- | ---------------------------------------------------------------------------------- | +| 200 | Role is updated. | +| 400 | Bad request (invalid json, missing content-type, missing or invalid fields, etc.). | +| 403 | Access denied (one of the specified permissions is not assigned to the requester) | +| 404 | Role was not found to update. | +| 500 | Unexpected error. Refer to body and/or server logs for more details. | ### Delete a custom role @@ -532,7 +532,7 @@ Accept: application/json | Param | Type | Required | Description | | ------ | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| force | boolean | No | When set to `true`, the role will be deleted with all it's assignments. | +| force | boolean | No | When set to `true`, the role will be deleted with all its assignments. | | global | boolean | No | A flag indicating if the role is global or not. If set to false, the default org ID of the authenticated user will be used from the request. Refer to the [About RBAC]({{< relref "/docs/grafana/latest/administration/roles-and-permissions/access-control" >}}) for more information. | #### Example response diff --git a/docs/sources/panels-visualizations/configure-legend/index.md b/docs/sources/panels-visualizations/configure-legend/index.md index 49c29959d4f8..fb2617940668 100644 --- a/docs/sources/panels-visualizations/configure-legend/index.md +++ b/docs/sources/panels-visualizations/configure-legend/index.md @@ -30,7 +30,7 @@ Legends are supported for the following visualizations: - [Trend][trend] -[Geomaps][] and [heatmaps][] also have legends, but they only provide the the choice to display or not display a legend and don't support other legend options. +[Geomaps][] and [heatmaps][] also have legends, but they only provide the choice to display or not display a legend and don't support other legend options. ## Legend options diff --git a/docs/sources/shared/datasources/tempo-search-traceql.md b/docs/sources/shared/datasources/tempo-search-traceql.md index 671f91fc0912..64ff336aa612 100644 --- a/docs/sources/shared/datasources/tempo-search-traceql.md +++ b/docs/sources/shared/datasources/tempo-search-traceql.md @@ -118,7 +118,7 @@ For additional information, refer to [Traces to metrics: Ad-hoc RED metrics in G When you use **Aggregate by**, the selections you make determine how the information is reported in the Table. Every combination that matches selections in your data is listed in the table. Each aggregate value, for example `intrinsic`:`name`, has a corresponding column in the results table. -For example, **names** matching `GET /:endpoint` with a **span.http.user_agent** of `k6/0.46` appeared in 31,466 spans. Instead of being listed by traces and associated spans, the query results are grouped by the the selections in **Aggregate by**. +For example, **names** matching `GET /:endpoint` with a **span.http.user_agent** of `k6/0.46` appeared in 31,466 spans. Instead of being listed by traces and associated spans, the query results are grouped by the selections in **Aggregate by**. The RED metrics are calculated for every name and user agent combination found in your data. diff --git a/docs/sources/shared/visualizations/connect-null-values.md b/docs/sources/shared/visualizations/connect-null-values.md index 4336568cd399..66fa2d507aca 100644 --- a/docs/sources/shared/visualizations/connect-null-values.md +++ b/docs/sources/shared/visualizations/connect-null-values.md @@ -8,6 +8,6 @@ Choose how null values, which are gaps in the data, appear on the graph. Null va ![Connect null values option](/static/img/docs/time-series-panel/connect-null-values-option-v9.png) -- **Never:** Time series data points with gaps in the the data are never connected. -- **Always:** Time series data points with gaps in the the data are always connected. +- **Never:** Time series data points with gaps in the data are never connected. +- **Always:** Time series data points with gaps in the data are always connected. - **Threshold:** Specify a threshold above which gaps in the data are no longer connected. This can be useful when the connected gaps in the data are of a known size and/or within a known range, and gaps outside this range should no longer be connected. diff --git a/docs/sources/shared/visualizations/disconnect-values.md b/docs/sources/shared/visualizations/disconnect-values.md index 63e6472c3636..1888102d7e85 100644 --- a/docs/sources/shared/visualizations/disconnect-values.md +++ b/docs/sources/shared/visualizations/disconnect-values.md @@ -8,5 +8,5 @@ Choose whether to set a threshold above which values in the data should be disco {{< figure src="/media/docs/grafana/screenshot-grafana-10-1-disconnect-values.png" max-width="750px" alt="Disconnect values options" >}} -- **Never:** Time series data points in the the data are never disconnected. +- **Never:** Time series data points in the data are never disconnected. - **Threshold:** Specify a threshold above which values in the data are disconnected. This can be useful when desired values in the data are of a known size and/or within a known range, and values outside this range should no longer be connected. From d308b47e974c42af9dcb9c53abdda97020a0f189 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 29 Feb 2024 14:07:00 -0500 Subject: [PATCH 029/138] [v10.4.x] Docs: fix config file info in upgrade guide (#83703) Docs: fix config file info in upgrade guide (#83273) * Updated incorrect custom config file names and locations * Corrected default config file name * Updated more config file info * Apply suggestions from code review Co-authored-by: Pepe Cano <825430+ppcano@users.noreply.github.com> * Reverted change * Fixed default config file info, added second custom file option, and added note about file locations * Added file path for second custom option * Apply suggestion from review Co-authored-by: Usman Ahmad * Apply suggestion from review Co-authored-by: Usman Ahmad * Apply suggestions from review Co-authored-by: Usman Ahmad * Apply suggestion from review * Add version interpolation syntax * Updated wording * Ran prettier --------- Co-authored-by: Pepe Cano <825430+ppcano@users.noreply.github.com> Co-authored-by: Usman Ahmad (cherry picked from commit e26cd8614d1f5f9445108c95824042191beb5be6) Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --- docs/sources/shared/back-up/back-up-grafana.md | 6 ++++-- .../sources/shared/upgrade/upgrade-common-tasks.md | 14 +++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/docs/sources/shared/back-up/back-up-grafana.md b/docs/sources/shared/back-up/back-up-grafana.md index c12ec9c6d4c7..db2f437663f6 100644 --- a/docs/sources/shared/back-up/back-up-grafana.md +++ b/docs/sources/shared/back-up/back-up-grafana.md @@ -17,8 +17,10 @@ Copy Grafana configuration files that you might have modified in your Grafana de The Grafana configuration files are located in the following directories: -- Default configuration: `$WORKING_DIR/conf/defaults.ini` -- Custom configuration: `$WORKING_DIR/conf/custom.ini` +- Default configuration: `$WORKING_DIR/defaults.ini` (Don't change this file) +- Custom configuration: `$WORKING_DIR/custom.ini` + +For more information on where to find configuration files, refer to [Configuration file location](https://grafana.com/docs/grafana//setup-grafana/configure-grafana/#configuration-file-location). {{% admonition type="note" %}} If you installed Grafana using the `deb` or `rpm` packages, then your configuration file is located at diff --git a/docs/sources/shared/upgrade/upgrade-common-tasks.md b/docs/sources/shared/upgrade/upgrade-common-tasks.md index 3c53e3d44f3d..7e84a837d4da 100644 --- a/docs/sources/shared/upgrade/upgrade-common-tasks.md +++ b/docs/sources/shared/upgrade/upgrade-common-tasks.md @@ -8,13 +8,13 @@ title: Upgrade guide common tasks ## Upgrade Grafana -The following sections provide instructions for how to upgrade Grafana based on your installation method. +The following sections provide instructions for how to upgrade Grafana based on your installation method. For more information on where to find configuration files, refer to [Configuration file location](https://grafana.com/docs/grafana//setup-grafana/configure-grafana/#configuration-file-location). ### Debian To upgrade Grafana installed from a Debian package (`.deb`), complete the following steps: -1. In your current installation of Grafana, save your custom configuration changes to a file named `/conf/custom.ini`. +1. In your current installation of Grafana, save your custom configuration changes to a file named `/grafana.ini`. This enables you to upgrade Grafana without the risk of losing your configuration changes. @@ -32,7 +32,7 @@ To upgrade Grafana installed from a Debian package (`.deb`), complete the follow To upgrade Grafana installed from the Grafana Labs APT repository, complete the following steps: -1. In your current installation of Grafana, save your custom configuration changes to a file named `/conf/custom.ini`. +1. In your current installation of Grafana, save your custom configuration changes to a file named `/grafana.ini`. This enables you to upgrade Grafana without the risk of losing your configuration changes. @@ -49,7 +49,7 @@ Grafana automatically updates when you run `apt-get upgrade`. To upgrade Grafana installed from the binary `.tar.gz` package, complete the following steps: -1. In your current installation of Grafana, save your custom configuration changes to a file named `/conf/custom.ini`. +1. In your current installation of Grafana, save your custom configuration changes to the custom configuration file, `custom.ini` or `grafana.ini`. This enables you to upgrade Grafana without the risk of losing your configuration changes. @@ -61,7 +61,7 @@ To upgrade Grafana installed from the binary `.tar.gz` package, complete the fol To upgrade Grafana installed using RPM or YUM complete the following steps: -1. In your current installation of Grafana, save your custom configuration changes to a file named `/conf/custom.ini`. +1. In your current installation of Grafana, save your custom configuration changes to a file named `/grafana.ini`. This enables you to upgrade Grafana without the risk of losing your configuration changes. @@ -84,7 +84,7 @@ To upgrade Grafana installed using RPM or YUM complete the following steps: To upgrade Grafana running in a Docker container, complete the following steps: -1. In your current installation of Grafana, save your custom configuration changes to a file named `/conf/custom.ini`. +1. Use Grafana [environment variables](https://grafana.com/docs/grafana//setup-grafana/configure-grafana/#override-configuration-with-environment-variables) to save your custom configurations; this is the recommended method. Alternatively, you can view your configuration files manually by accessing the deployed container. This enables you to upgrade Grafana without the risk of losing your configuration changes. @@ -119,7 +119,7 @@ To upgrade Grafana installed on Windows, complete the following steps: To upgrade Grafana installed on Mac, complete the following steps: -1. In your current installation of Grafana, save your custom configuration changes to a file named `/conf/custom.ini`. +1. In your current installation of Grafana, save your custom configuration changes to the custom configuration file, `custom.ini`. This enables you to upgrade Grafana without the risk of losing your configuration changes. From c0da5fd7a538d3d8608ce9cc7a27973a3aa4930a Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Fri, 1 Mar 2024 10:52:45 +0100 Subject: [PATCH 030/138] [v10.4.x] LDAP: Fix LDAP users authenticated via auth proxy not being able to use LDAP active sync (#83751) LDAP: Fix LDAP users authenticated via auth proxy not being able to use LDAP active sync (#83715) * fix LDAP users authenticated via auth proxy not being able to use ldap sync * simplify id resolution at the cost of no fallthrough * remove unused services * remove unused cache key (cherry picked from commit 2182cc47acaeae16e7208b2a59ac80ef1e9bba76) Co-authored-by: Jo --- pkg/services/authn/authnimpl/service.go | 2 +- pkg/services/authn/clients/proxy.go | 33 ++++++++----------- pkg/services/authn/clients/proxy_test.go | 5 ++- pkg/services/contexthandler/contexthandler.go | 2 +- 4 files changed, 17 insertions(+), 25 deletions(-) diff --git a/pkg/services/authn/authnimpl/service.go b/pkg/services/authn/authnimpl/service.go index b436d098cfb0..28874c379435 100644 --- a/pkg/services/authn/authnimpl/service.go +++ b/pkg/services/authn/authnimpl/service.go @@ -124,7 +124,7 @@ func ProvideService( } if s.cfg.AuthProxyEnabled && len(proxyClients) > 0 { - proxy, err := clients.ProvideProxy(cfg, cache, userService, proxyClients...) + proxy, err := clients.ProvideProxy(cfg, cache, proxyClients...) if err != nil { s.log.Error("Failed to configure auth proxy", "err", err) } else { diff --git a/pkg/services/authn/clients/proxy.go b/pkg/services/authn/clients/proxy.go index 46c9ee1b0415..fdfe1960e9d7 100644 --- a/pkg/services/authn/clients/proxy.go +++ b/pkg/services/authn/clients/proxy.go @@ -15,7 +15,6 @@ import ( authidentity "github.com/grafana/grafana/pkg/services/auth/identity" "github.com/grafana/grafana/pkg/services/authn" "github.com/grafana/grafana/pkg/services/login" - "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util/errutil" @@ -43,12 +42,12 @@ var ( _ authn.ContextAwareClient = new(Proxy) ) -func ProvideProxy(cfg *setting.Cfg, cache proxyCache, userSrv user.Service, clients ...authn.ProxyClient) (*Proxy, error) { +func ProvideProxy(cfg *setting.Cfg, cache proxyCache, clients ...authn.ProxyClient) (*Proxy, error) { list, err := parseAcceptList(cfg.AuthProxyWhitelist) if err != nil { return nil, err } - return &Proxy{log.New(authn.ClientProxy), cfg, cache, userSrv, clients, list}, nil + return &Proxy{log.New(authn.ClientProxy), cfg, cache, clients, list}, nil } type proxyCache interface { @@ -61,7 +60,6 @@ type Proxy struct { log log.Logger cfg *setting.Cfg cache proxyCache - userSrv user.Service clients []authn.ProxyClient acceptedIPs []*net.IPNet } @@ -91,21 +89,17 @@ func (c *Proxy) Authenticate(ctx context.Context, r *authn.Request) (*authn.Iden if err != nil { c.log.FromContext(ctx).Warn("Failed to parse user id from cache", "error", err, "userId", string(entry)) } else { - usr, err := c.userSrv.GetSignedInUserWithCacheCtx(ctx, &user.GetSignedInUserQuery{ - UserID: uid, - OrgID: r.OrgID, - }) - - if err != nil { - c.log.FromContext(ctx).Warn("Could not resolved cached user", "error", err, "userId", string(entry)) - } - - // if we for some reason cannot find the user we proceed with the normal flow, authenticate with ProxyClient - // and perform syncs - if usr != nil { - c.log.FromContext(ctx).Debug("User was loaded from cache, skip syncs", "userId", usr.UserID) - return authn.IdentityFromSignedInUser(authn.NamespacedID(authn.NamespaceUser, usr.UserID), usr, authn.ClientParams{SyncPermissions: true}, login.AuthProxyAuthModule), nil - } + return &authn.Identity{ + ID: authn.NamespacedID(authn.NamespaceUser, uid), + OrgID: r.OrgID, + // FIXME: This does not match the actual auth module used, but should not have any impact + // Maybe caching the auth module used with the user ID would be a good idea + AuthenticatedBy: login.AuthProxyAuthModule, + ClientParams: authn.ClientParams{ + FetchSyncedUser: true, + SyncPermissions: true, + }, + }, nil } } } @@ -116,7 +110,6 @@ func (c *Proxy) Authenticate(ctx context.Context, r *authn.Request) (*authn.Iden identity, clientErr = proxyClient.AuthenticateProxy(ctx, r, username, additional) if identity != nil { identity.ClientParams.CacheAuthProxyKey = cacheKey - identity.AuthenticatedBy = login.AuthProxyAuthModule return identity, nil } } diff --git a/pkg/services/authn/clients/proxy_test.go b/pkg/services/authn/clients/proxy_test.go index 408f5b32004f..04b0d6c492dd 100644 --- a/pkg/services/authn/clients/proxy_test.go +++ b/pkg/services/authn/clients/proxy_test.go @@ -13,7 +13,6 @@ import ( "github.com/grafana/grafana/pkg/services/authn" "github.com/grafana/grafana/pkg/services/authn/authntest" - "github.com/grafana/grafana/pkg/services/user/usertest" "github.com/grafana/grafana/pkg/setting" ) @@ -113,7 +112,7 @@ func TestProxy_Authenticate(t *testing.T) { calledAdditional = additional return nil, nil }} - c, err := ProvideProxy(cfg, &fakeCache{expectedErr: errors.New("")}, usertest.NewUserServiceFake(), proxyClient) + c, err := ProvideProxy(cfg, &fakeCache{expectedErr: errors.New("")}, proxyClient) require.NoError(t, err) _, err = c.Authenticate(context.Background(), tt.req) @@ -210,7 +209,7 @@ func TestProxy_Hook(t *testing.T) { withRole := func(role string) func(t *testing.T) { cacheKey := fmt.Sprintf("users:johndoe-%s", role) return func(t *testing.T) { - c, err := ProvideProxy(cfg, cache, usertest.NewUserServiceFake(), authntest.MockProxyClient{}) + c, err := ProvideProxy(cfg, cache, authntest.MockProxyClient{}) require.NoError(t, err) userIdentity := &authn.Identity{ ID: userID, diff --git a/pkg/services/contexthandler/contexthandler.go b/pkg/services/contexthandler/contexthandler.go index 256d13a34fa2..b405fed5ad4f 100644 --- a/pkg/services/contexthandler/contexthandler.go +++ b/pkg/services/contexthandler/contexthandler.go @@ -120,7 +120,7 @@ func (h *ContextHandler) Middleware(next http.Handler) http.Handler { reqContext.UserToken = identity.SessionToken reqContext.IsSignedIn = !reqContext.SignedInUser.IsAnonymous reqContext.AllowAnonymous = reqContext.SignedInUser.IsAnonymous - reqContext.IsRenderCall = identity.AuthenticatedBy == login.RenderModule + reqContext.IsRenderCall = identity.GetAuthenticatedBy() == login.RenderModule } reqContext.Logger = reqContext.Logger.New("userId", reqContext.UserID, "orgId", reqContext.OrgID, "uname", reqContext.Login) From dcec8aafb762aa2bb016c2e68a05c21f669c999c Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Fri, 1 Mar 2024 19:01:05 +0100 Subject: [PATCH 031/138] [v10.4.x] Fix: Cache busting of plugins module.js file (#83791) Fix: Cache busting of plugins module.js file (#83763) fix(plugins): make sure extractPath regex matches with and without leading slash (cherry picked from commit c59ebfc60f5aec1eccfe07da7a6d948782ddafdb) Co-authored-by: Jack Westbrook --- public/app/features/plugins/loader/cache.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/features/plugins/loader/cache.ts b/public/app/features/plugins/loader/cache.ts index 739c4c580720..3db74fd2a708 100644 --- a/public/app/features/plugins/loader/cache.ts +++ b/public/app/features/plugins/loader/cache.ts @@ -35,7 +35,7 @@ export function resolveWithCache(url: string, defaultBust = initializedAt): stri } function extractPath(address: string): string | undefined { - const match = /\/.+\/(plugins\/.+\/module)\.js/i.exec(address); + const match = /\/?.+\/(plugins\/.+\/module)\.js/i.exec(address); if (!match) { return; } From 1c79d8e0c076e1e1508d7dcda44127d7f92886dc Mon Sep 17 00:00:00 2001 From: linoman <2051016+linoman@users.noreply.github.com> Date: Mon, 4 Mar 2024 06:05:16 -0600 Subject: [PATCH 032/138] [v10.4.x] Chore: Improve domain validation for Google OAuth - Backport 83229 to v10.4.x (#83726) * Chore: Query oauth info from a new instance (#83229) * query OAuth info from a new instance * add `hd` validation flag * add `disable_hd_validation` to settings map * update documentation --------- Co-authored-by: Jo (cherry picked from commit b02ae375ba5599fa1e72fb818a1424a8e134efaa) --- conf/defaults.ini | 1 + conf/sample.ini | 1 + .../configure-authentication/google/index.md | 8 +++ pkg/login/social/connectors/google_oauth.go | 31 +++++++++++ .../social/connectors/google_oauth_test.go | 52 +++++++++++++++++++ 5 files changed, 93 insertions(+) diff --git a/conf/defaults.ini b/conf/defaults.ini index 93158d3b6cbc..67bc7e72e43b 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -679,6 +679,7 @@ token_url = https://oauth2.googleapis.com/token api_url = https://openidconnect.googleapis.com/v1/userinfo signout_redirect_url = allowed_domains = +validate_hd = false hosted_domain = allowed_groups = role_attribute_path = diff --git a/conf/sample.ini b/conf/sample.ini index ad4f8569fd6e..e60d15e9bdf2 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -643,6 +643,7 @@ ;api_url = https://openidconnect.googleapis.com/v1/userinfo ;signout_redirect_url = ;allowed_domains = +;validate_hd = ;hosted_domain = ;allowed_groups = ;role_attribute_path = diff --git a/docs/sources/setup-grafana/configure-security/configure-authentication/google/index.md b/docs/sources/setup-grafana/configure-security/configure-authentication/google/index.md index 7d0fe701c146..58746d2824ea 100644 --- a/docs/sources/setup-grafana/configure-security/configure-authentication/google/index.md +++ b/docs/sources/setup-grafana/configure-security/configure-authentication/google/index.md @@ -111,6 +111,14 @@ automatically signed up. You may specify a domain to be passed as `hd` query parameter accepted by Google's OAuth 2.0 authentication API. Refer to Google's OAuth [documentation](https://developers.google.com/identity/openid-connect/openid-connect#hd-param). +{{% admonition type="note" %}} +The `hd` parameter retrieved from Google ID token is also used to determine the user's hosted domain. The Google Oauth `allowed_domains` configuration option is used to restrict access to users from a specific domain. If the `allowed_domains` configuration option is set, the `hd` parameter from the Google ID token must match the `allowed_domains` configuration option. If the `hd` parameter from the Google ID token does not match the `allowed_domains` configuration option, the user is denied access. + +When an account does not belong to a Google Workspace, the `hd` claim is not be available. + +This validation will be enabled by default with Grafana 11.0. To disable this validation, set the `validate_hd` configuration option to `false`. The `allowed_domains` configuration option will use the email claim to validate the domain. +{{% /admonition %}} + #### PKCE IETF's [RFC 7636](https://datatracker.ietf.org/doc/html/rfc7636) diff --git a/pkg/login/social/connectors/google_oauth.go b/pkg/login/social/connectors/google_oauth.go index 6709d4e05cfc..4fac34e8612f 100644 --- a/pkg/login/social/connectors/google_oauth.go +++ b/pkg/login/social/connectors/google_oauth.go @@ -17,19 +17,23 @@ import ( ssoModels "github.com/grafana/grafana/pkg/services/ssosettings/models" "github.com/grafana/grafana/pkg/services/ssosettings/validation" "github.com/grafana/grafana/pkg/setting" + "github.com/grafana/grafana/pkg/util/errutil" ) const ( legacyAPIURL = "https://www.googleapis.com/oauth2/v1/userinfo" googleIAMGroupsEndpoint = "https://content-cloudidentity.googleapis.com/v1/groups/-/memberships:searchDirectGroups" googleIAMScope = "https://www.googleapis.com/auth/cloud-identity.groups.readonly" + validateHDKey = "validate_hd" ) var _ social.SocialConnector = (*SocialGoogle)(nil) var _ ssosettings.Reloadable = (*SocialGoogle)(nil) +var ExtraGoogleSettingKeys = []string{validateHDKey} type SocialGoogle struct { *SocialBase + validateHD bool } type googleUserData struct { @@ -37,12 +41,14 @@ type googleUserData struct { Email string `json:"email"` Name string `json:"name"` EmailVerified bool `json:"email_verified"` + HD string `json:"hd"` rawJSON []byte `json:"-"` } func NewGoogleProvider(info *social.OAuthInfo, cfg *setting.Cfg, ssoSettings ssosettings.Service, features featuremgmt.FeatureToggles) *SocialGoogle { provider := &SocialGoogle{ SocialBase: newSocialBase(social.GoogleProviderName, info, features, cfg), + validateHD: MustBool(info.Extra[validateHDKey], false), } if strings.HasPrefix(info.ApiUrl, legacyAPIURL) { @@ -87,6 +93,7 @@ func (s *SocialGoogle) Reload(ctx context.Context, settings ssoModels.SSOSetting defer s.reloadMutex.Unlock() s.SocialBase = newSocialBase(social.GoogleProviderName, newInfo, s.features, s.cfg) + s.validateHD = MustBool(newInfo.Extra[validateHDKey], false) return nil } @@ -115,6 +122,10 @@ func (s *SocialGoogle) UserInfo(ctx context.Context, client *http.Client, token return nil, fmt.Errorf("user email is not verified") } + if err := s.isHDAllowed(data.HD, info); err != nil { + return nil, err + } + groups, errPage := s.retrieveGroups(ctx, client, data) if errPage != nil { s.log.Warn("Error retrieving groups", "error", errPage) @@ -157,6 +168,7 @@ type googleAPIData struct { Name string `json:"name"` Email string `json:"email"` EmailVerified bool `json:"verified_email"` + HD string `json:"hd"` } func (s *SocialGoogle) extractFromAPI(ctx context.Context, client *http.Client) (*googleUserData, error) { @@ -178,6 +190,7 @@ func (s *SocialGoogle) extractFromAPI(ctx context.Context, client *http.Client) Name: data.Name, Email: data.Email, EmailVerified: data.EmailVerified, + HD: data.HD, rawJSON: response.Body, }, nil } @@ -290,3 +303,21 @@ func (s *SocialGoogle) getGroupsPage(ctx context.Context, client *http.Client, u return &data, nil } + +func (s *SocialGoogle) isHDAllowed(hd string, info *social.OAuthInfo) error { + if s.validateHD { + return nil + } + + if len(info.AllowedDomains) == 0 { + return nil + } + + for _, allowedDomain := range info.AllowedDomains { + if hd == allowedDomain { + return nil + } + } + + return errutil.Forbidden("the hd claim found in the ID token is not present in the allowed domains", errutil.WithPublicMessage("Invalid domain")) +} diff --git a/pkg/login/social/connectors/google_oauth_test.go b/pkg/login/social/connectors/google_oauth_test.go index 95345c94e532..d822d4d7b888 100644 --- a/pkg/login/social/connectors/google_oauth_test.go +++ b/pkg/login/social/connectors/google_oauth_test.go @@ -890,3 +890,55 @@ func TestSocialGoogle_Reload(t *testing.T) { }) } } + +func TestIsHDAllowed(t *testing.T) { + testCases := []struct { + name string + email string + allowedDomains []string + expectedErrorMessage string + validateHD bool + }{ + { + name: "should not fail if no allowed domains are set", + email: "mycompany.com", + allowedDomains: []string{}, + expectedErrorMessage: "", + }, + { + name: "should not fail if email is from allowed domain", + email: "mycompany.com", + allowedDomains: []string{"grafana.com", "mycompany.com", "example.com"}, + expectedErrorMessage: "", + }, + { + name: "should fail if email is not from allowed domain", + email: "mycompany.com", + allowedDomains: []string{"grafana.com", "example.com"}, + expectedErrorMessage: "the hd claim found in the ID token is not present in the allowed domains", + }, + { + name: "should not fail if the HD validation is disabled and the email not being from an allowed domain", + email: "mycompany.com", + allowedDomains: []string{"grafana.com", "example.com"}, + validateHD: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + info := &social.OAuthInfo{} + info.AllowedDomains = tc.allowedDomains + s := NewGoogleProvider(info, &setting.Cfg{}, &ssosettingstests.MockService{}, featuremgmt.WithFeatures()) + s.validateHD = tc.validateHD + err := s.isHDAllowed(tc.email, info) + + if tc.expectedErrorMessage != "" { + require.Error(t, err) + require.Contains(t, err.Error(), tc.expectedErrorMessage) + } else { + require.NoError(t, err) + } + }) + } +} From deec5361b75e144135419f0cba74de37dc48affa Mon Sep 17 00:00:00 2001 From: Pepe Cano <825430+ppcano@users.noreply.github.com> Date: Mon, 4 Mar 2024 15:51:06 +0100 Subject: [PATCH 033/138] [v10.4.x] Alerting docs: update the Terraform Provision guide (#83820) * Alerting docs: update the Terraform Provision guide (#83773) * Alerting docs: update the Terraform Provision guide * Fix incorrect links * Update docs/sources/alerting/set-up/provision-alerting-resources/terraform-provisioning/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/alerting/set-up/provision-alerting-resources/terraform-provisioning/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/alerting/set-up/provision-alerting-resources/terraform-provisioning/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> --------- Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> (cherry picked from commit 111df1bba0efb85f7a4a3d7e54afe485cc30ff37) * Fix `doc-validator` issue with relative link * Use patch fixed version of doc-validator that better supports docs/reference destinations Signed-off-by: Jack Baldry --------- (cherry picked from commit eb25b669c6a3aca8f5bda80f59762e1b5d6580e5) Signed-off-by: Jack Baldry --------- Signed-off-by: Jack Baldry --- .github/workflows/doc-validator.yml | 2 +- .../terraform-provisioning/index.md | 490 ++++++++++-------- 2 files changed, 263 insertions(+), 229 deletions(-) diff --git a/.github/workflows/doc-validator.yml b/.github/workflows/doc-validator.yml index 9e28a128b978..620a8f84e7db 100644 --- a/.github/workflows/doc-validator.yml +++ b/.github/workflows/doc-validator.yml @@ -7,7 +7,7 @@ jobs: doc-validator: runs-on: "ubuntu-latest" container: - image: "grafana/doc-validator:v4.0.0" + image: "grafana/doc-validator:v4.1.1" steps: - name: "Checkout code" uses: "actions/checkout@v4" diff --git a/docs/sources/alerting/set-up/provision-alerting-resources/terraform-provisioning/index.md b/docs/sources/alerting/set-up/provision-alerting-resources/terraform-provisioning/index.md index f7bd77c87212..488ca0864d35 100644 --- a/docs/sources/alerting/set-up/provision-alerting-resources/terraform-provisioning/index.md +++ b/docs/sources/alerting/set-up/provision-alerting-resources/terraform-provisioning/index.md @@ -23,267 +23,103 @@ weight: 200 Use Terraform’s Grafana Provider to manage your alerting resources and provision them into your Grafana system. Terraform provider support for Grafana Alerting makes it easy to create, manage, and maintain your entire Grafana Alerting stack as code. -Refer to [Grafana Provider](https://registry.terraform.io/providers/grafana/grafana/latest/docs) documentation for more examples and information on Terraform Alerting schemas. +This guide outlines the steps and references to provision alerting resources with Terraform. For a practical demo, you can clone and try this [example using Grafana OSS and Docker Compose](https://github.com/grafana/provisioning-alerting-examples/tree/main/terraform). -Complete the following tasks to create and manage your alerting resources using Terraform. - -1. Create an API key for provisioning. -1. Configure the Terraform provider. -1. Define your alerting resources in Terraform. [Export alerting resources][alerting_export] in Terraform format, or implement the [Terraform Alerting schemas](https://registry.terraform.io/providers/grafana/grafana/latest/docs). +To create and manage your alerting resources using Terraform, you have to complete the following tasks. +1. Create an API key to configure the Terraform provider. +1. Create your alerting resources in Terraform format by + - [exporting configured alerting resources][alerting_export] + - or writing the [Terraform Alerting schemas](https://registry.terraform.io/providers/grafana/grafana/latest/docs). + > By default, you cannot edit provisioned resources. Enable [`disable_provenance` in the Terraform resource](#enable-editing-resources-in-the-grafana-ui) to allow changes in the Grafana UI. 1. Run `terraform apply` to provision your alerting resources. -{{< admonition type="note" >}} - -- By default, you cannot edit resources provisioned from Terraform from the UI. This ensures that your alerting stack always stays in sync with your code. To change the default behaviour, refer to [Edit provisioned resources in the Grafana UI](#edit-provisioned-resources-in-the-grafana-ui). - -- Before you begin, ensure you have the [Grafana Terraform Provider](https://registry.terraform.io/providers/grafana/grafana/) 1.27.0 or higher, and are using Grafana 9.1 or higher. - -{{< /admonition >}} - -## Create an API key for provisioning +Before you begin, you should have available a Grafana instance and [Terraform installed](https://www.terraform.io/downloads) on your machine. -You can create a [service account token][service-accounts] to authenticate Terraform with Grafana. Most existing tooling using API keys should automatically work with the new Grafana Alerting support. +## Create an API key and configure the Terraform provider -There are also dedicated RBAC roles for alerting provisioning. This lets you easily authenticate as a service account with the minimum permissions needed to provision your Alerting infrastructure. - -To create an API key for provisioning, complete the following steps. +You can create a [service account token][service-accounts] to authenticate Terraform with Grafana. To create an API key for provisioning alerting resources, complete the following steps. 1. Create a new service account. 1. Assign the role or permission to access the [Alerting provisioning API][alerting_http_provisioning]. 1. Create a new service account token. 1. Name and save the token for use in Terraform. -Alternatively, you can use basic authentication. To view all the supported authentication formats, see [here](https://registry.terraform.io/providers/grafana/grafana/latest/docs#authentication). - -## Configure the Terraform provider - -Grafana Alerting support is included as part of the [Grafana Terraform provider](https://registry.terraform.io/providers/grafana/grafana/latest/docs). +You can now move to the working directory for your Terraform configurations, and create a file named `main.tf` like: -The following is an example you can use to configure the Terraform provider. - -```HCL +```main.tf terraform { required_providers { grafana = { source = "grafana/grafana" - version = ">= 1.28.2" + version = ">= 2.9.0" } } } provider "grafana" { - url = - auth = + url = + auth = } ``` -## Import contact points and templates - -Contact points connect an alerting stack to the outside world. They tell Grafana how to connect to your external systems and where to deliver notifications. - -To provision contact points and templates, refer to the [grafana_contact_point schema](https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/contact_point) and [grafana_message_template schema](https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/message_template), and complete the following steps. - -1. Copy this code block into a `.tf` file on your local machine. - - This example creates a contact point that sends alert notifications to Slack. - - ```HCL - resource "grafana_contact_point" "my_slack_contact_point" { - name = "Send to My Slack Channel" - - slack { - url = - text = <` with the URL of the Grafana instance. +- `` with the API token previously created. -1. Go to the Grafana UI and check the details of your contact point. +This Terraform configuration installs the [Grafana Terraform provider](https://registry.terraform.io/providers/grafana/grafana/latest/docs) and authenticates against your Grafana instance using an API token. For other authentication alternatives including basic authentication, refer to the [`auth` option documentation](https://registry.terraform.io/providers/grafana/grafana/latest/docs#authentication). -1. Click **Test** to verify that the contact point works correctly. +For Grafana Cloud, refer to the [instructions to manage a Grafana Cloud stack with Terraform][provision-cloud-with-terraform]. For role-based access control, refer to [Provisioning RBAC with Terraform][rbac-terraform-provisioning] and the [alerting provisioning roles (`fixed:alerting.provisioning.*`)][rbac-role-definitions]. -### Reuse templates +## Create Terraform configurations for alerting resources -You can reuse the same templates across many contact points. In the example above, a shared template ie embedded using the statement `{{ template “Alert Instance Template” . }}` +[Grafana Terraform provider](https://registry.terraform.io/providers/grafana/grafana/latest/docs) enables you to manage the following alerting resources. -This fragment can then be managed separately in Terraform: +| Alerting resource | Terraform resource | +| ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | +| [Alert rules][alerting-rules] | [grafana_rule_group](https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/rule_group) | +| [Contact points][contact-points] | [grafana_contact_point](https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/contact_point) | +| [Notification templates][notification-template] | [grafana_message_template](https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/message_template) | +| [Notification policy tree][notification-policy] | [grafana_notification_policy](https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/notification_policy) | +| [Mute timings][mute-timings] | [grafana_mute_timing](https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/mute_timing) | -```HCL -resource "grafana_message_template" "my_alert_template" { - name = "Alert Instance Template" +In this section, we'll create Terraform configurations for each alerting resource and demonstrate how to link them together. - template = <}} +### Add alert rules -1. Copy this code block into a `.tf` file on your local machine. +[Alert rules][alerting-rules] enable you to receive alerts by querying any backend Grafana data sources. - In this example, the alerts are grouped by `alertname`, which means that any notifications coming from alerts which share the same name, are grouped into the same Slack message. You can provide any set of label keys here, or you can use the special label `"..."` to route by all label keys, sending each alert in a separate notification. - - If you want to route specific notifications differently, you can add sub-policies. Sub-policies allow you to apply routing to different alerts based on label matching. In this example, we apply a mute timing to all alerts with the label a=b. - - ```HCL - resource "grafana_notification_policy" "my_policy" { - group_by = ["alertname"] - contact_point = grafana_contact_point.my_slack_contact_point.name - - group_wait = "45s" - group_interval = "6m" - repeat_interval = "3h" - - policy { - matcher { - label = "a" - match = "=" - value = "b" - } - group_by = ["..."] - contact_point = grafana_contact_point.a_different_contact_point.name - mute_timings = [grafana_mute_timing.my_mute_timing.name] - - policy { - matcher { - label = "sublabel" - match = "=" - value = "subvalue" - } - contact_point = grafana_contact_point.a_third_contact_point.name - group_by = ["..."] - } - } - } - ``` - -1. In the mute_timings field, link a mute timing to your notification policy. - -1. Run the command `terraform apply`. - -1. Go to the Grafana UI and check the details of your notification policy. - -1. Click **Test** to verify that the notification point is working correctly. - -## Import mute timings - -Mute timings provide the ability to mute alert notifications for defined time periods. - -To provision mute timings, refer to the [grafana_mute_timing schema](https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/mute_timing), and complete the following steps. - -1. Copy this code block into a `.tf` file on your local machine. - - In this example, alert notifications are muted on weekends. - - ```HCL - resource "grafana_mute_timing" "my_mute_timing" { - name = "My Mute Timing" - - intervals { - times { - start = "04:56" - end = "14:17" - } - weekdays = ["saturday", "sunday", "tuesday:thursday"] - months = ["january:march", "12"] - years = ["2025:2027"] - } - } - ``` - -1. Run the command `terraform apply`. -1. Go to the Grafana UI and check the details of your mute timing. -1. Reference your newly created mute timing in a notification policy using the `mute_timings` field. - This will apply your mute timing to some or all of your notifications. - -1. Click **Test** to verify that the mute timing is working correctly. - -## Import alert rules - -[Alert rules][alerting-rules] enable you to alert against any Grafana data source. This can be a data source that you already have configured, or you can [define your data sources in Terraform](https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/data_source) alongside your alert rules. - -To provision alert rules, refer to the [grafana_rule_group schema](https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/rule_group), and complete the following steps. - -1. Create a data source to query and a folder to store your rules in. +1. First, create a data source to query and a folder to store your rules in. In this example, the [TestData][testdata] data source is used. - Alerts can be defined against any backend datasource in Grafana. - - ```HCL - resource "grafana_data_source" "testdata_datasource" { + ```terraform + resource "grafana_data_source" "" { name = "TestData" type = "testdata" } - resource "grafana_folder" "rule_folder" { + resource "grafana_folder" "" { title = "My Rule Folder" } ``` -1. Define an alert rule. + Replace the following field values: + + - `` with the terraform name of the data source. + - `` with the terraform name of the folder. - For more information on alert rules, refer to [how to create Grafana-managed alerts](/blog/2022/08/01/grafana-alerting-video-how-to-create-alerts-in-grafana-9/). +1. Create or find an alert rule you want to import in Grafana. -1. Create a rule group containing one or more rules. +1. [Export][alerting_export] the alert rule group in Terraform format. This exports the alert rule group as [`grafana_rule_group` Terraform resource](https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/rule_group). - In this example, the `grafana_rule_group` resource group is used. + You can edit the exported resource, or alternatively, consider creating the resource from scratch. - ```HCL - resource "grafana_rule_group" "my_rule_group" { + ```terraform + resource "grafana_rule_group" "" { name = "My Alert Rules" - folder_uid = grafana_folder.rule_folder.uid + folder_uid = grafana_folder..uid interval_seconds = 60 org_id = 1 @@ -299,7 +135,7 @@ To provision alert rules, refer to the [grafana_rule_group schema](https://regis from = 600 to = 0 } - datasource_uid = grafana_data_source.testdata_datasource.uid + datasource_uid = grafana_data_source..uid // `model` is a JSON blob that sends datasource-specific data. // It's different for every datasource. The alert's query is defined here. model = jsonencode({ @@ -343,40 +179,231 @@ To provision alert rules, refer to the [grafana_rule_group schema](https://regis } ``` -1. Run the command `terraform apply`. -1. Go to the Grafana UI and check your alert rule. + Replace the following field values: -You can see whether or not the alert rule is firing. You can also see a visualization of each of the alert rule’s query stages + - `` with the name of the alert rule group. -When the alert fires, Grafana routes a notification through the policy you defined. + Note that the distinct Grafana resources are connected through `uid` values in their Terraform configurations. The `uid` value will be randomly generated when provisioning. -For example, if you chose Slack as a contact point, Grafana’s embedded [Alertmanager](https://github.com/prometheus/alertmanager) automatically posts a message to Slack. + To link the alert rule group with its respective data source and folder in this example, replace the following field values: -## Edit provisioned resources in the Grafana UI + - `` with the terraform name of the previously defined data source. + - `` with the terraform name of the the previously defined folder. -By default, you cannot edit resources provisioned via Terraform in Grafana. To enable editing these resources in the Grafana UI, use the `disable_provenance` attribute on alerting resources: +1. Continue to add more Grafana resources or [use the Terraform CLI for provisioning](#provision-grafana-resources-with-terraform). -```HCL -provider "grafana" { - url = "http://grafana.example.com/" - auth = var.grafana_auth +### Add contact points + +[Contact points][contact-points] are the receivers of alert notifications. + +1. Create or find the contact points you want to import in Grafana. Alternatively, consider writing the resource in code as demonstrated in the example below. + +1. [Export][alerting_export] the contact point in Terraform format. This exports the contact point as [`grafana_contact_point` Terraform resource](https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/contact_point)—edit it if necessary. + +1. In this example, notifications are muted on weekends. + + ```terraform + resource "grafana_contact_point" "" { + name = "My contact point email" + + email { + addresses = [""] + } + } + ``` + + Replace the following field values: + + - `` with the terraform name of the contact point. It will be used to reference the contact point in other Terraform resources. + - `` with the email to receive alert notifications. + +1. Continue to add more Grafana resources or [use the Terraform CLI for provisioning](#provision-grafana-resources-with-terraform). + +### Add and enable templates + +[Notification templates][notification-template] allow customization of alert notifications across multiple contact points. + +1. Create or find the notification template you want to import in Grafana. Alternatively, consider writing the resource in code as demonstrated in the example below. + +1. [Export][alerting_export] the template as [`grafana_message_template` Terraform resource](https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/message_template). + + This example is a simple demo template defined as `custom_email.message`. + + ```terraform + resource "grafana_message_template" "" { + name = "custom_email.message" + + template = <" { + name = "My contact point email" + + email { + addresses = [""] + message = "{{ template \"custom_email.message\" .}}" + } + } + ``` + +1. Continue to add more Grafana resources or [use the Terraform CLI for provisioning](#provision-grafana-resources-with-terraform). + +### Add mute timings + +[Mute timings][mute-timings] pause alert notifications during predetermined intervals. + +1. Create or find the mute timings you want to import in Grafana. Alternatively, consider writing the resource in code as demonstrated in the example below. + +1. [Export][alerting_export] the mute timing in Terraform format. This exports the mute timing as [`grafana_mute_timing` Terraform resource](https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/mute_timing)—edit it if necessary. + +1. This example turns off notifications on weekends. + + ```terraform + resource "grafana_mute_timing" "" { + name = "No weekends" + + intervals { + weekdays = ["saturday", "sunday"] + } + } + ``` + + Replace the following field values: + + - `` with the name of the Terraform resource. It will be used to reference the mute timing in the Terraform notification policy tree. + +1. Continue to add more Grafana resources or [use the Terraform CLI for provisioning](#provision-grafana-resources-with-terraform). + +### Add the notification policy tree + +[Notification policies][notification-policy] defines how to route alert instances to your contact points. + +{{% admonition type="warning" %}} + +Since the policy tree is a single resource, provisioning the `grafana_notification_policy` resource will overwrite a policy tree created through any other means. + +{{< /admonition >}} + +1. Find the default notification policy tree. Alternatively, consider writing the resource in code as demonstrated in the example below. + +1. [Export][alerting_export] the notification policy tree in Terraform format. This exports it as [`grafana_notification_policy` Terraform resource](https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/notification_policy)—edit it if necessary. + + ```terraform + resource "grafana_notification_policy" "my_policy_tree" { + contact_point = grafana_contact_point..name + ... + + policy { + contact_point = grafana_contact_point..name + + matcher {...} + + mute_timings = [grafana_mute_timing..name] + } + } + ``` + + To configure the mute timing and contact point previously created in the notification policy tree, replace the following field values: + + - `` with the terraform name of the previously defined contact point. + - `` with the terraform name of the the previously defined mute timing. + +1. Continue to add more Grafana resources or [use the Terraform CLI for provisioning](#provision-grafana-resources-with-terraform). + +### Enable editing resources in the Grafana UI + +By default, you cannot edit resources provisioned via Terraform in Grafana. This ensures that your alerting stack always stays in sync with your Terraform code. + +To make provisioned resources editable in the Grafana UI, enable the `disable_provenance` attribute on alerting resources. + +```terraform +resource "grafana_contact_point" "my_contact_point" { + name = "My Contact Point" + + disable_provenance = true } -resource "grafana_mute_timing" "mute_all" { - name = "mute all" +resource "grafana_message_template" "my_template" { + name = "My Reusable Template" + template = "{{define \"My Reusable Template\" }}\n template content\n{{ end }}" + disable_provenance = true - intervals {} } +... ``` -**Useful Links:** +Note that `disable_provenance` is not supported for [grafana_mute_timing](https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/mute_timing). + +## Provision Grafana resources with Terraform + +To create the previous alerting resources in Grafana with the Terraform CLI, complete the following steps. -[Grafana Terraform Provider documentation](https://registry.terraform.io/providers/grafana/grafana/latest/docs) +1. Initialize the working directory containing the Terraform configuration files. + + ```shell + terraform init + ``` + + This command initializes the Terraform directory, installing the Grafana Terraform provider configured in the `main.tf` file. + +1. Apply the Terraform configuration files to provision the resources. + + ```shell + terraform apply + ``` + + Before applying any changes to Grafana, Terraform displays the execution plan and requests your approval. + + ```shell + Plan: 4 to add, 0 to change, 0 to destroy. + + Do you want to perform these actions? + Terraform will perform the actions described above. + Only 'yes' will be accepted to approve. + + Enter a value: + ``` + + Once you have confirmed to proceed with the changes, Terraform will create the provisioned resources in Grafana! + + ```shell + Apply complete! Resources: 4 added, 0 changed, 0 destroyed. + ``` + +You can now access Grafana to verify the creation of the distinct resources. + +## More examples + +For more examples on the concept of this guide: + +- Try the demo [provisioning alerting resources in Grafana OSS using Terraform and Docker Compose](https://github.com/grafana/provisioning-alerting-examples/tree/main/terraform). +- Review all the available options and examples of the Terraform Alerting schemas in the [Grafana Terraform Provider documentation](https://registry.terraform.io/providers/grafana/grafana/latest/docs). +- Review the [tutorial to manage a Grafana Cloud stack using Terraform][provision-cloud-with-terraform]. {{% docs/reference %}} [alerting-rules]: "/docs/grafana/ -> /docs/grafana//alerting/alerting-rules" [alerting-rules]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/alerting-rules" +[contact-points]: "/docs/grafana/ -> /docs/grafana//alerting/configure-notifications/manage-contact-points" +[contact-points]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/configure-notifications/manage-contact-points" + +[mute-timings]: "/docs/grafana/ -> /docs/grafana//alerting/configure-notifications/mute-timings" +[mute-timings]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/configure-notifications/mute-timings" + +[notification-policy]: "/docs/grafana/ -> /docs/grafana//alerting/configure-notifications/create-notification-policy" +[notification-policy]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/configure-notifications/create-notification-policy" + +[notification-template]: "/docs/grafana/ -> /docs/grafana//alerting/configure-notifications/template-notifications" +[notification-template]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/configure-notifications/template-notifications" + [alerting_export]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/export-alerting-resources" [alerting_export]: "/docs/grafana-cloud/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/export-alerting-resources" @@ -387,5 +414,12 @@ resource "grafana_mute_timing" "mute_all" { [service-accounts]: "/docs/grafana-cloud/ -> /docs/grafana//administration/service-accounts" [testdata]: "/docs/grafana/ -> /docs/grafana//datasources/testdata" -[testdata]: "/docs/grafana-cloud/ -> /docs/grafana//datasources/testdata" +[testdata]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/connect-externally-hosted/data-sources/testdata" + +[provision-cloud-with-terraform]: "/docs/ -> /docs/grafana-cloud/developer-resources/infrastructure-as-code/terraform/terraform-cloud-stack" + +[rbac-role-definitions]: "/docs/ -> /docs/grafana//administration/roles-and-permissions/access-control/rbac-fixed-basic-role-definitions" + +[rbac-terraform-provisioning]: "/docs/ -> /docs/grafana//administration/roles-and-permissions/access-control/rbac-terraform-provisioning" + {{% /docs/reference %}} From f2333ae80720168d807f9bd3f23fcb772e19dda8 Mon Sep 17 00:00:00 2001 From: Andreas Christou Date: Mon, 4 Mar 2024 15:18:53 +0000 Subject: [PATCH 034/138] Update whats new url --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 21f152ef7023..6a655697b6ee 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "plugin:build:dev": "lerna run dev --ignore=\"@grafana/*\" --ignore=\"@grafana-plugins/input-datasource\"" }, "grafana": { - "whatsNewUrl": "https://grafana.com/docs/grafana/next/whatsnew/whats-new-in-v10-3/", + "whatsNewUrl": "https://grafana.com/docs/grafana/next/whatsnew/whats-new-in-v10-4/", "releaseNotesUrl": "https://grafana.com/docs/grafana/next/release-notes/" }, "devDependencies": { From 906490eeac3e20f0952a8dc6638dee192a1db7f6 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Mon, 4 Mar 2024 19:36:44 +0100 Subject: [PATCH 035/138] [v10.4.x] alerting:clarify silence preview (#83838) alerting:clarify silence preview (#83754) * alerting:clarify silence preview * prettier * Update docs/sources/alerting/configure-notifications/create-silence.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Lint docs --------- Co-authored-by: Armand Grillet <2117580+armandgrillet@users.noreply.github.com> Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> (cherry picked from commit 89575f1df42cb5b9f2a4316201c75ad219488353) Co-authored-by: tonypowa <45235678+tonypowa@users.noreply.github.com> --- .../alerting/manage-notifications/create-silence.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/sources/alerting/manage-notifications/create-silence.md b/docs/sources/alerting/manage-notifications/create-silence.md index 3b0d544360ea..e066a9c048cd 100644 --- a/docs/sources/alerting/manage-notifications/create-silence.md +++ b/docs/sources/alerting/manage-notifications/create-silence.md @@ -26,7 +26,11 @@ weight: 410 Silences stop notifications from getting created and last for only a specified window of time. -**Note that inhibition rules are not supported in the Grafana Alertmanager.** +{{< admonition type="note" >}} + +- Inhibition rules are not supported in the Grafana Alertmanager. +- The preview of silenced alerts only applies to alerts in firing state. + {{< /admonition >}} ## Add silences @@ -38,7 +42,7 @@ To add a silence, complete the following steps. 1. Click **Create silence** to open the Create silence page. 1. In **Silence start and end**, select the start and end date to indicate when the silence should go into effect and expire. 1. Optionally, in **Duration**, specify how long the silence is enforced. This automatically updates the end time in the **Silence start and end** field. -1. In the **Label** and **Value** fields, enter one or more _Matching Labels_. Matchers determine which rules the silence will apply to. +1. In the **Label** and **Value** fields, enter one or more _Matching Labels_. Matchers determine which rules the silence will apply to. Any matching alerts (in firing state) will show in the **Affected alert instances** field 1. In **Comment**, add details about the silence. 1. Click **Submit**. From 3171158e44703226bd0bccc97e97033da6a5a6e8 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Tue, 5 Mar 2024 12:39:13 +0100 Subject: [PATCH 036/138] [v10.4.x] GenAI: Update the component only when the response is fully generated (#83895) Dashboards: Auto-generate get stuck and quick feedback actions doesn't respond (#83879) * Update the component only when the response is fully generated * Fix quick feedback action doesn't respond * Fix history not displaying after the second click * Fix the history that moves when regenerating --------- Co-authored-by: Adela Almasan <88068998+adela-almasan@users.noreply.github.com> (cherry picked from commit 112c0e7a79c00c7057ef362b6b8a9b7e4471f1b5) Co-authored-by: Ivan Ortega Alba --- .../components/GenAI/GenAIButton.test.tsx | 45 +++++++++++++++++-- .../components/GenAI/GenAIButton.tsx | 38 ++++++++-------- .../components/GenAI/GenAIHistory.tsx | 35 +++++---------- .../dashboard/components/GenAI/hooks.ts | 13 +++++- 4 files changed, 85 insertions(+), 46 deletions(-) diff --git a/public/app/features/dashboard/components/GenAI/GenAIButton.test.tsx b/public/app/features/dashboard/components/GenAI/GenAIButton.test.tsx index 79d477313821..fc76cf269d08 100644 --- a/public/app/features/dashboard/components/GenAI/GenAIButton.test.tsx +++ b/public/app/features/dashboard/components/GenAI/GenAIButton.test.tsx @@ -173,13 +173,11 @@ describe('GenAIButton', () => { await waitFor(() => expect(getByRole('button')).toBeEnabled()); }); - it('should call onGenerate when the text is generating', async () => { + it('should not call onGenerate when the text is generating', async () => { const onGenerate = jest.fn(); setup({ onGenerate, messages: [], eventTrackingSrc: eventTrackingSrc }); - await waitFor(() => expect(onGenerate).toHaveBeenCalledTimes(1)); - - expect(onGenerate).toHaveBeenCalledWith('Some incomplete generated text'); + await waitFor(() => expect(onGenerate).not.toHaveBeenCalledTimes(1)); }); it('should stop generating when clicking the button', async () => { @@ -191,6 +189,45 @@ describe('GenAIButton', () => { expect(setShouldStopMock).toHaveBeenCalledTimes(1); expect(setShouldStopMock).toHaveBeenCalledWith(true); + expect(onGenerate).not.toHaveBeenCalled(); + }); + }); + + describe('when it is completed from generating data', () => { + const setShouldStopMock = jest.fn(); + + beforeEach(() => { + jest.mocked(useOpenAIStream).mockReturnValue({ + messages: [], + error: undefined, + streamStatus: StreamStatus.COMPLETED, + reply: 'Some completed generated text', + setMessages: jest.fn(), + setStopGeneration: setShouldStopMock, + value: { + enabled: true, + stream: new Observable().subscribe(), + }, + }); + }); + + it('should render improve text ', async () => { + setup(); + + waitFor(async () => expect(await screen.findByText('Improve')).toBeInTheDocument()); + }); + + it('should enable the button', async () => { + setup(); + waitFor(async () => expect(await screen.findByRole('button')).toBeEnabled()); + }); + + it('should call onGenerate when the text is completed', async () => { + const onGenerate = jest.fn(); + setup({ onGenerate, messages: [], eventTrackingSrc: eventTrackingSrc }); + + await waitFor(() => expect(onGenerate).toHaveBeenCalledTimes(1)); + expect(onGenerate).toHaveBeenCalledWith('Some completed generated text'); }); }); diff --git a/public/app/features/dashboard/components/GenAI/GenAIButton.tsx b/public/app/features/dashboard/components/GenAI/GenAIButton.tsx index 3c2647a9a2f0..c8e43b17c6e0 100644 --- a/public/app/features/dashboard/components/GenAI/GenAIButton.tsx +++ b/public/app/features/dashboard/components/GenAI/GenAIButton.tsx @@ -54,10 +54,11 @@ export const GenAIButton = ({ } = useOpenAIStream(model, temperature); const [history, setHistory] = useState([]); - const [showHistory, setShowHistory] = useState(true); + const [showHistory, setShowHistory] = useState(false); const hasHistory = history.length > 0; - const isFirstHistoryEntry = streamStatus === StreamStatus.GENERATING && !hasHistory; + const isGenerating = streamStatus === StreamStatus.GENERATING; + const isFirstHistoryEntry = !hasHistory; const isButtonDisabled = disabled || (value && !value.enabled && !error); const reportInteraction = (item: AutoGenerateItem) => reportAutoGenerateInteraction(eventTrackingSrc, item); @@ -69,19 +70,17 @@ export const GenAIButton = ({ onClickProp?.(e); setMessages(typeof messages === 'function' ? messages() : messages); } else { - if (setShowHistory) { - setShowHistory(true); - } + setShowHistory(true); } } const buttonItem = error ? AutoGenerateItem.erroredRetryButton - : isFirstHistoryEntry + : isGenerating ? AutoGenerateItem.stopGenerationButton - : hasHistory - ? AutoGenerateItem.improveButton - : AutoGenerateItem.autoGenerateButton; + : isFirstHistoryEntry + ? AutoGenerateItem.autoGenerateButton + : AutoGenerateItem.improveButton; reportInteraction(buttonItem); }; @@ -96,10 +95,10 @@ export const GenAIButton = ({ useEffect(() => { // Todo: Consider other options for `"` sanitation - if (isFirstHistoryEntry && reply) { + if (streamStatus === StreamStatus.COMPLETED && reply) { onGenerate(sanitizeReply(reply)); } - }, [streamStatus, reply, onGenerate, isFirstHistoryEntry]); + }, [streamStatus, reply, onGenerate]); useEffect(() => { if (streamStatus === StreamStatus.COMPLETED) { @@ -119,7 +118,7 @@ export const GenAIButton = ({ }; const getIcon = () => { - if (isFirstHistoryEntry) { + if (isGenerating) { return undefined; } if (error || (value && !value?.enabled)) { @@ -135,7 +134,7 @@ export const GenAIButton = ({ buttonText = 'Retry'; } - if (isFirstHistoryEntry) { + if (isGenerating) { buttonText = STOP_GENERATION_TEXT; } @@ -175,9 +174,11 @@ export const GenAIButton = ({ eventTrackingSrc={eventTrackingSrc} /> } - placement="bottom-start" + placement="left-start" fitContent={true} - show={showHistory ? undefined : false} + show={showHistory} + onClose={() => setShowHistory(false)} + onOpen={() => setShowHistory(true)} > {button} @@ -189,8 +190,8 @@ export const GenAIButton = ({ return (
- {isFirstHistoryEntry && } - {!hasHistory && ( + {isGenerating && } + {isFirstHistoryEntry ? ( {button} + ) : ( + renderButtonWithToggletip() )} - {hasHistory && renderButtonWithToggletip()}
); }; diff --git a/public/app/features/dashboard/components/GenAI/GenAIHistory.tsx b/public/app/features/dashboard/components/GenAI/GenAIHistory.tsx index 8b688f6992b6..3d1780d82864 100644 --- a/public/app/features/dashboard/components/GenAI/GenAIHistory.tsx +++ b/public/app/features/dashboard/components/GenAI/GenAIHistory.tsx @@ -2,18 +2,7 @@ import { css } from '@emotion/css'; import React, { useEffect, useState } from 'react'; import { GrafanaTheme2 } from '@grafana/data'; -import { - Alert, - Button, - HorizontalGroup, - Icon, - IconButton, - Input, - Text, - TextLink, - useStyles2, - VerticalGroup, -} from '@grafana/ui'; +import { Alert, Button, Icon, IconButton, Input, Stack, Text, TextLink, useStyles2 } from '@grafana/ui'; import { STOP_GENERATION_TEXT } from './GenAIButton'; import { GenerationHistoryCarousel } from './GenerationHistoryCarousel'; @@ -100,7 +89,9 @@ export const GenAIHistory = ({ const onGenerateWithFeedback = (suggestion: string | QuickFeedbackType) => { if (suggestion !== QuickFeedbackType.Regenerate) { - messages = [...messages, ...getFeedbackMessage(history[currentIndex], suggestion)]; + messages = [...messages, ...getFeedbackMessage(history[currentIndex - 1], suggestion)]; + } else { + messages = [...messages, ...getFeedbackMessage(history[currentIndex - 1], 'Please, regenerate')]; } setMessages(messages); @@ -122,13 +113,11 @@ export const GenAIHistory = ({ return (
{showError && ( -
- - -
Sorry, I was unable to complete your request. Please try again.
-
-
-
+ + +

Sorry, I was unable to complete your request. Please try again.

+
+
)}
- + - +
@@ -186,7 +175,7 @@ const getStyles = (theme: GrafanaTheme2) => ({ display: 'flex', flexDirection: 'column', width: 520, - height: 250, + maxHeight: 350, // This is the space the footer height paddingBottom: 35, }), diff --git a/public/app/features/dashboard/components/GenAI/hooks.ts b/public/app/features/dashboard/components/GenAI/hooks.ts index f8ae8968ee25..80bcc806d3fc 100644 --- a/public/app/features/dashboard/components/GenAI/hooks.ts +++ b/public/app/features/dashboard/components/GenAI/hooks.ts @@ -52,6 +52,8 @@ export function useOpenAIStream( const [streamStatus, setStreamStatus] = useState(StreamStatus.IDLE); const [error, setError] = useState(); const { error: notifyError } = useAppNotification(); + // Accumulate response and it will only update the state of the attatched component when the stream is completed. + let partialReply = ''; const onError = useCallback( (e: Error) => { @@ -69,6 +71,12 @@ export function useOpenAIStream( [messages, model, temperature, notifyError] ); + useEffect(() => { + if (messages.length > 0) { + setReply(''); + } + }, [messages]); + const { error: enabledError, value: enabled } = useAsync( async () => await isLLMPluginEnabled(), [isLLMPluginEnabled] @@ -102,9 +110,12 @@ export function useOpenAIStream( return { enabled, stream: stream.subscribe({ - next: setReply, + next: (reply) => { + partialReply = reply; + }, error: onError, complete: () => { + setReply(partialReply); setStreamStatus(StreamStatus.COMPLETED); setTimeout(() => { setStreamStatus(StreamStatus.IDLE); From fa8a096438503063bded5806534612738ba26f8c Mon Sep 17 00:00:00 2001 From: Kim Nylander <104772500+knylander-grafana@users.noreply.github.com> Date: Tue, 5 Mar 2024 11:47:25 -0500 Subject: [PATCH 037/138] [v10.4.x] [DOC] Add profile-traces intro material; update Pyroscope data source info (#83860) * [DOC] Add profile-traces intro material; update Pyroscope data source info (#83739) * Add profile-traces intro material; update Pyroscope data source info * Apply suggestions from code review Co-authored-by: Jack Baldry * Updates and file rename from review * Add PYROSCOPE_VERSION * Apply suggestions from code review * Format tables Signed-off-by: Jack Baldry * Apply suggestions from code review Co-authored-by: Jack Baldry Co-authored-by: Jennifer Villa * Apply suggestions from code review --------- Signed-off-by: Jack Baldry Co-authored-by: Jack Baldry Co-authored-by: Jennifer Villa (cherry picked from commit 57935250fdf5837db60472ef82e1d3ce9b11e9f5) * Chagnes from prettier --- docs/sources/_index.md | 1 + docs/sources/datasources/pyroscope/_index.md | 11 +- .../pyroscope/profiling-and-tracing.md | 16 +++ .../pyroscope-profile-tracing-intro.md | 123 ++++++++++++++++++ .../datasources/tempo-editor-traceql.md | 2 +- .../datasources/tempo-traces-to-profiles.md | 8 +- 6 files changed, 154 insertions(+), 7 deletions(-) create mode 100644 docs/sources/datasources/pyroscope/profiling-and-tracing.md create mode 100644 docs/sources/shared/datasources/pyroscope-profile-tracing-intro.md diff --git a/docs/sources/_index.md b/docs/sources/_index.md index 0ff6e3c74351..b6fb2f9a91f5 100644 --- a/docs/sources/_index.md +++ b/docs/sources/_index.md @@ -15,6 +15,7 @@ labels: - oss cascade: TEMPO_VERSION: latest + PYROSCOPE_VERSION: latest title: Grafana open source documentation --- diff --git a/docs/sources/datasources/pyroscope/_index.md b/docs/sources/datasources/pyroscope/_index.md index 88d5a1c88be8..8c7d7bc37c96 100644 --- a/docs/sources/datasources/pyroscope/_index.md +++ b/docs/sources/datasources/pyroscope/_index.md @@ -24,9 +24,13 @@ weight: 1150 Grafana Pyroscope is a horizontally scalable, highly available, multi-tenant, OSS, continuous profiling aggregation system. Add it as a data source, and you are ready to query your profiles in [Explore][explore]. -To learn more about profiling and Pyroscope, refer to the [Introduction to Pyroscope](/docs/pyroscope/introduction/). +Refer to [Introduction to Pyroscope](https://grafana.com/docs/pyroscope//introduction/) to understand profiling and Pyroscope. -For information on configuring the Pyroscope data source, refer to [Configure the Grafana Pyroscope data source](./configure-pyroscope-data-source). +To use profiling data, you should: + +- [Configure your application to send profiles](/docs/pyroscope//configure-client/) +- [Configure the Grafana Pyroscope data source](./configure-pyroscope-data-source/). +- [View and query profiling data in Explore](./query-profile-data/) ## Integrate profiles into dashboards @@ -38,12 +42,13 @@ In this case, the screenshot shows memory profiles alongside panels for logs and ## Visualize traces and profiles data using Traces to profiles You can link profile and tracing data using your Pyroscope data source with the Tempo data source. +To learn more about how profiles and tracing can work together, refer to [Profiling and tracing synergies](./profiling-and-tracing/). Combined traces and profiles let you see granular line-level detail when available for a trace span. This allows you pinpoint the exact function that's causing a bottleneck in your application as well as a specific request. ![trace-profiler-view](https://grafana.com/static/img/pyroscope/pyroscope-trace-profiler-view-2023-11-30.png) -For more information, refer to the [Traces to profile section][configure-tempo-data-source] of the Tempo data source documentation. +For more information, refer to the [Traces to profile section][configure-tempo-data-source] and [Link tracing and profiling with span profiles](https://grafana.com/docs/pyroscope//configure-client/trace-span-profiles/). {{< youtube id="AG8VzfFMLxo" >}} diff --git a/docs/sources/datasources/pyroscope/profiling-and-tracing.md b/docs/sources/datasources/pyroscope/profiling-and-tracing.md new file mode 100644 index 000000000000..98315f7c9963 --- /dev/null +++ b/docs/sources/datasources/pyroscope/profiling-and-tracing.md @@ -0,0 +1,16 @@ +--- +title: How profiling and tracing work together +menuTitle: How profiling and tracing work together +description: Learn about how profiling and tracing work together. +weight: 250 +keywords: + - pyroscope data source + - continuous profiling + - tracing +--- + +# How profiling and tracing work together + +[//]: # 'Shared content for Trace to profiles in the Pyroscope data source' + +{{< docs/shared source="grafana" lookup="datasources/pyroscope-profile-tracing-intro.md" version="" >}} diff --git a/docs/sources/shared/datasources/pyroscope-profile-tracing-intro.md b/docs/sources/shared/datasources/pyroscope-profile-tracing-intro.md new file mode 100644 index 000000000000..b7c9df002fcf --- /dev/null +++ b/docs/sources/shared/datasources/pyroscope-profile-tracing-intro.md @@ -0,0 +1,123 @@ +--- +headless: true +labels: + products: + - enterprise + - oss +--- + +[//]: # 'This file documents the introductory material for traces to profiling for the Pyroscope data source.' +[//]: # 'This shared file is included in these locations:' +[//]: # '/grafana/docs/sources/datasources/pyroscope/profiling-and-tracing.md' +[//]: # '/website/docs/grafana-cloud/data-configuration/traces/traces-query-editor.md' +[//]: # '/docs/sources/view-and-analyze-profile-data/profile-tracing/_index.md' +[//]: # +[//]: # 'If you make changes to this file, verify that the meaning and content are not changed in any place where the file is included.' +[//]: # 'Any links should be fully qualified and not relative: /docs/grafana/ instead of ../grafana/.' + + + +Profiles, continuous profiling, and distributed traces are all tools that can be used to improve the performance and reliability of applications. +However, each tool has its own strengths and weaknesses, and it is important to choose the right tool for the job as well as understand when to use both. + +## Profiling + +Profiling offers a deep-dive into an application's performance at the code level, highlighting resource usage and performance hotspots. + + + + + + + + + + + + + + +
UsageDuring development, major releases, or upon noticing performance quirks.
Benefits +
    +
  • Business: Boosts user experience through enhanced application performance.
  • +
  • Technical: Gives clear insights into code performance and areas of refinement.
  • +
+
ExampleA developer uses profiling upon noting slow app performance, identifies a CPU-heavy function, and optimizes it.
+ +## Continuous profiling + +Continuous profiling provides ongoing performance insights, capturing long-term trends and intermittent issues. + + + + + + + + + + + + + + +
UsageMainly in production, especially for high-priority applications.
Benefits +
    +
  • Business: Preemptively addresses inefficiencies, potentially saving costs.
  • +
  • Technical: Highlights performance trends and issues like potential memory leaks over time.
  • +
+
ExampleA month-long data from continuous profiling suggests increasing memory consumption, hinting at a memory leak.
+ +## Distributed tracing + +Traces requests as they cross multiple services, revealing interactions and service dependencies. + + + + + + + + + + + + + + +
UsageEssential for systems like microservices where requests touch multiple services.
Benefits +
    +
  • Business: Faster issue resolution, reduced downtimes, and strengthened customer trust.
  • +
  • Technical: A broad view of the system's structure, revealing bottlenecks and inter-service dependencies.
  • +
+
ExampleIn e-commerce, a user's checkout request might involve various services. Tracing depicts this route, pinpointing where time is most spent.
+ +## Combined power of tracing and profiling + +When used together, tracing and profiling provide a powerful tool for understanding system and application performance. + + + + + + + + + + + + + + +
UsageFor comprehensive system-to-code insights, especially when diagnosing complex issues spread across services and codebases.
Benefits +
    +
  • Business: Reduces downtime, optimizes user experience, and safeguards revenues.
  • +
  • Technical: +
      +
    • Holistic view: Tracing pinpoints bottle-necked services, while profiling delves into the responsible code segments.
    • +
    • End-to-end insight: Visualizes a request's full journey and the performance of individual code parts.
    • +
    • Efficient diagnosis: Tracing identifies service latency; profiling zeroes in on its cause, be it database queries, API calls, or specific code inefficiencies.
    • +
    +
  • +
+
ExampleTracing reveals latency in a payment service. Combined with profiling, it's found that a particular function, making third-party validation calls, is the culprit. This insight guides optimization, refining system efficiency.
diff --git a/docs/sources/shared/datasources/tempo-editor-traceql.md b/docs/sources/shared/datasources/tempo-editor-traceql.md index 1114609240cf..65e5a992dd46 100644 --- a/docs/sources/shared/datasources/tempo-editor-traceql.md +++ b/docs/sources/shared/datasources/tempo-editor-traceql.md @@ -95,7 +95,7 @@ Spans with the same color belong to the same service. The grey text to the right The Tempo data source supports streaming responses to TraceQL queries so you can see partial query results as they come in without waiting for the whole query to finish. {{% admonition type="note" %}} -To use this experimental feature, enable the `traceQLStreaming` feature toggle. If you’re using Grafana Cloud and would like to enable this feature, please contact customer support. +To use this feature in Grafana OSS v10.1 and later, enable the `traceQLStreaming` feature toggle. This capability is enabled by default in Grafana Cloud. {{% /admonition %}} Streaming is available for both the **Search** and **TraceQL** query types, and you'll get immediate visibility of incoming traces on the results table. diff --git a/docs/sources/shared/datasources/tempo-traces-to-profiles.md b/docs/sources/shared/datasources/tempo-traces-to-profiles.md index fde1964f20d1..9b9b81b05a30 100644 --- a/docs/sources/shared/datasources/tempo-traces-to-profiles.md +++ b/docs/sources/shared/datasources/tempo-traces-to-profiles.md @@ -29,14 +29,16 @@ There are two ways to configure the trace to profiles feature: - Configure a custom query where you can use a template language to interpolate variables from the trace or span. {{< admonition type="note">}} -Traces to profile requires a Tempo data source with Traces to profiles configured and a Pyroscope data source. This integration supports profile data generated using Go, Ruby, and Java instrumentation SDKs. +Traces to profile requires a Tempo data source with Traces to profiles configured and a Pyroscope data source. This integration supports profile data generated using [Go](/docs/pyroscope//configure-client/trace-span-profiles/go-span-profiles/), [Ruby](/docs/pyroscope//configure-client/trace-span-profiles/ruby-span-profiles/), and [Java](/docs/pyroscope//configure-client/trace-span-profiles/java-span-profiles/) instrumentation SDKs. + +As with traces, your application needs to be instrumented to emit profiling data. For more information, refer to [Linking tracing and profiling with span profiles](/docs/pyroscope//configure-client/trace-span-profiles/). {{< /admonition >}} To use trace to profiles, navigate to **Explore** and query a trace. Each span now links to your queries. Clicking a link runs the query in a split panel. If tags are configured, Grafana dynamically inserts the span attribute values into the query. The query runs over the time range of the (span start time - 60) to (span end time + 60 seconds). ![Selecting a link in the span queries the profile data source](/media/docs/tempo/profiles/tempo-trace-to-profile.png) -To use trace to profiles, you must have a configured Grafana Pyroscope data source. For more information, refer to the [Grafana Pyroscope data source](/docs/grafana/latest/datasources/grafana-pyroscope/) documentation. +To use trace to profiles, you must have a configured Grafana Pyroscope data source. For more information, refer to the [Grafana Pyroscope data source](/docs/grafana//datasources/grafana-pyroscope/) documentation. **Embedded flame graphs** are also inserted into each span details section that has a linked profile (requires a configured Grafana Pyroscope data source). This lets you see resource consumption in a flame graph visualization for each span without having to navigate away from the current view. @@ -70,7 +72,7 @@ To use a custom query with the configuration, follow these steps: 1. Select a Pyroscope data source from the **Data source** drop-down. 1. Optional: Choose any tags to use in the query. If left blank, the default values of `service.name` and `service.namespace` are used. - These tags can be used in the custom query with `${__tags}` variable. This variable interpolates the mapped tags as list in an appropriate syntax for the data source. Only the tags that were present in the span are included; tags that aren't present are omitted. You can also configure a new name for the tag. This is useful in cases where the tag has dots in the name and the target data source doesn't allow using dots in labels. For example, you can remap `service.name` to `service_name`. If you don’t map any tags here, you can still use any tag in the query, for example: `method="${__span.tags.method}"`. You can learn more about custom query variables [here](/docs/grafana/latest/datasources/tempo/configure-tempo-data-source/#custom-query-variables). + These tags can be used in the custom query with `${__tags}` variable. This variable interpolates the mapped tags as list in an appropriate syntax for the data source. Only the tags that were present in the span are included; tags that aren't present are omitted. You can also configure a new name for the tag. This is useful in cases where the tag has dots in the name and the target data source doesn't allow using dots in labels. For example, you can remap `service.name` to `service_name`. If you don’t map any tags here, you can still use any tag in the query, for example: `method="${__span.tags.method}"`. You can learn more about custom query variables [here](/docs/grafana//datasources/tempo/configure-tempo-data-source/#custom-query-variables). 1. Select one or more profile types to use in the query. Select the drop-down and choose options from the menu. 1. Switch on **Use custom query** to enter a custom query. From 9dcf8e650ffb504451f68f0a990a36a026cab513 Mon Sep 17 00:00:00 2001 From: Dave Henderson Date: Tue, 5 Mar 2024 16:44:27 -0500 Subject: [PATCH 038/138] [v10.4.x] chore: bump Go to 1.21.8 (#83937) chore: bump Go to 1.21.8 (#83927) * chore: bump Go to 1.21.8 Signed-off-by: Dave Henderson * bump workflows too Signed-off-by: Dave Henderson --------- Signed-off-by: Dave Henderson (cherry picked from commit 01fb2cff624e402b927e16f4e04e9fc35c7ab08c) --- .drone.yml | 208 ++++++++++---------- .github/workflows/alerting-swagger-gen.yml | 2 +- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/pr-codeql-analysis-go.yml | 2 +- .github/workflows/publish-kinds-next.yml | 2 +- .github/workflows/publish-kinds-release.yml | 2 +- .github/workflows/verify-kinds.yml | 2 +- Dockerfile | 2 +- Makefile | 2 +- scripts/drone/variables.star | 2 +- 10 files changed, 113 insertions(+), 113 deletions(-) diff --git a/.drone.yml b/.drone.yml index 8a5b62dba71c..db66b040ffd3 100644 --- a/.drone.yml +++ b/.drone.yml @@ -25,7 +25,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: compile-build-cmd - commands: - ./bin/build verify-drone @@ -76,14 +76,14 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: compile-build-cmd - commands: - go install github.com/bazelbuild/buildtools/buildifier@latest - buildifier --lint=warn -mode=check -r . depends_on: - compile-build-cmd - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: lint-starlark trigger: event: @@ -323,7 +323,7 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-cue depends_on: [] - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: verify-gen-cue - commands: - '# It is required that generated jsonnet is committed and in sync with its inputs.' @@ -332,21 +332,21 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-jsonnet depends_on: [] - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: verify-gen-jsonnet - commands: - apk add --update make - make gen-go depends_on: - verify-gen-cue - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: wire-install - commands: - apk add --update build-base shared-mime-info shared-mime-info-lang - go test -tags requires_buildifer -short -covermode=atomic -timeout=5m ./pkg/... depends_on: - wire-install - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: test-backend - commands: - apk add --update build-base @@ -355,7 +355,7 @@ steps: | grep -o '\(.*\)/' | sort -u) depends_on: - wire-install - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: test-backend-integration trigger: event: @@ -406,7 +406,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: compile-build-cmd - commands: - apk add --update curl jq bash @@ -433,7 +433,7 @@ steps: - apk add --update make - make gen-go depends_on: [] - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: wire-install - commands: - apk add --update make build-base @@ -442,16 +442,16 @@ steps: - wire-install environment: CGO_ENABLED: "1" - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: lint-backend - commands: - go run scripts/modowners/modowners.go check go.mod - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: validate-modfile - commands: - apk add --update make - make swagger-validate - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: validate-openapi-spec trigger: event: @@ -508,7 +508,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: compile-build-cmd - commands: - '# It is required that code generated from Thema/CUE be committed and in sync @@ -518,7 +518,7 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-cue depends_on: [] - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: verify-gen-cue - commands: - '# It is required that generated jsonnet is committed and in sync with its inputs.' @@ -527,14 +527,14 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-jsonnet depends_on: [] - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: verify-gen-jsonnet - commands: - apk add --update make - make gen-go depends_on: - verify-gen-cue - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: wire-install - commands: - apk add --update g++ make python3 && ln -sf /usr/bin/python3 /usr/bin/python @@ -568,7 +568,7 @@ steps: from_secret: drone_token - commands: - /src/grafana-build artifacts -a targz:grafana:linux/amd64 -a targz:grafana:linux/arm64 - -a targz:grafana:linux/arm/v7 --go-version=1.21.6 --yarn-cache=$$YARN_CACHE_FOLDER + -a targz:grafana:linux/arm/v7 --go-version=1.21.8 --yarn-cache=$$YARN_CACHE_FOLDER --build-id=$$DRONE_BUILD_NUMBER --grafana-dir=$$PWD > packages.txt depends_on: - yarn-install @@ -718,7 +718,7 @@ steps: - /src/grafana-build artifacts -a docker:grafana:linux/amd64 -a docker:grafana:linux/amd64:ubuntu -a docker:grafana:linux/arm64 -a docker:grafana:linux/arm64:ubuntu -a docker:grafana:linux/arm/v7 -a docker:grafana:linux/arm/v7:ubuntu --yarn-cache=$$YARN_CACHE_FOLDER --build-id=$$DRONE_BUILD_NUMBER - --go-version=1.21.6 --ubuntu-base=ubuntu:22.04 --alpine-base=alpine:3.19.1 --tag-format='{{ + --go-version=1.21.8 --ubuntu-base=ubuntu:22.04 --alpine-base=alpine:3.19.1 --tag-format='{{ .version_base }}-{{ .buildID }}-{{ .arch }}' --grafana-dir=$$PWD --ubuntu-tag-format='{{ .version_base }}-{{ .buildID }}-ubuntu-{{ .arch }}' > docker.txt - find ./dist -name '*docker*.tar.gz' -type f | xargs -n1 docker load -i @@ -862,7 +862,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: compile-build-cmd - commands: - echo $DRONE_RUNNER_NAME @@ -876,7 +876,7 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-cue depends_on: [] - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: verify-gen-cue - commands: - '# It is required that generated jsonnet is committed and in sync with its inputs.' @@ -885,14 +885,14 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-jsonnet depends_on: [] - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: verify-gen-jsonnet - commands: - apk add --update make - make gen-go depends_on: - verify-gen-cue - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: wire-install - commands: - dockerize -wait tcp://postgres:5432 -timeout 120s @@ -913,7 +913,7 @@ steps: GRAFANA_TEST_DB: postgres PGPASSWORD: grafanatest POSTGRES_HOST: postgres - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: postgres-integration-tests - commands: - dockerize -wait tcp://mysql57:3306 -timeout 120s @@ -934,7 +934,7 @@ steps: environment: GRAFANA_TEST_DB: mysql MYSQL_HOST: mysql57 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: mysql-5.7-integration-tests - commands: - dockerize -wait tcp://mysql80:3306 -timeout 120s @@ -955,7 +955,7 @@ steps: environment: GRAFANA_TEST_DB: mysql MYSQL_HOST: mysql80 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: mysql-8.0-integration-tests - commands: - dockerize -wait tcp://redis:6379 -timeout 120s @@ -970,7 +970,7 @@ steps: - wait-for-redis environment: REDIS_URL: redis://redis:6379/0 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: redis-integration-tests - commands: - dockerize -wait tcp://memcached:11211 -timeout 120s @@ -985,7 +985,7 @@ steps: - wait-for-memcached environment: MEMCACHED_HOSTS: memcached:11211 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: memcached-integration-tests - commands: - dockerize -wait tcp://mimir_backend:8080 -timeout 120s @@ -1001,7 +1001,7 @@ steps: environment: AM_TENANT_ID: test AM_URL: http://mimir_backend:8080 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: remote-alertmanager-integration-tests trigger: event: @@ -1090,7 +1090,7 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-cue depends_on: [] - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: verify-gen-cue trigger: event: @@ -1131,7 +1131,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: compile-build-cmd - commands: - apt-get update -yq && apt-get install shellcheck @@ -1199,7 +1199,7 @@ steps: environment: GITHUB_TOKEN: from_secret: github_token - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: swagger-gen trigger: event: @@ -1301,7 +1301,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: compile-build-cmd - commands: - '# It is required that code generated from Thema/CUE be committed and in sync @@ -1312,7 +1312,7 @@ steps: - CODEGEN_VERIFY=1 make gen-cue depends_on: - clone-enterprise - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: verify-gen-cue - commands: - '# It is required that generated jsonnet is committed and in sync with its inputs.' @@ -1322,14 +1322,14 @@ steps: - CODEGEN_VERIFY=1 make gen-jsonnet depends_on: - clone-enterprise - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: verify-gen-jsonnet - commands: - apk add --update make - make gen-go depends_on: - verify-gen-cue - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: wire-install - commands: - apk add --update build-base @@ -1337,7 +1337,7 @@ steps: - go test -v -run=^$ -benchmem -timeout=1h -count=8 -bench=. ${GO_PACKAGES} depends_on: - wire-install - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: sqlite-benchmark-integration-tests - commands: - apk add --update build-base @@ -1349,7 +1349,7 @@ steps: GRAFANA_TEST_DB: postgres PGPASSWORD: grafanatest POSTGRES_HOST: postgres - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: postgres-benchmark-integration-tests - commands: - apk add --update build-base @@ -1360,7 +1360,7 @@ steps: environment: GRAFANA_TEST_DB: mysql MYSQL_HOST: mysql57 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: mysql-5.7-benchmark-integration-tests - commands: - apk add --update build-base @@ -1371,7 +1371,7 @@ steps: environment: GRAFANA_TEST_DB: mysql MYSQL_HOST: mysql80 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: mysql-8.0-benchmark-integration-tests trigger: event: @@ -1450,7 +1450,7 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-cue depends_on: [] - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: verify-gen-cue trigger: branch: main @@ -1627,7 +1627,7 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-cue depends_on: [] - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: verify-gen-cue - commands: - '# It is required that generated jsonnet is committed and in sync with its inputs.' @@ -1636,21 +1636,21 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-jsonnet depends_on: [] - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: verify-gen-jsonnet - commands: - apk add --update make - make gen-go depends_on: - verify-gen-cue - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: wire-install - commands: - apk add --update build-base shared-mime-info shared-mime-info-lang - go test -tags requires_buildifer -short -covermode=atomic -timeout=5m ./pkg/... depends_on: - wire-install - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: test-backend - commands: - apk add --update build-base @@ -1659,7 +1659,7 @@ steps: | grep -o '\(.*\)/' | sort -u) depends_on: - wire-install - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: test-backend-integration trigger: branch: main @@ -1704,13 +1704,13 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: compile-build-cmd - commands: - apk add --update make - make gen-go depends_on: [] - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: wire-install - commands: - apk add --update make build-base @@ -1719,16 +1719,16 @@ steps: - wire-install environment: CGO_ENABLED: "1" - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: lint-backend - commands: - go run scripts/modowners/modowners.go check go.mod - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: validate-modfile - commands: - apk add --update make - make swagger-validate - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: validate-openapi-spec - commands: - ./bin/build verify-drone @@ -1785,7 +1785,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: compile-build-cmd - commands: - '# It is required that code generated from Thema/CUE be committed and in sync @@ -1795,7 +1795,7 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-cue depends_on: [] - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: verify-gen-cue - commands: - '# It is required that generated jsonnet is committed and in sync with its inputs.' @@ -1804,14 +1804,14 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-jsonnet depends_on: [] - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: verify-gen-jsonnet - commands: - apk add --update make - make gen-go depends_on: - verify-gen-cue - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: wire-install - commands: - apk add --update g++ make python3 && ln -sf /usr/bin/python3 /usr/bin/python @@ -1844,7 +1844,7 @@ steps: name: build-frontend-packages - commands: - /src/grafana-build artifacts -a targz:grafana:linux/amd64 -a targz:grafana:linux/arm64 - -a targz:grafana:linux/arm/v7 --go-version=1.21.6 --yarn-cache=$$YARN_CACHE_FOLDER + -a targz:grafana:linux/arm/v7 --go-version=1.21.8 --yarn-cache=$$YARN_CACHE_FOLDER --build-id=$$DRONE_BUILD_NUMBER --grafana-dir=$$PWD > packages.txt depends_on: - update-package-json-version @@ -2030,7 +2030,7 @@ steps: - /src/grafana-build artifacts -a docker:grafana:linux/amd64 -a docker:grafana:linux/amd64:ubuntu -a docker:grafana:linux/arm64 -a docker:grafana:linux/arm64:ubuntu -a docker:grafana:linux/arm/v7 -a docker:grafana:linux/arm/v7:ubuntu --yarn-cache=$$YARN_CACHE_FOLDER --build-id=$$DRONE_BUILD_NUMBER - --go-version=1.21.6 --ubuntu-base=ubuntu:22.04 --alpine-base=alpine:3.19.1 --tag-format='{{ + --go-version=1.21.8 --ubuntu-base=ubuntu:22.04 --alpine-base=alpine:3.19.1 --tag-format='{{ .version_base }}-{{ .buildID }}-{{ .arch }}' --grafana-dir=$$PWD --ubuntu-tag-format='{{ .version_base }}-{{ .buildID }}-ubuntu-{{ .arch }}' > docker.txt - find ./dist -name '*docker*.tar.gz' -type f | xargs -n1 docker load -i @@ -2236,7 +2236,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: compile-build-cmd - commands: - echo $DRONE_RUNNER_NAME @@ -2250,7 +2250,7 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-cue depends_on: [] - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: verify-gen-cue - commands: - '# It is required that generated jsonnet is committed and in sync with its inputs.' @@ -2259,14 +2259,14 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-jsonnet depends_on: [] - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: verify-gen-jsonnet - commands: - apk add --update make - make gen-go depends_on: - verify-gen-cue - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: wire-install - commands: - dockerize -wait tcp://postgres:5432 -timeout 120s @@ -2287,7 +2287,7 @@ steps: GRAFANA_TEST_DB: postgres PGPASSWORD: grafanatest POSTGRES_HOST: postgres - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: postgres-integration-tests - commands: - dockerize -wait tcp://mysql57:3306 -timeout 120s @@ -2308,7 +2308,7 @@ steps: environment: GRAFANA_TEST_DB: mysql MYSQL_HOST: mysql57 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: mysql-5.7-integration-tests - commands: - dockerize -wait tcp://mysql80:3306 -timeout 120s @@ -2329,7 +2329,7 @@ steps: environment: GRAFANA_TEST_DB: mysql MYSQL_HOST: mysql80 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: mysql-8.0-integration-tests - commands: - dockerize -wait tcp://redis:6379 -timeout 120s @@ -2344,7 +2344,7 @@ steps: - wait-for-redis environment: REDIS_URL: redis://redis:6379/0 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: redis-integration-tests - commands: - dockerize -wait tcp://memcached:11211 -timeout 120s @@ -2359,7 +2359,7 @@ steps: - wait-for-memcached environment: MEMCACHED_HOSTS: memcached:11211 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: memcached-integration-tests - commands: - dockerize -wait tcp://mimir_backend:8080 -timeout 120s @@ -2375,7 +2375,7 @@ steps: environment: AM_TENANT_ID: test AM_URL: http://mimir_backend:8080 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: remote-alertmanager-integration-tests trigger: branch: main @@ -2568,7 +2568,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: compile-build-cmd - commands: - ./bin/build artifacts docker fetch --edition oss @@ -2665,7 +2665,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: compile-build-cmd - commands: - ./bin/build artifacts packages --tag $${DRONE_TAG} --src-bucket $${PRERELEASE_BUCKET} @@ -2735,7 +2735,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: compile-build-cmd - commands: - apk add --update g++ make python3 && ln -sf /usr/bin/python3 /usr/bin/python @@ -2802,7 +2802,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: compile-build-cmd - depends_on: - compile-build-cmd @@ -2909,7 +2909,7 @@ steps: from_secret: gcp_key_base64 GITHUB_TOKEN: from_secret: github_token - GO_VERSION: 1.21.6 + GO_VERSION: 1.21.8 GPG_PASSPHRASE: from_secret: packages_gpg_passphrase GPG_PRIVATE_KEY: @@ -2967,13 +2967,13 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: compile-build-cmd - commands: - ./bin/build whatsnew-checker depends_on: - compile-build-cmd - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: whats-new-checker trigger: event: @@ -3076,7 +3076,7 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-cue depends_on: [] - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: verify-gen-cue - commands: - '# It is required that generated jsonnet is committed and in sync with its inputs.' @@ -3085,21 +3085,21 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-jsonnet depends_on: [] - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: verify-gen-jsonnet - commands: - apk add --update make - make gen-go depends_on: - verify-gen-cue - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: wire-install - commands: - apk add --update build-base shared-mime-info shared-mime-info-lang - go test -tags requires_buildifer -short -covermode=atomic -timeout=5m ./pkg/... depends_on: - wire-install - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: test-backend - commands: - apk add --update build-base @@ -3108,7 +3108,7 @@ steps: | grep -o '\(.*\)/' | sort -u) depends_on: - wire-install - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: test-backend-integration trigger: event: @@ -3165,7 +3165,7 @@ steps: from_secret: gcp_key_base64 GITHUB_TOKEN: from_secret: github_token - GO_VERSION: 1.21.6 + GO_VERSION: 1.21.8 GPG_PASSPHRASE: from_secret: packages_gpg_passphrase GPG_PRIVATE_KEY: @@ -3348,7 +3348,7 @@ steps: from_secret: gcp_key_base64 GITHUB_TOKEN: from_secret: github_token - GO_VERSION: 1.21.6 + GO_VERSION: 1.21.8 GPG_PASSPHRASE: from_secret: packages_gpg_passphrase GPG_PRIVATE_KEY: @@ -3498,7 +3498,7 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-cue depends_on: [] - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: verify-gen-cue - commands: - '# It is required that generated jsonnet is committed and in sync with its inputs.' @@ -3507,21 +3507,21 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-jsonnet depends_on: [] - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: verify-gen-jsonnet - commands: - apk add --update make - make gen-go depends_on: - verify-gen-cue - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: wire-install - commands: - apk add --update build-base shared-mime-info shared-mime-info-lang - go test -tags requires_buildifer -short -covermode=atomic -timeout=5m ./pkg/... depends_on: - wire-install - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: test-backend - commands: - apk add --update build-base @@ -3530,7 +3530,7 @@ steps: | grep -o '\(.*\)/' | sort -u) depends_on: - wire-install - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: test-backend-integration trigger: cron: @@ -3585,7 +3585,7 @@ steps: from_secret: gcp_key_base64 GITHUB_TOKEN: from_secret: github_token - GO_VERSION: 1.21.6 + GO_VERSION: 1.21.8 GPG_PASSPHRASE: from_secret: packages_gpg_passphrase GPG_PRIVATE_KEY: @@ -3732,7 +3732,7 @@ steps: from_secret: gcp_key_base64 GITHUB_TOKEN: from_secret: github_token - GO_VERSION: 1.21.6 + GO_VERSION: 1.21.8 GPG_PASSPHRASE: from_secret: packages_gpg_passphrase GPG_PRIVATE_KEY: @@ -3841,7 +3841,7 @@ steps: from_secret: gcp_key_base64 GITHUB_TOKEN: from_secret: github_token - GO_VERSION: 1.21.6 + GO_VERSION: 1.21.8 GPG_PASSPHRASE: from_secret: packages_gpg_passphrase GPG_PRIVATE_KEY: @@ -3931,20 +3931,20 @@ steps: - commands: [] depends_on: - clone - image: golang:1.21.6-windowsservercore-1809 + image: golang:1.21.8-windowsservercore-1809 name: windows-init - commands: - go install github.com/google/wire/cmd/wire@v0.5.0 - wire gen -tags oss ./pkg/server depends_on: - windows-init - image: golang:1.21.6-windowsservercore-1809 + image: golang:1.21.8-windowsservercore-1809 name: wire-install - commands: - go test -tags requires_buildifer -short -covermode=atomic -timeout=5m ./pkg/... depends_on: - wire-install - image: golang:1.21.6-windowsservercore-1809 + image: golang:1.21.8-windowsservercore-1809 name: test-backend trigger: event: @@ -4037,7 +4037,7 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-cue depends_on: [] - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: verify-gen-cue - commands: - '# It is required that generated jsonnet is committed and in sync with its inputs.' @@ -4046,14 +4046,14 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-jsonnet depends_on: [] - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: verify-gen-jsonnet - commands: - apk add --update make - make gen-go depends_on: - verify-gen-cue - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: wire-install - commands: - dockerize -wait tcp://postgres:5432 -timeout 120s @@ -4074,7 +4074,7 @@ steps: GRAFANA_TEST_DB: postgres PGPASSWORD: grafanatest POSTGRES_HOST: postgres - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: postgres-integration-tests - commands: - dockerize -wait tcp://mysql57:3306 -timeout 120s @@ -4095,7 +4095,7 @@ steps: environment: GRAFANA_TEST_DB: mysql MYSQL_HOST: mysql57 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: mysql-5.7-integration-tests - commands: - dockerize -wait tcp://mysql80:3306 -timeout 120s @@ -4116,7 +4116,7 @@ steps: environment: GRAFANA_TEST_DB: mysql MYSQL_HOST: mysql80 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: mysql-8.0-integration-tests - commands: - dockerize -wait tcp://redis:6379 -timeout 120s @@ -4131,7 +4131,7 @@ steps: - wait-for-redis environment: REDIS_URL: redis://redis:6379/0 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: redis-integration-tests - commands: - dockerize -wait tcp://memcached:11211 -timeout 120s @@ -4146,7 +4146,7 @@ steps: - wait-for-memcached environment: MEMCACHED_HOSTS: memcached:11211 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: memcached-integration-tests - commands: - dockerize -wait tcp://mimir_backend:8080 -timeout 120s @@ -4162,7 +4162,7 @@ steps: environment: AM_TENANT_ID: test AM_URL: http://mimir_backend:8080 - image: golang:1.21.6-alpine + image: golang:1.21.8-alpine name: remote-alertmanager-integration-tests trigger: event: @@ -4516,7 +4516,7 @@ steps: path: /root/.docker/ - commands: - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM alpine/git:2.40.1 - - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM golang:1.21.6-alpine + - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM golang:1.21.8-alpine - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM node:20.9.0-alpine - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM google/cloud-sdk:431.0.0 - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM grafana/grafana-ci-deploy:1.3.3 @@ -4550,7 +4550,7 @@ steps: path: /root/.docker/ - commands: - trivy --exit-code 1 --severity HIGH,CRITICAL alpine/git:2.40.1 - - trivy --exit-code 1 --severity HIGH,CRITICAL golang:1.21.6-alpine + - trivy --exit-code 1 --severity HIGH,CRITICAL golang:1.21.8-alpine - trivy --exit-code 1 --severity HIGH,CRITICAL node:20.9.0-alpine - trivy --exit-code 1 --severity HIGH,CRITICAL google/cloud-sdk:431.0.0 - trivy --exit-code 1 --severity HIGH,CRITICAL grafana/grafana-ci-deploy:1.3.3 @@ -4804,6 +4804,6 @@ kind: secret name: gcr_credentials --- kind: signature -hmac: b26b23c44efb37e0868731724ff9c86471347f942e6281c011f83830bfe4517f +hmac: 2efd2831b156aaa63917767d65a92990e0c85e7d24ffb9f69f0374499b4a2973 ... diff --git a/.github/workflows/alerting-swagger-gen.yml b/.github/workflows/alerting-swagger-gen.yml index a9abc4f57829..5e7b7baa99eb 100644 --- a/.github/workflows/alerting-swagger-gen.yml +++ b/.github/workflows/alerting-swagger-gen.yml @@ -16,7 +16,7 @@ jobs: - name: Set go version uses: actions/setup-go@v4 with: - go-version: '1.21.6' + go-version: '1.21.8' - name: Build swagger run: | make -C pkg/services/ngalert/api/tooling post.json api.json diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 455633da8ecf..e8fafcf0bc29 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -47,7 +47,7 @@ jobs: name: Set go version uses: actions/setup-go@v4 with: - go-version: '1.21.6' + go-version: '1.21.8' # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/pr-codeql-analysis-go.yml b/.github/workflows/pr-codeql-analysis-go.yml index 4d9cc3760a6c..e414c6dcc250 100644 --- a/.github/workflows/pr-codeql-analysis-go.yml +++ b/.github/workflows/pr-codeql-analysis-go.yml @@ -35,7 +35,7 @@ jobs: - name: Set go version uses: actions/setup-go@v4 with: - go-version: '1.21.6' + go-version: '1.21.8' # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/publish-kinds-next.yml b/.github/workflows/publish-kinds-next.yml index 618411fd0889..7dc3cedb741b 100644 --- a/.github/workflows/publish-kinds-next.yml +++ b/.github/workflows/publish-kinds-next.yml @@ -36,7 +36,7 @@ jobs: - name: "Setup Go" uses: "actions/setup-go@v4" with: - go-version: '1.21.6' + go-version: '1.21.8' - name: "Verify kinds" run: go run .github/workflows/scripts/kinds/verify-kinds.go diff --git a/.github/workflows/publish-kinds-release.yml b/.github/workflows/publish-kinds-release.yml index 0a2a013737ab..acdfcbcb0b5b 100644 --- a/.github/workflows/publish-kinds-release.yml +++ b/.github/workflows/publish-kinds-release.yml @@ -39,7 +39,7 @@ jobs: - name: "Setup Go" uses: "actions/setup-go@v4" with: - go-version: '1.21.6' + go-version: '1.21.8' - name: "Verify kinds" run: go run .github/workflows/scripts/kinds/verify-kinds.go diff --git a/.github/workflows/verify-kinds.yml b/.github/workflows/verify-kinds.yml index 9107bed450af..007abd0b9a23 100644 --- a/.github/workflows/verify-kinds.yml +++ b/.github/workflows/verify-kinds.yml @@ -18,7 +18,7 @@ jobs: - name: "Setup Go" uses: "actions/setup-go@v4" with: - go-version: '1.21.6' + go-version: '1.21.8' - name: "Verify kinds" run: go run .github/workflows/scripts/kinds/verify-kinds.go diff --git a/Dockerfile b/Dockerfile index 9f41c4c048e9..5c4d3d032fd9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ ARG BASE_IMAGE=alpine:3.18.5 ARG JS_IMAGE=node:20-alpine3.18 ARG JS_PLATFORM=linux/amd64 -ARG GO_IMAGE=golang:1.21.6-alpine3.18 +ARG GO_IMAGE=golang:1.21.8-alpine3.18 ARG GO_SRC=go-builder ARG JS_SRC=js-builder diff --git a/Makefile b/Makefile index cd49a4230532..25904afef590 100644 --- a/Makefile +++ b/Makefile @@ -256,7 +256,7 @@ build-docker-full-ubuntu: ## Build Docker image based on Ubuntu for development. --build-arg COMMIT_SHA=$$(git rev-parse HEAD) \ --build-arg BUILD_BRANCH=$$(git rev-parse --abbrev-ref HEAD) \ --build-arg BASE_IMAGE=ubuntu:22.04 \ - --build-arg GO_IMAGE=golang:1.21.6 \ + --build-arg GO_IMAGE=golang:1.21.8 \ --tag grafana/grafana$(TAG_SUFFIX):dev-ubuntu \ $(DOCKER_BUILD_ARGS) diff --git a/scripts/drone/variables.star b/scripts/drone/variables.star index bc118eedaa3f..d2965ed0d92f 100644 --- a/scripts/drone/variables.star +++ b/scripts/drone/variables.star @@ -3,7 +3,7 @@ global variables """ grabpl_version = "v3.0.50" -golang_version = "1.21.6" +golang_version = "1.21.8" # nodejs_version should match what's in ".nvmrc", but without the v prefix. nodejs_version = "20.9.0" From 23320f3cabc1135d2078b212b4da7fd07d1fb223 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Tue, 5 Mar 2024 22:06:36 -0500 Subject: [PATCH 039/138] =?UTF-8?q?[v10.4.x]=20Docs:=20What=E2=80=99s=20ne?= =?UTF-8?q?w=20&=20Upgrade=20guide=2010.4=20(#83944)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docs: What’s new & Upgrade guide 10.4 (#83133) * Updated index pages and added v10.4 breaking changes, upgrade guide, and what's new pages * Added what's new entries * Removed empty headings * Fixed link * Removed duplicate entry and fixed styling * Removed breaking changes page and references to it * Added intro text * Docs: 10.4 technical note for alertingUpgradeDryrunOnStart (#83262) * Docs: 10.4 technical note for alertingUpgradeDryrunOnStart * Apply suggestions from code review Co-authored-by: Isabel <76437239+imatwawana@users.noreply.github.com> * Address PR comments * restarts -> starts --------- Co-authored-by: Isabel <76437239+imatwawana@users.noreply.github.com> * Fixed spelling * Added new entries to What's new * reorder and add intro * Added PagerDuty data source entry * Added entries * Added new entries * Fixed formatting * Fixed page weight and links * Apply suggestion from review Co-authored-by: Mitch Seaman * remove team lbac, move return to previous (#83921) - Remove Team LBAC for Loki (it is Cloud only) - Move Return to Previous into the Alerting section, since it only works for Alerting now - Add a note that data sources are separate from Grafana but included for visibility * Replaced manual note with admonition shortcode * move Return to Previous out of Alerting section * Added youtube links * Commented out youtube videos and removed duplicate video embed --------- Co-authored-by: Matthew Jacobson Co-authored-by: Mitchel Seaman Co-authored-by: Mitch Seaman (cherry picked from commit db13c0839fa6061b6598e8d6749256127577e4d4) Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --- docs/sources/_index.md | 4 +- .../upgrade-guide/upgrade-v10.4/index.md | 37 +++ docs/sources/whatsnew/_index.md | 1 + docs/sources/whatsnew/whats-new-in-v10-4.md | 266 ++++++++++++++++++ 4 files changed, 306 insertions(+), 2 deletions(-) create mode 100644 docs/sources/upgrade-guide/upgrade-v10.4/index.md create mode 100644 docs/sources/whatsnew/whats-new-in-v10-4.md diff --git a/docs/sources/_index.md b/docs/sources/_index.md index b6fb2f9a91f5..2ef3f960b46b 100644 --- a/docs/sources/_index.md +++ b/docs/sources/_index.md @@ -82,8 +82,8 @@ title: Grafana open source documentation

Provisioning

Learn how to automate your Grafana configuration.

- }}" class="nav-cards__item nav-cards__item--guide"> -

What's new in v10.3

+
}}" class="nav-cards__item nav-cards__item--guide"> +

What's new in v10.4

Explore the features and enhancements in the latest release.

diff --git a/docs/sources/upgrade-guide/upgrade-v10.4/index.md b/docs/sources/upgrade-guide/upgrade-v10.4/index.md new file mode 100644 index 000000000000..678641ec4cc4 --- /dev/null +++ b/docs/sources/upgrade-guide/upgrade-v10.4/index.md @@ -0,0 +1,37 @@ +--- +description: Guide for upgrading to Grafana v10.4 +keywords: + - grafana + - configuration + - documentation + - upgrade + - '10.4' +title: Upgrade to Grafana v10.4 +menuTitle: Upgrade to v10.4 +weight: 1300 +--- + +# Upgrade to Grafana v10.4 + +{{< docs/shared lookup="upgrade/intro.md" source="grafana" version="" >}} + +{{< docs/shared lookup="back-up/back-up-grafana.md" source="grafana" version="" leveloffset="+1" >}} + +{{< docs/shared lookup="upgrade/upgrade-common-tasks.md" source="grafana" version="" >}} + +## Technical notes + +### Legacy alerting -> Grafana Alerting dry-run on start + +If you haven't already upgraded to Grafana Alerting from legacy Alerting, Grafana will initiate a dry-run of the upgrade every time the instance starts. This is in preparation for the removal of legacy Alerting in Grafana v11. The dry-run logs the results of the upgrade attempt and identifies any issues requiring attention before you can successfully execute the upgrade. No changes are made during the dry-run. + +You can disable this behavior using the feature flag `alertingUpgradeDryrunOnStart`: + +```toml +[feature_toggles] +alertingUpgradeDryrunOnStart=false +``` + +{{% admonition type="note" %}} +We strongly encourage you to review the [upgrade guide](https://grafana.com/docs/grafana/v10.4/alerting/set-up/migrating-alerts/) and perform the necessary upgrade steps prior to v11. +{{% /admonition %}} diff --git a/docs/sources/whatsnew/_index.md b/docs/sources/whatsnew/_index.md index daac47235ff4..5e7be79bb36d 100644 --- a/docs/sources/whatsnew/_index.md +++ b/docs/sources/whatsnew/_index.md @@ -76,6 +76,7 @@ For a complete list of every change, with links to pull requests and related iss ## Grafana 10 +- [What's new in 10.4](https://grafana.com/docs/grafana//whatsnew/whats-new-in-v10-4/) - [What's new in 10.3](https://grafana.com/docs/grafana//whatsnew/whats-new-in-v10-3/) - [What's new in 10.2](https://grafana.com/docs/grafana//whatsnew/whats-new-in-v10-2/) - [What's new in 10.1]({{< relref "whats-new-in-v10-1/" >}}) diff --git a/docs/sources/whatsnew/whats-new-in-v10-4.md b/docs/sources/whatsnew/whats-new-in-v10-4.md new file mode 100644 index 000000000000..f1106a21b642 --- /dev/null +++ b/docs/sources/whatsnew/whats-new-in-v10-4.md @@ -0,0 +1,266 @@ +--- +description: Feature and improvement highlights for Grafana v10.4 +keywords: + - grafana + - new + - documentation + - '10.4' + - release notes +labels: +products: + - cloud + - enterprise + - oss +title: What's new in Grafana v10.4 +weight: -41 +--- + +# What’s new in Grafana v10.4 + +Welcome to Grafana 10.4! This minor release contains some notable improvements in its own right, as well as early previews of functionality we intend to turn on by default in Grafana v11. Read on to learn about a quicker way to set up alert notifications, an all-new UI for configuring single sign-on, and improvements to our Canvas, Geomap, and Table panels. + +For even more detail about all the changes in this release, refer to the [changelog](https://github.com/grafana/grafana/blob/main/CHANGELOG.md). For the specific steps we recommend when you upgrade to v10.4, check out our [Upgrade Guide](https://grafana.com/docs/grafana//upgrade-guide/upgrade-v10.4/). + + + + + + + +## Dashboards and visualizations + +### AngularJS plugin warnings in dashboards + + + +_Generally available in all editions of Grafana_ + +AngularJS support in Grafana was deprecated in v9 and will be turned off by default in Grafana v11. When this happens, any plugin which depended on AngularJS will not load, and dashboard panels will be unable to show data. + +To help you understand where you may be impacted, Grafana now displays a warning banner in any dashboard with a dependency on an AngularJS plugin. Additionally, warning icons are present in any panel where the panel plugin or underlying data source plugin has an AngularJS dependency. + +This complements the existing warnings already present on the **Plugins** page under the administration menu. + +In addition, you can use our [detect-angular-dashboards](https://github.com/grafana/detect-angular-dashboards) open source tool, which can be run against any Grafana instance to generate a report listing all dashboards that have a dependency on an AngularJS plugin, as well as which plugins are in use. This tool also supports the detection of [private plugins](https://grafana.com/legal/plugins/) that are dependent on AngularJS, however this particular feature requires Grafana v10.1.0 or higher. + +Use the aforementioned tooling and warnings to plan migrations to React based [visualizations](https://grafana.com/docs/grafana/latest/panels-visualizations/) and [data sources](https://grafana.com/docs/grafana/latest/datasources/) included in Grafana or from the [Grafana plugins catalog](https://grafana.com/grafana/plugins/). + +To learn more, refer to the [Angular support deprecation](https://grafana.com/docs/grafana//developers/angular_deprecation/), which includes [recommended alternative plugins](https://grafana.com/docs/grafana//developers/angular_deprecation/angular-plugins/). + + + +[Documentation](https://grafana.com/docs/grafana//developers/angular_deprecation/) + +### Data visualization quality of life improvements + + + +_Generally available in all editions of Grafana_ + +We’ve made a number of small improvements to the data visualization experience in Grafana. + +#### Geomap geojson layer now supports styling + +You can now visualize geojson styles such as polygons, point color/size, and line strings. To learn more, [refer to the documentation](https://grafana.com/docs/grafana//panels-visualizations/visualizations/geomap/#geojson-layer). + +![Geomap marker symbol alignment](/media/docs/grafana/screenshot-grafana-10-4-geomap-geojson-styling-support.png) + +#### Canvas elements now support snapping and aligning + +You can precisely place elements in a canvas with ease as elements now snap into place and align with one another. + +{{< video-embed src="/media/docs/grafana/screen-recording-10-4-canvas-element-snapping.mp4" caption="Canvas element snapping and alignment" >}} + +#### View data links inline in table visualizations + +You can now view your data links inline to help you keep your tables visually streamlined. + +![Table inline datalink support](/media/docs/grafana/gif-grafana-10-4-table-inline-datalink.gif) + +### Create subtables in table visualizations with Group to nested tables + + + +_Available in public preview in all editions of Grafana_ + +You can now create subtables out of your data using the new **Group to nested tables** transformation. To use this feature, enable the `groupToNestedTableTransformation` [feature toggle](https://grafana.com/docs/grafana//setup-grafana/configure-grafana/feature-toggles/#preview-feature-toggles). + +{{< video-embed src="/media/docs/grafana/screen-recording-10-4-table-group-to-nested-table-transformation.mp4" caption="Group to nested tables transformation" >}} + +### Set library panel permissions with RBAC + + + +_Generally available in Grafana Enterprise and Grafana Cloud_ + +We've added the option to manage library panel permissions through role-based access control (RBAC). With this feature, you can choose who can create, edit, and read library panels. RBAC provides a standardized way of granting, changing, and revoking access when it comes to viewing and modifying Grafana resources, such as dashboards, reports, and administrative settings. + +[Documentation](https://grafana.com/docs/grafana//dashboards/build-dashboards/manage-library-panels/) + +### Tooltip improvements + + + +_Available in public preview in all editions of Grafana_ + +We’ve made a number of small improvements to the way tooltips work in Grafana. To try out the new tooltips, enable the `newVizTooltips` [feature toggle](https://grafana.com/docs/grafana//setup-grafana/configure-grafana/feature-toggles/). + +**Copy on click support** + +You can now copy the content from within a tooltip by clicking on the text. + +![Tooltip](/media/docs/grafana/gif-grafana-10-4-tooltip–copy.gif) + +**Scrollable content** + +You can now scroll the content of a tooltip, which allows you to view long lists. This is currently supported in the time series, candlestick, and trend visualizations. We'll add more improvements to the scrolling functionality in a future version. + +![Tooltip](/media/docs/grafana/gif-grafana-10-4-tooltip-content-scroll.gif) + +**Added tooltip options for candlestick visualization** + +The default tooltip options are now also visible in candlestick visualizations. + +**Hover proximity option in time series** + +We've added a tooltip hover proximity limit option (in pixels), which makes it possible to reduce the number of hovered-over data points under the cursor when two datasets are not aligned in time. + +![Time Series hover proximity](/media/docs/grafana/gif-grafana-10-4-hover-proximity.gif) + +## Return to previous + + + +_Available in public preview in all editions of Grafana_ + +When you're browsing Grafana - for example, exploring the dashboard and metrics related to an alert - it's easy to end up far from where you started and hard get back to where you came from. The ‘Return to previous’ button is an easy way to go back to the previous context, like the alert rule that kicked off your exploration. This first release works for Alerts, and we plan to expand to other apps and features in Grafana in future releases to make it easier to navigate around. + +Return to Previous is rolling out across Grafana Cloud now. To try Return to Previous in self-managed Grafana, turn on the `returnToPrevious` [feature toggle](https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/feature-toggles/) in Grafana v10.4 or newer. + + + +{{< admonition type="note" >}} +The term **context** refers to applications in Grafana like Incident and OnCall, as well as core features like Explore and Dashboards. + +To notice a change in your context, look at Grafana's breadcrumbs. If you go from _Home > **Dashboards**_ to _Home > **Explore**_, you've changed context. If you go from _Home > **Dashboards** > Playlist > Edit playlist_ to _Home > **Dashboards** > Reporting > Settings_, you are in the same context. +{{< /admonition >}} + +## Alerting + +### Simplified Alert Notification Routing + + + +_Generally available in all editions of Grafana_ + +This feature simplifies your options for configuring where your notifications are sent when an alert rule fires. Choose an existing contact point directly from within the alert rule creation form without the need to label match notification policies.  You can also set optional muting, grouping, and timing settings directly in the alert rule. + +Simplified routing inherits the alert rule RBAC, increasing control over notification routing while preventing accidental notification policy updates, ensuring critical notifications make it to their intended contact point destination. + +To try out Simplified Alert Notification Routing enable the `alertingSimplifiedRouting` feature toggle. + + + +### Grafana Alerting upgrade with rule preview + + + +_Generally available in all editions of Grafana_ + +Users looking to migrate to the new Grafana Alerting product can do so with confidence with the Grafana Alerting migration preview tool. The migration preview tool allows users to view, edit, and delete migrated rules prior cutting over, with the option to roll back to Legacy Alerting. + +[Documentation](https://grafana.com/docs/grafana//alerting/set-up/migrating-alerts/#upgrade-with-preview-recommended) + +### Rule evaluation spread over the entire evaluation interval + + + +_Generally available in all editions of Grafana_ + +Grafana Alerting previously evaluated rules at the start of the evaluation interval. This created a sudden spike of resource utilization, impacting data sources. Rule evaluation is now spread over the entire interval for smoother performance utilization of data sources. + +### UTF-8 Support for Prometheus and Mimir Alertmanagers + + + +_Generally available in all editions of Grafana_ + +Grafana can now be used to manage both Prometheus and Mimir Alertmanagers with UTF-8 configurations. For more information, please see the +[release notes for Alertmanager 0.27.0](https://github.com/prometheus/alertmanager/releases). + +## Authentication and authorization + +### SSO Settings UI and Terraform resource for configuring OAuth providers + + + +_Available in public preview in all editions of Grafana_ + +Configuring OAuth providers was a bit cumbersome in Grafana: Grafana Cloud users had to reach out to Grafana Support, self-hosted users had to manually edit the configuration file, set up environment variables, and then they had to restart Grafana. On Cloud, the Advanced Auth page is there to configure some of the providers, but configuring Generic OAuth hasn’t been available until now and there was no way to manage the settings through the Grafana UI, nor was there a way to manage the settings through Terraform or the Grafana API. + +Our goal is to make setting up SSO for your Grafana instance simple and fast. + +To get there, we are introducing easier self-serve configuration options for OAuth in Grafana. All of the currently supported OAuth providers are now available for configuration through the Grafana UI, Terraform and via the API. From the UI, you can also now manage all of the settings for the Generic OAuth provider. + +We are working on adding complete support for configuring all other supported OAuth providers as well, such as GitHub, GitLab, Google, Microsoft Azure AD and Okta. You can already manage some of these settings via the new self-serve configuration options, and we’re working on adding more at the moment. + +![Screenshot of the Authentication provider list page](/media/docs/grafana-cloud/screenshot-sso-settings-ui-public-prev-v10.4.png) + + + +[Documentation](https://grafana.com/docs/grafana/next/setup-grafana/configure-security/configure-authentication/) + +## Data sources + +{{< admonition type="note" >}} +The following data sources are released separately from Grafana itself. They are included here for extra visibility. +{{< /admonition >}} + +### PagerDuty enterprise data source for Grafana + + + +_Generally available in Grafana Enterprise and Grafana Cloud_ + +PagerDuty enterprise data source plugin for Grafana allows you to query incidents data or visualize incidents using annotations. + +{{< admonition type="note" >}} +Plugin is currently in a preview phase. +{{< /admonition >}} + +You can find more information and how to configure the plugin in the [documentation](https://grafana.com/docs/plugins/grafana-pagerduty-datasource/latest/). + +Screenshots: + +{{< figure src="/media/docs/plugins/PagerDuty-incidents-annotation.png" caption="PagerDuty data source annotation editor" alt="PagerDuty data source annotation editor" >}} + +{{< figure src="/media/docs/plugins/PagerDuty-incidents-real-life-example.png" caption="Incidents annotations from PagerDuty data source on a dashboard panel" alt="Incidents annotations from PagerDuty data source on a dashboard panel" >}} + + + +### SurrealDB Data Source + + + +_Experimental in all editions of Grafana_ + +A SurrealDB data source has been [added to the Plugin Catalog](https://grafana.com/grafana/plugins/grafana-surrealdb-datasource/), enabling the integration of [SurrealDB](https://surrealdb.com/), a real-time, multi-model database, with Grafana's visualization capabilities. This datasource allows users to directly query and visualize data from SurrealDB within Grafana, using SurrealDB's query language. + +The SurrealDB data source launches with just the basics today. You can write queries in SurrealQL using the built-in query editor, although many Grafana features like macros are not supported for now. + +You can find more information and how to configure the plugin [on Github](https://github.com/grafana/surrealdb-datasource). + +{{< figure src="/media/images/dashboards/surrealdb-dashboard-example.png" >}} + +[Documentation](https://grafana.com/grafana/plugins/grafana-surrealdb-datasource/) From 4d40128896d82bd1774087ef33507b8e9eb86c73 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 6 Mar 2024 07:20:12 +0000 Subject: [PATCH 040/138] [v10.4.x] Docs: fix commented out Slack team names (#83949) Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> fix commented out Slack team names (#83946) --- docs/sources/whatsnew/whats-new-in-v10-4.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/sources/whatsnew/whats-new-in-v10-4.md b/docs/sources/whatsnew/whats-new-in-v10-4.md index f1106a21b642..434ea61f73b6 100644 --- a/docs/sources/whatsnew/whats-new-in-v10-4.md +++ b/docs/sources/whatsnew/whats-new-in-v10-4.md @@ -42,7 +42,7 @@ Use full URLs for links. When linking to versioned docs, replace the version wit ### AngularJS plugin warnings in dashboards - + _Generally available in all editions of Grafana_ @@ -100,7 +100,7 @@ You can now create subtables out of your data using the new **Group to nested ta ### Set library panel permissions with RBAC - + _Generally available in Grafana Enterprise and Grafana Cloud_ @@ -140,7 +140,7 @@ We've added a tooltip hover proximity limit option (in pixels), which makes it p ## Return to previous - + _Available in public preview in all editions of Grafana_ @@ -160,7 +160,7 @@ To notice a change in your context, look at Grafana's breadcrumbs. If you go fro ### Simplified Alert Notification Routing - + _Generally available in all editions of Grafana_ @@ -251,7 +251,7 @@ Screenshots: ### SurrealDB Data Source - + _Experimental in all editions of Grafana_ From 2c3f9581cf1521e3c1b6163f47009635fca9e998 Mon Sep 17 00:00:00 2001 From: Pepe Cano <825430+ppcano@users.noreply.github.com> Date: Wed, 6 Mar 2024 10:43:53 +0100 Subject: [PATCH 041/138] Backport alerting docs changes to v10.4.x (#83898) * Alerting docs: update Alerting Provisioning (#83376) * Minor updates to Provisioning Index page * Add instructions to export other alerting resources * Edit example provisioning a `template` via config file * Add `Resource` column to the `Export API endpoints` table * Sort the `export` endpoint on the table in `Alerting Provisioning HTTP API` * Minor updates for clarity to `Use configuration files to provision` docs * Add `More examples` in Terraform Provisioning docs * File provisioning: rename `Useful Links` section to `More examples` * Minor grammar change * Update docs/sources/alerting/set-up/provision-alerting-resources/_index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/alerting/set-up/provision-alerting-resources/_index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/alerting/set-up/provision-alerting-resources/export-alerting-resources/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/alerting/set-up/provision-alerting-resources/export-alerting-resources/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/alerting/set-up/provision-alerting-resources/export-alerting-resources/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Address requested changes to `Export` docs * export: Minor grammar change * Update docs/sources/alerting/set-up/provision-alerting-resources/export-alerting-resources/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Fix `doc-validator` issue with relative link * Use patch fixed version of doc-validator that better supports docs/reference destinations Signed-off-by: Jack Baldry --------- Signed-off-by: Jack Baldry Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> Co-authored-by: Jack Baldry (cherry picked from commit eb25b669c6a3aca8f5bda80f59762e1b5d6580e5) * Alerting docs: fix incorrect `docs/reference` link (cherry picked from commit c3c6ee4dcaa3ed1770ddf29b417698e19e6c1070) * Alerting docs: document `mute-timings` export endpoints (#83797) (cherry picked from commit 244589d7eac0fa839c74560e9205ccf8da7bcf87) * Alerting docs: improve visibility on the distinct options to edit provisioned resources (#83839) Alerting docs: specify the distinct options to edit provisioned resources (cherry picked from commit 019c9618f051e3819be2a2a5fbfd06a3fa5b3aa6) --- .../provision-alerting-resources/_index.md | 17 ++- .../export-alerting-resources/index.md | 127 +++++++++++++++--- .../file-provisioning/index.md | 99 ++++++++++---- .../terraform-provisioning/index.md | 1 + .../shared/alerts/alerting_provisioning.md | 111 +++++++++++++-- 5 files changed, 289 insertions(+), 66 deletions(-) diff --git a/docs/sources/alerting/set-up/provision-alerting-resources/_index.md b/docs/sources/alerting/set-up/provision-alerting-resources/_index.md index 269d85aea334..7da5fa634c3e 100644 --- a/docs/sources/alerting/set-up/provision-alerting-resources/_index.md +++ b/docs/sources/alerting/set-up/provision-alerting-resources/_index.md @@ -33,8 +33,10 @@ Choose from the options below to import (or provision) your Grafana Alerting res 1. [Use configuration files to provision your alerting resources](/docs/grafana//alerting/set-up/provision-alerting-resources/file-provisioning), such as alert rules and contact points, through files on disk. {{< admonition type="note" >}} - File provisioning is not available in Grafana Cloud instances. - {{< /admonition >}} + + - You cannot edit provisioned resources from files in the Grafana UI. + - Provisioning with configuration files is not available in Grafana Cloud. + {{< /admonition >}} 1. Use [Terraform to provision alerting resources][alerting_tf_provisioning]. @@ -42,14 +44,15 @@ Choose from the options below to import (or provision) your Grafana Alerting res {{< admonition type="note" >}} The JSON output from the majority of Alerting HTTP endpoints isn't compatible for provisioning via configuration files. - Instead, use the [Export Alerting endpoints](/docs/grafana//alerting/set-up/provision-alerting-resources/export-alerting-resources#export-api-endpoints) to return or download the alerting resources in provisioning format. + + If you need the alerting resources for file provisioning, use [Export Alerting endpoints](/docs/grafana//alerting/set-up/provision-alerting-resources/export-alerting-resources#export-api-endpoints) to return or download them in provisioning format. {{< /admonition >}} ## Export alerting resources -You can export both manually created and provisioned alerting resources. For more information, refer to [Export alerting resources][alerting_export]. +You can export both manually created and provisioned alerting resources. You can also edit and export an alert rule without applying the changes. -To modify imported alert rules, you can use the **Modify export** feature to edit and then export. +For detailed instructions on the various export options, refer to [Export alerting resources][alerting_export]. ## View provisioned alerting resources @@ -61,10 +64,6 @@ To view your provisioned resources in Grafana, complete the following steps. Provisioned resources are labeled **Provisioned**, so that it is clear that they were not created manually. -**Useful Links:** - -[Grafana provisioning][provisioning] - {{% docs/reference %}} [alerting_tf_provisioning]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/terraform-provisioning" [alerting_tf_provisioning]: "/docs/grafana-cloud/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/terraform-provisioning" diff --git a/docs/sources/alerting/set-up/provision-alerting-resources/export-alerting-resources/index.md b/docs/sources/alerting/set-up/provision-alerting-resources/export-alerting-resources/index.md index 82c82706ad7d..12b06c734bd8 100644 --- a/docs/sources/alerting/set-up/provision-alerting-resources/export-alerting-resources/index.md +++ b/docs/sources/alerting/set-up/provision-alerting-resources/export-alerting-resources/index.md @@ -22,9 +22,23 @@ weight: 300 Export your alerting resources, such as alert rules, contact points, and notification policies for provisioning, automatically importing single folders and single groups. +There are distinct methods to export your alerting resources: + +- [Grafana UI](#export-from-the-grafana-ui) exports in Terraform format and YAML or JSON formats for file provisioning. +- [HTTP Alerting API](#http-alerting-api) exports in JSON API format used by the HTTP Alerting API. +- [HTTP Alerting API - Export endpoints](#export-api-endpoints) exports in YAML or JSON formats for file provisioning. + +{{< admonition type="note" >}} +Alerting resources imported through [file provisioning](/docs/grafana//alerting/set-up/provision-alerting-resources/file-provisioning) cannot be edited in the Grafana UI. This prevents changes made in the UI from being overridden by file provisioning during Grafana restarts. + +If you need to modify provisioned alerting resources in Grafana, refer to [edit HTTP API alerting resources in the Grafana UI](/docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning#edit-resources-in-the-grafana-ui) or to [edit Terraform alerting resources in the Grafana UI](/docs/grafana//alerting/set-up/provision-alerting-resources/terraform-provisioning#enable-editing-resources-in-the-grafana-ui). +{{< /admonition >}} + +## Export from the Grafana UI + The export options listed below enable you to download resources in YAML, JSON, or Terraform format, facilitating their provisioning through [configuration files](/docs/grafana//alerting/set-up/provision-alerting-resources/file-provisioning) or [Terraform][alerting_tf_provisioning]. -## Export alert rules +### Export alert rules To export alert rules from the Grafana UI, complete the following steps. @@ -36,20 +50,16 @@ To export alert rules from the Grafana UI, complete the following steps. 1. Find the group you want to export and click the **Export rule group** icon. 1. Choose the format to export in. - The exported rule data appears in different formats - YAML, JSON, Terraform. + The exported alert rule data appears in different formats - YAML, JSON, Terraform. 1. Click **Copy Code** or **Download**. - a. Choose **Copy Code** to go to an existing file and paste in the code. - - b. Choose **Download** to download a file with the exported data. - -## Modify and export alert rules without saving changes - -Use the **Modify export** mode to edit and export an alert rule without updating it. +### Modify alert rule and export rule group without saving changes {{% admonition type="note" %}} This feature is for Grafana-managed alert rules only. It is available to Admin, Viewer, and Editor roles. {{% /admonition %}} +Use the **Modify export** mode to edit and export an alert rule without updating it. The exported data includes all alert rules within the same alert group. + To export a modified alert rule without saving the modifications, complete the following steps from the Grafana UI. 1. Click **Alerts & IRM** -> **Alert rules**. @@ -58,27 +68,89 @@ To export a modified alert rule without saving the modifications, complete the f 1. Click **Export**. 1. Choose the format to export in. - The exported rule data appears in different formats - YAML, JSON, Terraform. + The exported alert rule group appears in different formats - YAML, JSON, Terraform. + +1. Click **Copy Code** or **Download**. + +### Export contact points + +To export contact points from the Grafana UI, complete the following steps. + +1. Click **Alerts & IRM** -> **Contact points**. +1. Find the contact point you want to export and click **More** -> **Export**. +1. Choose the format to export in. + + The exported contact point appears in different formats - YAML, JSON, Terraform. 1. Click **Copy Code** or **Download**. - a. Choose **Copy Code** to go to an existing file and paste in the code. +### Export templates + +Grafana currently doesn't offer an Export UI for notification templates, unlike other Alerting resources presented in this documentation. - b. Choose **Download** to download a file with the exported data. +However, you can export it by manually copying the content template and title directly from the Grafana UI. -## Export API endpoints +1. Click **Alerts & IRM** -> **Contact points** -> **Notification templates** tab. +1. Find the template you want to export. +1. Copy the content and title. +1. Adjust it for the [file provisioning format][alerting_file_provisioning_template] or [Terraform resource][alerting_tf_provisioning_template]. -You can also use the **Alerting provisioning HTTP API** to export alerting resources in YAML or JSON formats for provisioning. +### Export the notification policy tree -Note that most Alerting endpoints return a JSON format that is not compatible for provisioning via configuration files, except the ones listed below. +All notification policies are provisioned through a single resource: the root of the notification policy tree. -| Method | URI | Summary | -| ------ | ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | -| GET | /api/v1/provisioning/alert-rules/:uid/export | [Export an alert rule in provisioning file format.][export_rule] | -| GET | /api/v1/provisioning/folder/:folderUid/rule-groups/:group/export | [Export an alert rule group in provisioning file format.][export_rule_group] | -| GET | /api/v1/provisioning/alert-rules/export | [Export all alert rules in provisioning file format.][export_rules] | -| GET | /api/v1/provisioning/contact-points/export | [Export all contact points in provisioning file format.][export_contacts] | -| GET | /api/v1/provisioning/policies/export | [Export the notification policy tree in provisioning file format.][export_notifications] | +{{% admonition type="warning" %}} + +Since the policy tree is a single resource, provisioning it will overwrite a policy tree created through any other means. + +{{< /admonition >}} + +To export the notification policy tree from the Grafana UI, complete the following steps. + +1. Click **Alerts & IRM** -> **Notification policies**. +1. In the **Default notification policy** section, click **...** -> **Export**. +1. Choose the format to export in. + + The exported contact point appears in different formats - YAML, JSON, Terraform. + +1. Click **Copy Code** or **Download**. + +### Export mute timings + +To export mute timings from the Grafana UI, complete the following steps. + +1. Click **Alerts & IRM** -> **Notification policies**, and then the **Mute timings** tab. +1. Find the mute timing you want to export and click **Export**. +1. Choose the format to export in. + + The exported contact point appears in different formats - YAML, JSON, Terraform. + +1. Click **Copy Code** or **Download**. + +## HTTP Alerting API + +You can use the [Alerting HTTP API][alerting_http_provisioning] to return existing alerting resources in JSON and import them to another Grafana instance using the same endpoint. For instance: + +| Resource | Method / URI | Summary | +| ----------- | ------------------------------------- | ------------------------ | +| Alert rules | GET /api/v1/provisioning/alert-rules | Get all alert rules. | +| Alert rules | POST /api/v1/provisioning/alert-rules | Create a new alert rule. | + +However, note these Alerting endpoints return a JSON format that is not compatible for provisioning through configuration files or Terraform, except the endpoints listed below. + +### Export API endpoints + +The **Alerting HTTP API** provides specific endpoints for exporting alerting resources in YAML or JSON formats, facilitating [provisioning via configuration files][alerting_file_provisioning]. Currently, Terraform format is not supported. + +| Resource | Method / URI | Summary | +| ------------------------ | -------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | +| Alert rules | GET /api/v1/provisioning/alert-rules/export | [Export all alert rules in provisioning file format.][export_rules] | +| Alert rules | GET /api/v1/provisioning/folder/:folderUid/rule-groups/:group/export | [Export an alert rule group in provisioning file format.][export_rule_group] | +| Alert rules | GET /api/v1/provisioning/alert-rules/:uid/export | [Export an alert rule in provisioning file format.][export_rule] | +| Contact points | GET /api/v1/provisioning/contact-points/export | [Export all contact points in provisioning file format.][export_contacts] | +| Notification policy tree | GET /api/v1/provisioning/policies/export | [Export the notification policy tree in provisioning file format.][export_notifications] | +| Mute timings | GET /api/v1/provisioning/mute-timings/export | [Export all mute timings in provisioning file format.][export_mute_timings] | +| Mute timings | GET /api/v1/provisioning/mute-timings/:name/export | [Export a mute timing in provisioning file format.][export_mute_timing] | These endpoints accept a `download` parameter to download a file containing the exported resources. @@ -88,9 +160,14 @@ These endpoints accept a `download` parameter to download a file containing the [alerting_tf_provisioning]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/terraform-provisioning" [alerting_tf_provisioning]: "/docs/grafana-cloud/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/terraform-provisioning" +[alerting_tf_provisioning_template]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/terraform-provisioning#import-contact-points-and-templates" +[alerting_tf_provisioning_template]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/set-up/provision-alerting-resources/terraform-provisioning#import-contact-points-and-templates" + [alerting_http_provisioning]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning" [alerting_http_provisioning]: "/docs/grafana-cloud/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning" +[alerting_file_provisioning_template]: "/docs/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/file-provisioning#import-templates" + [export_rule]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-alert-rule-exportspan-export-an-alert-rule-in-provisioning-file-format-_routegetalertruleexport_" [export_rule]: "/docs/grafana-cloud/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-alert-rule-exportspan-export-an-alert-rule-in-provisioning-file-format-_routegetalertruleexport_" @@ -103,6 +180,12 @@ These endpoints accept a `download` parameter to download a file containing the [export_contacts]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-contactpoints-exportspan-export-all-contact-points-in-provisioning-file-format-_routegetcontactpointsexport_" [export_contacts]: "/docs/grafana-cloud/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-contactpoints-exportspan-export-all-contact-points-in-provisioning-file-format-_routegetcontactpointsexport_" +[export_mute_timing]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-mute-timing-exportspan-export-a-mute-timing-in-provisioning-file-format-_routegetmutetimingexport_" +[export_mute_timing]: "/docs/grafana-cloud/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-mute-timing-exportspan-export-a-mute-timing-in-provisioning-file-format-_routegetmutetimingexport_" + +[export_mute_timings]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-mute-timings-exportspan-export-all-mute-timings-in-provisioning-file-format-_routegetmutetimingsexport_" +[export_mute_timings]: "/docs/grafana-cloud/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-mute-timings-exportspan-export-all-mute-timings-in-provisioning-file-format-_routegetmutetimingsexport_" + [export_notifications]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-policy-tree-exportspan-export-the-notification-policy-tree-in-provisioning-file-format-_routegetpolicytreeexport_" [export_notifications]: "/docs/grafana-cloud/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning/#span-idroute-get-policy-tree-exportspan-export-the-notification-policy-tree-in-provisioning-file-format-_routegetpolicytreeexport_" {{% /docs/reference %}} diff --git a/docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md b/docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md index 22066714f5fd..7d810107226a 100644 --- a/docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md +++ b/docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md @@ -30,24 +30,26 @@ For a complete guide about how Grafana provisions resources, refer to the [Provi {{< admonition type="note" >}} +- Provisioning with configuration files is not available in Grafana Cloud. + - You cannot edit provisioned resources from files in Grafana. You can only change the resource properties by changing the provisioning file and restarting Grafana or carrying out a hot reload. This prevents changes being made to the resource that would be overwritten if a file is provisioned again or a hot reload is carried out. -- Importing takes place during the initial set up of your Grafana system, but you can re-run it at any time using the [Grafana Admin API](/docs/grafana//developers/http_api/admin#reload-provisioning-configurations). +- Provisioning using configuration files takes place during the initial set up of your Grafana system, but you can re-run it at any time using the [Grafana Admin API](/docs/grafana//developers/http_api/admin#reload-provisioning-configurations). - Importing an existing alerting resource results in a conflict. First, when present, remove the resources you plan to import. {{< /admonition >}} ## Import alert rules -Create or delete alert rules in your Grafana instance(s). +Create or delete alert rules using provisioning files in your Grafana instance(s). -1. Create alert rules in Grafana. +1. Find the alert rule group in Grafana. 1. [Export][alerting_export] and download a provisioning file for your alert rules. -1. Copy the contents into a YAML or JSON configuration file in the `provisioning/alerting` directory. +1. Copy the contents into a YAML or JSON configuration file and add it to the `provisioning/alerting` directory of the Grafana instance you want to import the alerting resources to. Example configuration files can be found below. -1. Add the file(s) to your GitOps workflow, so that they deploy alongside your Grafana instance(s). +1. Restart your Grafana instance (or reload the provisioned files using the Admin API). Here is an example of a configuration file for creating alert rules. @@ -138,15 +140,15 @@ deleteRules: ## Import contact points -Create or delete contact points in your Grafana instance(s). +Create or delete contact points using provisioning files in your Grafana instance(s). -1. Create a contact point in Grafana. +1. Find the contact point in Grafana. 1. [Export][alerting_export] and download a provisioning file for your contact point. -1. Copy the contents into a YAML or JSON configuration file in the `provisioning/alerting` directory. +1. Copy the contents into a YAML or JSON configuration file and add it to the `provisioning/alerting` directory of the Grafana instance you want to import the alerting resources to. Example configuration files can be found below. -1. Add the file(s) to your GitOps workflow, so that they deploy alongside your Grafana instance(s). +1. Restart your Grafana instance (or reload the provisioned files using the Admin API). Here is an example of a configuration file for creating contact points. @@ -569,9 +571,54 @@ settings: {{< /collapse >}} +## Import templates + +Create or delete templates using provisioning files in your Grafana instance(s). + +1. Find the notification template in Grafana. +1. [Export][alerting_export] a template by copying the template content and title. +1. Copy the contents into a YAML or JSON configuration file and add it to the `provisioning/alerting` directory of the Grafana instance you want to import the alerting resources to. + + Example configuration files can be found below. + +1. Restart your Grafana instance (or reload the provisioned files using the Admin API). + +Here is an example of a configuration file for creating templates. + +```yaml +# config file version +apiVersion: 1 + +# List of templates to import or update +templates: + # organization ID, default = 1 + - orgId: 1 + # name of the template, must be unique + name: my_first_template + # content of the the template + template: | + {{ define "my_first_template" }} + Custom notification message + {{ end }} +``` + +Here is an example of a configuration file for deleting templates. + +```yaml +# config file version +apiVersion: 1 + +# List of alert rule UIDs that should be deleted +deleteTemplates: + # organization ID, default = 1 + - orgId: 1 + # name of the template, must be unique + name: my_first_template +``` + ## Import notification policies -Create or reset the notification policy tree in your Grafana instance(s). +Create or reset the notification policy tree using provisioning files in your Grafana instance(s). In Grafana, the entire notification policy tree is considered a single, large resource. Add new specific policies as sub-policies under the root policy. Since specific policies may depend on each other, you cannot provision subsets of the policy tree; the entire tree must be defined in a single place. @@ -581,13 +628,13 @@ Since the policy tree is a single resource, provisioning it will overwrite a pol {{< /admonition >}} -1. Create a notification policy in Grafana. -1. [Export][alerting_export] and download a provisioning file for your notification policy. -1. Copy the contents into a YAML or JSON configuration file in the `provisioning/alerting` directory. +1. Find the notification policy tree in Grafana. +1. [Export][alerting_export] and download a provisioning file for your notification policy tree. +1. Copy the contents into a YAML or JSON configuration file and add it to the `provisioning/alerting` directory of the Grafana instance you want to import the alerting resources to. Example configuration files can be found below. -1. Add the file(s) to your GitOps workflow, so that they deploy alongside your Grafana instance(s). +1. Restart your Grafana instance (or reload the provisioned files using the Admin API). Here is an example of a configuration file for creating notification policies. @@ -705,13 +752,15 @@ deleteTemplates: ## Import mute timings -Create or delete mute timings in your Grafana instance(s). +Create or delete mute timings via provisioning files using provisioning files in your Grafana instance(s). -1. Create a YAML or JSON configuration file. +1. Find the mute timing in Grafana. +1. [Export][alerting_export] and download a provisioning file for your mute timing. +1. Copy the contents into a YAML or JSON configuration file and add it to the `provisioning/alerting` directory of the Grafana instance you want to import the alerting resources to. Example configuration files can be found below. -1. Add the file(s) to your GitOps workflow, so that they deploy alongside your Grafana instance(s). +1. Restart your Grafana instance (or reload the provisioned files using the Admin API). Here is an example of a configuration file for creating mute timings. @@ -770,7 +819,7 @@ If you are a Kubernetes user, you can leverage file provisioning using Kubernete template: the content for my template ``` -1. Add the file(s) to your GitOps workflow, so that they deploy alongside your Grafana instance(s). +1. Restart your Grafana instance (or reload the provisioned files using the Admin API). ```yaml apiVersion: apps/v1 @@ -807,13 +856,17 @@ If you are a Kubernetes user, you can leverage file provisioning using Kubernete This eliminates the need for a persistent database to use Grafana Alerting in Kubernetes; all your provisioned resources appear after each restart or re-deployment. Grafana still requires a database for normal operation, you do not need to persist the contents of the database between restarts if all objects are provisioned using files. -**Useful Links:** +## More examples -[Grafana provisioning][provisioning] +- [Provision Grafana][provisioning] {{% docs/reference %}} + [alerting_export]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/export-alerting-resources" -[alerting_export]: "/docs/grafana-cloud/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/export-alerting-resources" -[provisioning]: "/docs/grafana/ -> /docs/grafana//administration/provisioning" -[provisioning]: "/docs/grafana-cloud/ -> /docs/grafana//administration/provisioning" +[alerting_export]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/set-up/provision-alerting-resources/export-alerting-resources" + +[provisioning]: "/docs/ -> /docs/grafana//administration/provisioning" + +[reload-provisioning-configurations]: "/docs/ -> /docs/grafana//developers/http_api/admin#reload-provisioning-configurations" + {{% /docs/reference %}} diff --git a/docs/sources/alerting/set-up/provision-alerting-resources/terraform-provisioning/index.md b/docs/sources/alerting/set-up/provision-alerting-resources/terraform-provisioning/index.md index 488ca0864d35..c215c625ace6 100644 --- a/docs/sources/alerting/set-up/provision-alerting-resources/terraform-provisioning/index.md +++ b/docs/sources/alerting/set-up/provision-alerting-resources/terraform-provisioning/index.md @@ -389,6 +389,7 @@ For more examples on the concept of this guide: - Review the [tutorial to manage a Grafana Cloud stack using Terraform][provision-cloud-with-terraform]. {{% docs/reference %}} + [alerting-rules]: "/docs/grafana/ -> /docs/grafana//alerting/alerting-rules" [alerting-rules]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/alerting-rules" diff --git a/docs/sources/shared/alerts/alerting_provisioning.md b/docs/sources/shared/alerts/alerting_provisioning.md index 7be0b2d010ce..eb7df8a9cac1 100644 --- a/docs/sources/shared/alerts/alerting_provisioning.md +++ b/docs/sources/shared/alerts/alerting_provisioning.md @@ -36,14 +36,14 @@ For managing resources related to [data source-managed alerts]({{< relref "/docs | ------ | ---------------------------------------------------------------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------- | | DELETE | /api/v1/provisioning/alert-rules/:uid | [route delete alert rule](#route-delete-alert-rule) | Delete a specific alert rule by UID. | | GET | /api/v1/provisioning/alert-rules/:uid | [route get alert rule](#route-get-alert-rule) | Get a specific alert rule by UID. | +| POST | /api/v1/provisioning/alert-rules | [route post alert rule](#route-post-alert-rule) | Create a new alert rule. | +| PUT | /api/v1/provisioning/alert-rules/:uid | [route put alert rule](#route-put-alert-rule) | Update an existing alert rule. | | GET | /api/v1/provisioning/alert-rules/:uid/export | [route get alert rule export](#route-get-alert-rule-export) | Export an alert rule in provisioning file format. | | GET | /api/v1/provisioning/folder/:folderUid/rule-groups/:group | [route get alert rule group](#route-get-alert-rule-group) | Get a rule group. | +| PUT | /api/v1/provisioning/folder/:folderUid/rule-groups/:group | [route put alert rule group](#route-put-alert-rule-group) | Update the interval of a rule group or modify the rules of the group. | | GET | /api/v1/provisioning/folder/:folderUid/rule-groups/:group/export | [route get alert rule group export](#route-get-alert-rule-group-export) | Export an alert rule group in provisioning file format. | | GET | /api/v1/provisioning/alert-rules | [route get alert rules](#route-get-alert-rules) | Get all the alert rules. | | GET | /api/v1/provisioning/alert-rules/export | [route get alert rules export](#route-get-alert-rules-export) | Export all alert rules in provisioning file format. | -| POST | /api/v1/provisioning/alert-rules | [route post alert rule](#route-post-alert-rule) | Create a new alert rule. | -| PUT | /api/v1/provisioning/alert-rules/:uid | [route put alert rule](#route-put-alert-rule) | Update an existing alert rule. | -| PUT | /api/v1/provisioning/folder/:folderUid/rule-groups/:group | [route put alert rule group](#route-put-alert-rule-group) | Update the interval of a rule group or modify the rules of the group. | #### Example alert rules template @@ -130,9 +130,9 @@ For managing resources related to [data source-managed alerts]({{< relref "/docs | ------ | ------------------------------------------ | ----------------------------------------------------------------- | ------------------------------------------------------ | | DELETE | /api/v1/provisioning/contact-points/:uid | [route delete contactpoints](#route-delete-contactpoints) | Delete a contact point. | | GET | /api/v1/provisioning/contact-points | [route get contactpoints](#route-get-contactpoints) | Get all the contact points. | -| GET | /api/v1/provisioning/contact-points/export | [route get contactpoints export](#route-get-contactpoints-export) | Export all contact points in provisioning file format. | | POST | /api/v1/provisioning/contact-points | [route post contactpoints](#route-post-contactpoints) | Create a contact point. | | PUT | /api/v1/provisioning/contact-points/:uid | [route put contactpoint](#route-put-contactpoint) | Update an existing contact point. | +| GET | /api/v1/provisioning/contact-points/export | [route get contactpoints export](#route-get-contactpoints-export) | Export all contact points in provisioning file format. | ### Notification policies @@ -140,18 +140,20 @@ For managing resources related to [data source-managed alerts]({{< relref "/docs | ------ | ------------------------------------ | ------------------------------------------------------------- | ---------------------------------------------------------------- | | DELETE | /api/v1/provisioning/policies | [route reset policy tree](#route-reset-policy-tree) | Clears the notification policy tree. | | GET | /api/v1/provisioning/policies | [route get policy tree](#route-get-policy-tree) | Get the notification policy tree. | -| GET | /api/v1/provisioning/policies/export | [route get policy tree export](#route-get-policy-tree-export) | Export the notification policy tree in provisioning file format. | | PUT | /api/v1/provisioning/policies | [route put policy tree](#route-put-policy-tree) | Sets the notification policy tree. | +| GET | /api/v1/provisioning/policies/export | [route get policy tree export](#route-get-policy-tree-export) | Export the notification policy tree in provisioning file format. | ### Mute timings -| Method | URI | Name | Summary | -| ------ | --------------------------------------- | ----------------------------------------------------- | -------------------------------- | -| DELETE | /api/v1/provisioning/mute-timings/:name | [route delete mute timing](#route-delete-mute-timing) | Delete a mute timing. | -| GET | /api/v1/provisioning/mute-timings/:name | [route get mute timing](#route-get-mute-timing) | Get a mute timing. | -| GET | /api/v1/provisioning/mute-timings | [route get mute timings](#route-get-mute-timings) | Get all the mute timings. | -| POST | /api/v1/provisioning/mute-timings | [route post mute timing](#route-post-mute-timing) | Create a new mute timing. | -| PUT | /api/v1/provisioning/mute-timings/:name | [route put mute timing](#route-put-mute-timing) | Replace an existing mute timing. | +| Method | URI | Name | Summary | +| ------ | ---------------------------------------------- | --------------------------------------------------------------- | ---------------------------------------------------- | +| DELETE | /api/v1/provisioning/mute-timings/:name | [route delete mute timing](#route-delete-mute-timing) | Delete a mute timing. | +| GET | /api/v1/provisioning/mute-timings/:name | [route get mute timing](#route-get-mute-timing) | Get a mute timing. | +| GET | /api/v1/provisioning/mute-timings | [route get mute timings](#route-get-mute-timings) | Get all the mute timings. | +| POST | /api/v1/provisioning/mute-timings | [route post mute timing](#route-post-mute-timing) | Create a new mute timing. | +| PUT | /api/v1/provisioning/mute-timings/:name | [route put mute timing](#route-put-mute-timing) | Replace an existing mute timing. | +| GET | /api/v1/provisioning/mute-timings/export | [route get mute timings export](#route-get-mute-timings-export) | Export all mute timings in provisioning file format. | +| GET | /api/v1/provisioning/mute-timings/:name/export | [route get mute timing export](#route-get-mute-timing-export) | Export a mute timing in provisioning file format. | ### Templates @@ -631,6 +633,83 @@ Status: OK [MuteTimings](#mute-timings) +### Export all mute timings in provisioning file format. (_RouteGetMuteTimingsExport_) + +``` +GET /api/v1/provisioning/mute-timings/export +``` + +#### Parameters + +| Name | Source | Type | Go type | Separator | Required | Default | Description | +| -------- | ------- | ------- | -------- | --------- | :------: | -------- | --------------------------------------------------------------------------------------------------------------------------------- | +| download | `query` | boolean | `bool` | | | | Whether to initiate a download of the file or not. | +| format | `query` | string | `string` | | | `"yaml"` | Format of the downloaded file, either yaml or json. Accept header can also be used, but the query parameter will take precedence. | + +#### All responses + +| Code | Status | Description | Has headers | Schema | +| ----------------------------------------- | --------- | ----------------- | :---------: | --------------------------------------------------- | +| [200](#route-get-mute-timings-export-200) | OK | MuteTimingsExport | | [schema](#route-get-mute-timings-export-200-schema) | +| [403](#route-get-mute-timings-export-403) | Forbidden | PermissionDenied | | [schema](#route-get-mute-timings-export-403-schema) | + +#### Responses + +##### 200 - MuteTimingsExport + +Status: OK + +###### Schema + +[AlertingFileExport](#alerting-file-export) + +##### 403 - PermissionDenied + +Status: Forbidden + +###### Schema + +[PermissionDenied](#permission-denied) + +### Export a mute timing in provisioning file format. (_RouteGetMuteTimingExport_) + +``` +GET /api/v1/provisioning/mute-timings/:name/export +``` + +#### Parameters + +| Name | Source | Type | Go type | Separator | Required | Default | Description | +| -------- | ------- | ------- | -------- | --------- | :------: | -------- | --------------------------------------------------------------------------------------------------------------------------------- | +| name | `path` | string | `string` | | ✓ | | Mute timing name. | +| download | `query` | boolean | `bool` | | | | Whether to initiate a download of the file or not. | +| format | `query` | string | `string` | | | `"yaml"` | Format of the downloaded file, either yaml or json. Accept header can also be used, but the query parameter will take precedence. | + +#### All responses + +| Code | Status | Description | Has headers | Schema | +| ---------------------------------------- | --------- | ---------------- | :---------: | --------------------------------------------------- | +| [200](#route-get-mute-timing-export-200) | OK | MuteTimingExport | | [schema](#route-get-mute-timings-export-200-schema) | +| [403](#route-get-mute-timing-export-403) | Forbidden | PermissionDenied | | [schema](#route-get-mute-timings-export-403-schema) | + +#### Responses + +##### 200 - MuteTimingExport + +Status: OK + +###### Schema + +[AlertingFileExport](#alerting-file-export) + +##### 403 - PermissionDenied + +Status: Forbidden + +###### Schema + +[PermissionDenied](#permission-denied) + ### Get the notification policy tree. (_RouteGetPolicyTree_) ``` @@ -1393,6 +1472,14 @@ Status: Accepted {{% /responsive-table %}} +### MuteTimingExport + +**Properties** + +### MuteTimingsExport + +**Properties** + ### MuteTimings [][MuteTimeInterval](#mute-time-interval) From 90b9cefd4bc94efa0f1d5ad9014bca2e566dd789 Mon Sep 17 00:00:00 2001 From: Pepe Cano <825430+ppcano@users.noreply.github.com> Date: Wed, 6 Mar 2024 12:00:56 +0100 Subject: [PATCH 042/138] [v10.4.x] Alerting docs: update file provisioning guide (#83957) Alerting docs: update file provisioning guide (#83924) (cherry picked from commit 2653bd8fabb4b7147f1e90b1f10acca5b8dfe279) --- .../file-provisioning/index.md | 93 ++++++------------- 1 file changed, 26 insertions(+), 67 deletions(-) diff --git a/docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md b/docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md index 7d810107226a..e5f2c33bb7c8 100644 --- a/docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md +++ b/docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md @@ -20,17 +20,13 @@ weight: 100 # Use configuration files to provision alerting resources -Manage your alerting resources using files from disk. When you start Grafana, the data from these files is created in your Grafana system. Grafana adds any new resources you created, updates any that you changed, and deletes old ones. +Manage your alerting resources using configuration files that can be version controlled. When Grafana starts, it provisions the resources defined in your configuration files. [Provisioning][provisioning] can create, update, or delete existing resources in your Grafana instance. -Arrange your files in a directory in a way that best suits your use case. For example, you can choose a team-based layout where every team has its own file, you can have one big file for all your teams; or you can have one file per resource type. - -Details on how to set up the files and which fields are required for each object are listed below depending on which resource you are provisioning. - -For a complete guide about how Grafana provisions resources, refer to the [Provision Grafana][provisioning] documentation. +This guide outlines the steps and references to provision alerting resources using YAML files. For a practical demo, you can clone and try [this example using Grafana OSS and Docker Compose](https://github.com/grafana/provisioning-alerting-examples/tree/main/config-files). {{< admonition type="note" >}} -- Provisioning with configuration files is not available in Grafana Cloud. +- [Provisioning Grafana](/docs/grafana//administration/provisioning) with configuration files is not available in Grafana Cloud. - You cannot edit provisioned resources from files in Grafana. You can only change the resource properties by changing the provisioning file and restarting Grafana or carrying out a hot reload. This prevents changes being made to the resource that would be overwritten if a file is provisioned again or a hot reload is carried out. @@ -39,12 +35,14 @@ For a complete guide about how Grafana provisions resources, refer to the [Provi - Importing an existing alerting resource results in a conflict. First, when present, remove the resources you plan to import. {{< /admonition >}} +Details on how to set up the files and which fields are required for each object are listed below depending on which resource you are provisioning. + ## Import alert rules Create or delete alert rules using provisioning files in your Grafana instance(s). 1. Find the alert rule group in Grafana. -1. [Export][alerting_export] and download a provisioning file for your alert rules. +1. [Export][export_alert_rules] and download a provisioning file for your alert rules. 1. Copy the contents into a YAML or JSON configuration file and add it to the `provisioning/alerting` directory of the Grafana instance you want to import the alerting resources to. Example configuration files can be found below. @@ -143,7 +141,7 @@ deleteRules: Create or delete contact points using provisioning files in your Grafana instance(s). 1. Find the contact point in Grafana. -1. [Export][alerting_export] and download a provisioning file for your contact point. +1. [Export][export_contact_points] and download a provisioning file for your contact point. 1. Copy the contents into a YAML or JSON configuration file and add it to the `provisioning/alerting` directory of the Grafana instance you want to import the alerting resources to. Example configuration files can be found below. @@ -576,7 +574,7 @@ settings: Create or delete templates using provisioning files in your Grafana instance(s). 1. Find the notification template in Grafana. -1. [Export][alerting_export] a template by copying the template content and title. +1. [Export][export_templates] a template by copying the template content and title. 1. Copy the contents into a YAML or JSON configuration file and add it to the `provisioning/alerting` directory of the Grafana instance you want to import the alerting resources to. Example configuration files can be found below. @@ -629,7 +627,7 @@ Since the policy tree is a single resource, provisioning it will overwrite a pol {{< /admonition >}} 1. Find the notification policy tree in Grafana. -1. [Export][alerting_export] and download a provisioning file for your notification policy tree. +1. [Export][export_policies] and download a provisioning file for your notification policy tree. 1. Copy the contents into a YAML or JSON configuration file and add it to the `provisioning/alerting` directory of the Grafana instance you want to import the alerting resources to. Example configuration files can be found below. @@ -755,7 +753,7 @@ deleteTemplates: Create or delete mute timings via provisioning files using provisioning files in your Grafana instance(s). 1. Find the mute timing in Grafana. -1. [Export][alerting_export] and download a provisioning file for your mute timing. +1. [Export][export_mute_timings] and download a provisioning file for your mute timing. 1. Copy the contents into a YAML or JSON configuration file and add it to the `provisioning/alerting` directory of the Grafana instance you want to import the alerting resources to. Example configuration files can be found below. @@ -801,69 +799,30 @@ deleteMuteTimes: name: mti_1 ``` -## File provisioning using Kubernetes - -If you are a Kubernetes user, you can leverage file provisioning using Kubernetes configuration maps. +## More examples -1. Create one or more configuration maps as follows. +For more examples on the concept of this guide: - ```yaml - apiVersion: v1 - kind: ConfigMap - metadata: - name: grafana-alerting - data: - provisioning.yaml: | - templates: - - name: my_first_template - template: the content for my template - ``` +- Try provisioning alerting resources in Grafana OSS with YAML files through a demo project using [Docker Compose](https://github.com/grafana/provisioning-alerting-examples/tree/main/config-files) or [Kubernetes deployments](https://github.com/grafana/provisioning-alerting-examples/tree/main/kubernetes). +- Review the distinct options about how Grafana provisions resources in the [Provision Grafana documentation][provisioning]. +- For Helm support, review the examples provisioning alerting resources in the [Grafana Helm Chart documentation](https://github.com/grafana/helm-charts/blob/main/charts/grafana/README.md). -1. Restart your Grafana instance (or reload the provisioned files using the Admin API). +{{% docs/reference %}} - ```yaml - apiVersion: apps/v1 - kind: Deployment - metadata: - name: grafana - spec: - replicas: 1 - selector: - matchLabels: - app: grafana - template: - metadata: - name: grafana - labels: - app: grafana - spec: - containers: - - name: grafana - image: grafana/grafana:latest - ports: - - name: grafana - containerPort: 3000 - volumeMounts: - - mountPath: /etc/grafana/provisioning/alerting - name: grafana-alerting - readOnly: false - volumes: - - name: grafana-alerting - configMap: - defaultMode: 420 - name: grafana-alerting - ``` - -This eliminates the need for a persistent database to use Grafana Alerting in Kubernetes; all your provisioned resources appear after each restart or re-deployment. Grafana still requires a database for normal operation, you do not need to persist the contents of the database between restarts if all objects are provisioned using files. +[export_alert_rules]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/export-alerting-resources#export-alert-rules" +[export_alert_rules]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/set-up/provision-alerting-resources/export-alerting-resources#export-alert-rules" -## More examples +[export_contact_points]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/export-alerting-resources#export-contact-points" +[export_contact_points]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/set-up/provision-alerting-resources/export-alerting-resources#export-contact-points" -- [Provision Grafana][provisioning] +[export_templates]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/export-alerting-resources#export-templates" +[export_templates]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/set-up/provision-alerting-resources/export-alerting-resources#export-templates" -{{% docs/reference %}} +[export_policies]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/export-alerting-resources#export-the-notification-policy-tree" +[export_policies]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/set-up/provision-alerting-resources/export-alerting-resources#export-the-notification-policy-tree" -[alerting_export]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/export-alerting-resources" -[alerting_export]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/set-up/provision-alerting-resources/export-alerting-resources" +[export_mute_timings]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/export-alerting-resources#export-mute-timings" +[export_mute_timings]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/set-up/provision-alerting-resources/export-alerting-resources#export-mute-timings" [provisioning]: "/docs/ -> /docs/grafana//administration/provisioning" From f5271952d07899fe9570c790b48f76943f1349b0 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 6 Mar 2024 13:31:25 +0100 Subject: [PATCH 043/138] [v10.4.x] Serviceaccounts: Add ability to add samename SA for different orgs (#83953) Serviceaccounts: Add ability to add samename SA for different orgs (#83893) * add ability to add samename SA for different orgs * Update pkg/services/user/userimpl/user.go * fix tests * refactor name * removed tests * add migration * fix linting (cherry picked from commit e611a736ed8a57e45c737fe6efdfffbe76084cb1) Co-authored-by: Eric Leijonmarck --- .../serviceaccounts/database/store.go | 17 +++- .../serviceaccounts/database/store_test.go | 93 ++++++++++++++++--- pkg/services/sqlstore/migrations/user_mig.go | 7 ++ 3 files changed, 102 insertions(+), 15 deletions(-) diff --git a/pkg/services/serviceaccounts/database/store.go b/pkg/services/serviceaccounts/database/store.go index 581626a3d2a3..ebb66ef48423 100644 --- a/pkg/services/serviceaccounts/database/store.go +++ b/pkg/services/serviceaccounts/database/store.go @@ -42,10 +42,19 @@ func ProvideServiceAccountsStore(cfg *setting.Cfg, store db.DB, apiKeyService ap } } +// generateLogin makes a generated string to have a ID for the service account across orgs and it's name +// this causes you to create a service account with the same name in different orgs +// not the same name in the same org +func generateLogin(prefix string, orgId int64, name string) string { + generatedLogin := fmt.Sprintf("%v-%v-%v", prefix, orgId, strings.ToLower(name)) + // in case the name has multiple spaces or dashes in the prefix or otherwise, replace them with a single dash + generatedLogin = strings.Replace(generatedLogin, "--", "-", 1) + return strings.Replace(generatedLogin, " ", "-", -1) +} + // CreateServiceAccount creates service account func (s *ServiceAccountsStoreImpl) CreateServiceAccount(ctx context.Context, orgId int64, saForm *serviceaccounts.CreateServiceAccountForm) (*serviceaccounts.ServiceAccountDTO, error) { - generatedLogin := serviceaccounts.ServiceAccountPrefix + strings.ToLower(saForm.Name) - generatedLogin = strings.ReplaceAll(generatedLogin, " ", "-") + login := generateLogin(serviceaccounts.ServiceAccountPrefix, orgId, saForm.Name) isDisabled := false role := org.RoleViewer if saForm.IsDisabled != nil { @@ -56,7 +65,7 @@ func (s *ServiceAccountsStoreImpl) CreateServiceAccount(ctx context.Context, org } newSA, err := s.userService.CreateServiceAccount(ctx, &user.CreateUserCommand{ - Login: generatedLogin, + Login: login, OrgID: orgId, Name: saForm.Name, IsDisabled: isDisabled, @@ -435,7 +444,7 @@ func (s *ServiceAccountsStoreImpl) MigrateApiKey(ctx context.Context, orgId int6 func (s *ServiceAccountsStoreImpl) CreateServiceAccountFromApikey(ctx context.Context, key *apikey.APIKey) error { prefix := "sa-autogen" cmd := user.CreateUserCommand{ - Login: fmt.Sprintf("%v-%v-%v", prefix, key.OrgID, key.Name), + Login: generateLogin(prefix, key.OrgID, key.Name), Name: fmt.Sprintf("%v-%v", prefix, key.Name), OrgID: key.OrgID, DefaultOrgRole: string(key.Role), diff --git a/pkg/services/serviceaccounts/database/store_test.go b/pkg/services/serviceaccounts/database/store_test.go index 57bbd8e4d46a..42e8da777172 100644 --- a/pkg/services/serviceaccounts/database/store_test.go +++ b/pkg/services/serviceaccounts/database/store_test.go @@ -30,8 +30,8 @@ func TestMain(m *testing.M) { // Service Account should not create an org on its own func TestStore_CreateServiceAccountOrgNonExistant(t *testing.T) { _, store := setupTestDatabase(t) + serviceAccountName := "new Service Account" t.Run("create service account", func(t *testing.T) { - serviceAccountName := "new Service Account" serviceAccountOrgId := int64(1) serviceAccountRole := org.RoleAdmin isDisabled := true @@ -47,13 +47,12 @@ func TestStore_CreateServiceAccountOrgNonExistant(t *testing.T) { } func TestStore_CreateServiceAccount(t *testing.T) { - _, store := setupTestDatabase(t) - orgQuery := &org.CreateOrgCommand{Name: orgimpl.MainOrgName} - orgResult, err := store.orgService.CreateWithMember(context.Background(), orgQuery) - require.NoError(t, err) - + serviceAccountName := "new Service Account" t.Run("create service account", func(t *testing.T) { - serviceAccountName := "new Service Account" + _, store := setupTestDatabase(t) + orgQuery := &org.CreateOrgCommand{Name: orgimpl.MainOrgName} + orgResult, err := store.orgService.CreateWithMember(context.Background(), orgQuery) + require.NoError(t, err) serviceAccountOrgId := orgResult.ID serviceAccountRole := org.RoleAdmin isDisabled := true @@ -65,13 +64,11 @@ func TestStore_CreateServiceAccount(t *testing.T) { saDTO, err := store.CreateServiceAccount(context.Background(), serviceAccountOrgId, &saForm) require.NoError(t, err) - assert.Equal(t, "sa-new-service-account", saDTO.Login) assert.Equal(t, serviceAccountName, saDTO.Name) assert.Equal(t, 0, int(saDTO.Tokens)) retrieved, err := store.RetrieveServiceAccount(context.Background(), serviceAccountOrgId, saDTO.Id) require.NoError(t, err) - assert.Equal(t, "sa-new-service-account", retrieved.Login) assert.Equal(t, serviceAccountName, retrieved.Name) assert.Equal(t, serviceAccountOrgId, retrieved.OrgId) assert.Equal(t, string(serviceAccountRole), retrieved.Role) @@ -81,6 +78,82 @@ func TestStore_CreateServiceAccount(t *testing.T) { require.NoError(t, err) assert.Equal(t, saDTO.Id, retrievedId) }) + + t.Run("create service account twice same org, error", func(t *testing.T) { + _, store := setupTestDatabase(t) + orgQuery := &org.CreateOrgCommand{Name: orgimpl.MainOrgName} + orgResult, err := store.orgService.CreateWithMember(context.Background(), orgQuery) + require.NoError(t, err) + serviceAccountOrgId := orgResult.ID + serviceAccountRole := org.RoleAdmin + isDisabled := true + saForm := serviceaccounts.CreateServiceAccountForm{ + Name: serviceAccountName, + Role: &serviceAccountRole, + IsDisabled: &isDisabled, + } + + saDTO, err := store.CreateServiceAccount(context.Background(), serviceAccountOrgId, &saForm) + require.NoError(t, err) + assert.Equal(t, serviceAccountName, saDTO.Name) + assert.Equal(t, 0, int(saDTO.Tokens)) + + retrieved, err := store.RetrieveServiceAccount(context.Background(), serviceAccountOrgId, saDTO.Id) + require.NoError(t, err) + assert.Equal(t, serviceAccountName, retrieved.Name) + assert.Equal(t, serviceAccountOrgId, retrieved.OrgId) + assert.Equal(t, string(serviceAccountRole), retrieved.Role) + assert.True(t, retrieved.IsDisabled) + + retrievedId, err := store.RetrieveServiceAccountIdByName(context.Background(), serviceAccountOrgId, serviceAccountName) + require.NoError(t, err) + assert.Equal(t, saDTO.Id, retrievedId) + + // should not b able to create the same service account twice in the same org + _, err = store.CreateServiceAccount(context.Background(), serviceAccountOrgId, &saForm) + require.Error(t, err) + }) + + t.Run("create service account twice different orgs should work", func(t *testing.T) { + _, store := setupTestDatabase(t) + orgQuery := &org.CreateOrgCommand{Name: orgimpl.MainOrgName} + orgResult, err := store.orgService.CreateWithMember(context.Background(), orgQuery) + require.NoError(t, err) + serviceAccountOrgId := orgResult.ID + serviceAccountRole := org.RoleAdmin + isDisabled := true + saForm := serviceaccounts.CreateServiceAccountForm{ + Name: serviceAccountName, + Role: &serviceAccountRole, + IsDisabled: &isDisabled, + } + + saDTO, err := store.CreateServiceAccount(context.Background(), serviceAccountOrgId, &saForm) + require.NoError(t, err) + assert.Equal(t, serviceAccountName, saDTO.Name) + assert.Equal(t, 0, int(saDTO.Tokens)) + + retrieved, err := store.RetrieveServiceAccount(context.Background(), serviceAccountOrgId, saDTO.Id) + require.NoError(t, err) + assert.Equal(t, serviceAccountName, retrieved.Name) + assert.Equal(t, serviceAccountOrgId, retrieved.OrgId) + assert.Equal(t, string(serviceAccountRole), retrieved.Role) + assert.True(t, retrieved.IsDisabled) + + retrievedId, err := store.RetrieveServiceAccountIdByName(context.Background(), serviceAccountOrgId, serviceAccountName) + require.NoError(t, err) + assert.Equal(t, saDTO.Id, retrievedId) + + orgQuerySecond := &org.CreateOrgCommand{Name: "Second Org name"} + orgResultSecond, err := store.orgService.CreateWithMember(context.Background(), orgQuerySecond) + require.NoError(t, err) + serviceAccountOrgIdSecond := orgResultSecond.ID + // should not b able to create the same service account twice in the same org + saDTOSecond, err := store.CreateServiceAccount(context.Background(), serviceAccountOrgIdSecond, &saForm) + require.NoError(t, err) + assert.Equal(t, serviceAccountName, saDTOSecond.Name) + assert.Equal(t, 0, int(saDTOSecond.Tokens)) + }) } func TestStore_CreateServiceAccountRoleNone(t *testing.T) { @@ -100,13 +173,11 @@ func TestStore_CreateServiceAccountRoleNone(t *testing.T) { saDTO, err := store.CreateServiceAccount(context.Background(), serviceAccountOrgId, &saForm) require.NoError(t, err) - assert.Equal(t, "sa-new-service-account", saDTO.Login) assert.Equal(t, serviceAccountName, saDTO.Name) assert.Equal(t, 0, int(saDTO.Tokens)) retrieved, err := store.RetrieveServiceAccount(context.Background(), serviceAccountOrgId, saDTO.Id) require.NoError(t, err) - assert.Equal(t, "sa-new-service-account", retrieved.Login) assert.Equal(t, serviceAccountName, retrieved.Name) assert.Equal(t, serviceAccountOrgId, retrieved.OrgId) assert.Equal(t, string(serviceAccountRole), retrieved.Role) diff --git a/pkg/services/sqlstore/migrations/user_mig.go b/pkg/services/sqlstore/migrations/user_mig.go index 4f56666fcdba..bac9f99bf118 100644 --- a/pkg/services/sqlstore/migrations/user_mig.go +++ b/pkg/services/sqlstore/migrations/user_mig.go @@ -153,6 +153,13 @@ func addUserMigrations(mg *Migrator) { mg.AddMigration("Add unique index user_uid", NewAddIndexMigration(userV2, &Index{ Cols: []string{"uid"}, Type: UniqueIndex, })) + + // Service accounts login were not unique per org. this migration is part of making it unique per org + // to be able to create service accounts that are unique per org + mg.AddMigration("Update login field for service accounts", NewRawSQLMigration(""). + SQLite("UPDATE user SET login = 'sa-' || CAST(org_id AS TEXT) || '-' || REPLACE(login, 'sa-', '') WHERE login IS NOT NULL AND is_service_account = 1;"). + Postgres("UPDATE \"user\" SET login = 'sa-' || org_id::text || '-' || REPLACE(login, 'sa-', '') WHERE login IS NOT NULL AND is_service_account = true;"). + Mysql("UPDATE user SET login = CONCAT('sa-', CAST(org_id AS CHAR), '-', REPLACE(login, 'sa-', '')) WHERE login IS NOT NULL AND is_service_account = 1;")) } const migSQLITEisServiceAccountNullable = `ALTER TABLE user ADD COLUMN tmp_service_account BOOLEAN DEFAULT 0; From fbd2400e4a898435bab0c08d7d47c65202e50332 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 6 Mar 2024 09:09:45 -0500 Subject: [PATCH 044/138] [v10.4.x] Docs: comment youtube videos back in (#83977) Docs: comment youtube videos back in (#83974) * Commented 4 youtube links back in * Fixed id (cherry picked from commit 316601258a7d7a614f30f1c4293a91090ce32bf1) Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --- docs/sources/whatsnew/whats-new-in-v10-4.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/sources/whatsnew/whats-new-in-v10-4.md b/docs/sources/whatsnew/whats-new-in-v10-4.md index 434ea61f73b6..545d53486897 100644 --- a/docs/sources/whatsnew/whats-new-in-v10-4.md +++ b/docs/sources/whatsnew/whats-new-in-v10-4.md @@ -58,7 +58,7 @@ Use the aforementioned tooling and warnings to plan migrations to React based [v To learn more, refer to the [Angular support deprecation](https://grafana.com/docs/grafana//developers/angular_deprecation/), which includes [recommended alternative plugins](https://grafana.com/docs/grafana//developers/angular_deprecation/angular-plugins/). - +{{< youtube id="XlEVs6g8dC8" >}} [Documentation](https://grafana.com/docs/grafana//developers/angular_deprecation/) @@ -148,7 +148,7 @@ When you're browsing Grafana - for example, exploring the dashboard and metrics Return to Previous is rolling out across Grafana Cloud now. To try Return to Previous in self-managed Grafana, turn on the `returnToPrevious` [feature toggle](https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/feature-toggles/) in Grafana v10.4 or newer. - +{{< youtube id="-Y3qPfD2wrA" >}} {{< admonition type="note" >}} The term **context** refers to applications in Grafana like Incident and OnCall, as well as core features like Explore and Dashboards. @@ -170,7 +170,7 @@ Simplified routing inherits the alert rule RBAC, increasing control over notific To try out Simplified Alert Notification Routing enable the `alertingSimplifiedRouting` feature toggle. - +{{< youtube id="uBBQ-_pWSNs" >}} ### Grafana Alerting upgrade with rule preview @@ -247,7 +247,7 @@ Screenshots: {{< figure src="/media/docs/plugins/PagerDuty-incidents-real-life-example.png" caption="Incidents annotations from PagerDuty data source on a dashboard panel" alt="Incidents annotations from PagerDuty data source on a dashboard panel" >}} - +{{< youtube id="dCklm2DaVqQ" >}} ### SurrealDB Data Source From 391a24025f9636aec68c2a6eefde2b93e4ffeac6 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 6 Mar 2024 08:55:52 -0600 Subject: [PATCH 045/138] [v10.4.x] Docs/datasources usman (#83985) Docs/datasources usman (#83712) * changed tags from oss to enterprise and cloud * added Dashboard Panel example * swapped the all-grafana-umbrella information to the correct page * added minor visibility improvements in steps * made some minor adjustments * added minor improvements * fixed a link * updates links * Apply suggestions from code review thanks for the improved suggestions. looks more better Co-authored-by: Jack Baldry * fixed links * fixed Grafana Enterprise link * run prettier * fixed add a data source links --------- Co-authored-by: Chris Moyer Co-authored-by: Jack Baldry (cherry picked from commit 544bff2539f6c37f1a8dabb13bcebea96f68ecee) Co-authored-by: Usman Ahmad --- .../data-source-management/_index.md | 45 +++--------------- docs/sources/datasources/_index.md | 46 +++++++++++++++++-- .../getting-started/build-first-dashboard.md | 2 +- .../get-started-grafana-influxdb.md | 2 +- 4 files changed, 52 insertions(+), 43 deletions(-) diff --git a/docs/sources/administration/data-source-management/_index.md b/docs/sources/administration/data-source-management/_index.md index f4a9be6f23b4..b57424f245ed 100644 --- a/docs/sources/administration/data-source-management/_index.md +++ b/docs/sources/administration/data-source-management/_index.md @@ -10,7 +10,7 @@ description: Data source management information for Grafana administrators labels: products: - enterprise - - oss + - cloud title: Data source management weight: 100 --- @@ -21,27 +21,15 @@ Grafana supports many different storage backends for your time series data (data Refer to [data sources]({{< relref "../../datasources" >}}) for more information about using data sources in Grafana. Only users with the organization admin role can add data sources. -## Add a data source - -Before you can create your first dashboard, you need to add your data source. - -{{% admonition type="note" %}} -Only users with the organization admin role can add data sources. -{{% /admonition %}} - -**To add a data source:** - -1. Click **Connections** in the left-side menu. -1. Enter the name of a specific data source in the search dialog. You can filter by **Data source** to only see data sources. -1. Click the data source you want to add. -1. Configure the data source following instructions specific to that data source. - For links to data source-specific documentation, see [Data sources]({{< relref "../../datasources" >}}). ## Data source permissions You can configure data source permissions to allow or deny certain users the ability to query, edit, or administrate a data source. Each data source’s configuration includes a Permissions tab where you can restrict data source permissions to specific users, service accounts, teams, or roles. -Query permission allows users to query the data source. Edit permission allows users to query the data source, edit the data source’s configuration and delete the data source. Admin permission allows users to query and edit the data source, change permissions on the data source and enable or disable query caching for the data source. + +- The `query` permission allows users to query the data source. +- The `edit` permission allows users to query the data source, edit the data source’s configuration and delete the data source. +- The `admin` permission allows users to query and edit the data source, change permissions on the data source and enable or disable query caching for the data source. {{% admonition type="note" %}} Available in [Grafana Enterprise]({{< relref "../../introduction/grafana-enterprise/" >}}) and [Grafana Cloud](/docs/grafana-cloud). @@ -71,7 +59,7 @@ You can assign data source permissions to users, service accounts, teams, and ro 1. Click **Connections** in the left-side menu. 1. Under Your connections, click **Data sources**. 1. Select the data source for which you want to edit permissions. -1. On the Permissions tab, find the user, service account, team, or role permission you want to update. +1. On the Permissions tab, find the **User**, **Service Account**, **Team**, or **Role** permission you want to update. 1. Select a different option in the **Permission** dropdown.
@@ -81,7 +69,7 @@ You can assign data source permissions to users, service accounts, teams, and ro 1. Click **Connections** in the left-side menu. 1. Under Your connections, click **Data sources**. 1. Select the data source from which you want to remove permissions. -1. On the Permissions tab, find the user, service account, team, or role permission you want to remove. +1. On the Permissions tab, find the **User**, **Service Account**, **Team**, or **Role** permission you want to remove. 1. Click the **X** next to the permission.
@@ -178,22 +166,3 @@ This action impacts all cache-enabled data sources. If you are using Memcached, ### Sending a request without cache If a data source query request contains an `X-Cache-Skip` header, then Grafana skips the caching middleware, and does not search the cache for a response. This can be particularly useful when debugging data source queries using cURL. - -## Add data source plugins - -Grafana ships with several [built-in data sources]({{< relref "../../datasources#built-in-core-data-sources" >}}). -You can add additional data sources as plugins, which you can install or create yourself. - -### Find data source plugins in the plugin catalog - -To view available data source plugins, go to the [plugin catalog](/grafana/plugins/?type=datasource) and select the "Data sources" filter. -For details about the plugin catalog, refer to [Plugin management]({{< relref "../../administration/plugin-management/" >}}). - -You can further filter the plugin catalog's results for data sources provided by the Grafana community, Grafana Labs, and partners. -If you use [Grafana Enterprise]({{< relref "../../introduction/grafana-enterprise/" >}}), you can also filter by Enterprise-supported plugins. - -For more documentation on a specific data source plugin's features, including its query language and editor, refer to its plugin catalog page. - -### Create a data source plugin - -To build your own data source plugin, refer to the ["Build a data source plugin"](/developers/plugin-tools/tutorials/build-a-data-source-plugin) tutorial and our documentation about [building a plugin](/developers/plugin-tools). diff --git a/docs/sources/datasources/_index.md b/docs/sources/datasources/_index.md index d264340a5e84..b738aa80a0c0 100644 --- a/docs/sources/datasources/_index.md +++ b/docs/sources/datasources/_index.md @@ -32,14 +32,29 @@ This documentation describes how to manage data sources in general, and how to configure or query the built-in data sources. For other data sources, refer to the list of [datasource plugins](/grafana/plugins/). -To develop a custom plugin, refer to [Build a plugin](/developers/plugin-tools). +To develop a custom plugin, refer to [Create a data source plugin](#create-a-data-source-plugin). ## Manage data sources Only users with the [organization administrator role][organization-roles] can add or remove data sources. To access data source management tools in Grafana as an administrator, navigate to **Configuration > Data Sources** in the Grafana sidebar. -For details on data source management, including instructions on how to add data sources and configure user permissions for queries, refer to the [administration documentation][data-source-management]. +For details on data source management, including instructions on how configure user permissions for queries, refer to the [administration documentation][data-source-management]. + +## Add a data source + +Before you can create your first dashboard, you need to add your data source. + +{{% admonition type="note" %}} +Only users with the organization admin role can add data sources. +{{% /admonition %}} + +**To add a data source:** + +1. Click **Connections** in the left-side menu. +1. Enter the name of a specific data source in the search dialog. You can filter by **Data source** to only see data sources. +1. Click the data source you want to add. +1. Configure the data source following instructions specific to that data source. ## Use query editors @@ -55,7 +70,7 @@ For example, this video demonstrates the visual Prometheus query builder: {{< vimeo 720004179 >}} -For general information about querying in Grafana, and common options and user interface elements across all query editors, refer to [Query and transform data][query-transform-data] . +For general information about querying in Grafana, and common options and user interface elements across all query editors, refer to [Query and transform data][query-transform-data]. ## Special data sources @@ -68,6 +83,7 @@ Grafana includes three special data sources: - You can't change an existing query to use the **Mixed** data source. - Grafana Play example: [Mixed data sources](https://play.grafana.org/d/000000100/mixed-datasources?orgId=1) - **Dashboard:** A data source that uses the result set from another panel in the same dashboard. The dashboard data source can use data either directly from the selected panel or from annotations attached to the selected panel. + - Grafana Play example: [Panel as Data source](https://play.grafana.org/d/ede8zps8ndb0gc/panel-as-data-source?orgId=1) ## Built-in core data sources @@ -91,6 +107,24 @@ These built-in core data sources are also included in the Grafana documentation: - [Testdata]({{< relref "./testdata" >}}) - [Zipkin]({{< relref "./zipkin" >}}) +## Add additional data source plugins + +You can add additional data sources as plugins (that are not available in core Grafana), which you can install or create yourself. + +### Find data source plugins in the plugin catalog + +To view available data source plugins, go to the [plugin catalog](/grafana/plugins/?type=datasource) and select the "Data sources" filter. +For details about the plugin catalog, refer to [Plugin management][Plugin-management]. + +You can further filter the plugin catalog's results for data sources provided by the Grafana community, Grafana Labs, and partners. +If you use [Grafana Enterprise][Grafana-Enterprise], you can also filter by Enterprise-supported plugins. + +For more documentation on a specific data source plugin's features, including its query language and editor, refer to its plugin catalog page. + +### Create a data source plugin + +To build your own data source plugin, refer to the [Build a data source plugin](/developers/plugin-tools/tutorials/build-a-data-source-plugin) tutorial and [Plugin tools](/developers/plugin-tools). + {{% docs/reference %}} [alerts]: "/docs/grafana/ -> /docs/grafana//alerting" [alerts]: "/docs/grafana-cloud/ -> /docs/grafana//alerting" @@ -109,4 +143,10 @@ These built-in core data sources are also included in the Grafana documentation: [query-transform-data]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/query-transform-data" [query-transform-data]: "/docs/grafana-cloud/ -> /docs/grafana//panels-visualizations/query-transform-data" + +[Plugin-management]: "/docs/grafana/ -> /docs/grafana//administration/plugin-management" +[Plugin-management]: "/docs/grafana-cloud -> /docs/grafana//administration/plugin-management" + +[Grafana-Enterprise]: "/docs/grafana/ -> /docs/grafana//introduction/grafana-enterprise" + {{% /docs/reference %}} diff --git a/docs/sources/getting-started/build-first-dashboard.md b/docs/sources/getting-started/build-first-dashboard.md index 49dda7915a37..fd76142ab5fe 100644 --- a/docs/sources/getting-started/build-first-dashboard.md +++ b/docs/sources/getting-started/build-first-dashboard.md @@ -77,7 +77,7 @@ Congratulations, you have created your first dashboard and it's displaying resul #### Next steps -Continue to experiment with what you have built, try the [explore workflow]({{< relref "../explore" >}}) or another visualization feature. Refer to [Data sources]({{< relref "../datasources" >}}) for a list of supported data sources and instructions on how to [add a data source]({{< relref "../administration/data-source-management#add-a-data-source" >}}). The following topics will be of interest to you: +Continue to experiment with what you have built, try the [explore workflow]({{< relref "../explore" >}}) or another visualization feature. Refer to [Data sources]({{< relref "../datasources" >}}) for a list of supported data sources and instructions on how to [add a data source]({{< relref "../datasources#add-a-data-source" >}}). The following topics will be of interest to you: - [Panels and visualizations]({{< relref "../panels-visualizations" >}}) - [Dashboards]({{< relref "../dashboards" >}}) diff --git a/docs/sources/getting-started/get-started-grafana-influxdb.md b/docs/sources/getting-started/get-started-grafana-influxdb.md index c257014ae35c..d6a163a1219a 100644 --- a/docs/sources/getting-started/get-started-grafana-influxdb.md +++ b/docs/sources/getting-started/get-started-grafana-influxdb.md @@ -38,7 +38,7 @@ Windows users might need to make additional adjustments. Look for special instru You can have more than one InfluxDB data source defined in Grafana. -1. Follow the general instructions to [add a data source]({{< relref "../administration/data-source-management#add-a-data-source" >}}). +1. Follow the general instructions to [add a data source]({{< relref "../datasources#add-a-data-source" >}}). 1. Decide if you will use InfluxQL or Flux as your query language. - [Configure the data source]({{< relref "../datasources/influxdb#configure-the-data-source" >}}) for your chosen query language. Each query language has its own unique data source settings. From b379816be6d20f626f3ac106b889e7026eaac712 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 6 Mar 2024 17:18:54 +0200 Subject: [PATCH 046/138] [v10.4.x] Changelog: Updated changelog for 10.4.0 (#83988) Changelog: Updated changelog for 10.4.0 (#83987) Co-authored-by: grafanabot (cherry picked from commit 146ad85a564d21ff40269f0a6325ab938da61397) Co-authored-by: grafana-delivery-bot[bot] <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> --- CHANGELOG.md | 227 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee66a614138e..40968f165c6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,230 @@ + + +# 10.4.0 (2024-03-06) + +### Features and enhancements + +- **Chore:** Improve domain validation for Google OAuth - Backport 83229 to v10.4.x. [#83726](https://github.com/grafana/grafana/issues/83726), [@linoman](https://github.com/linoman) +- **DataQuery:** Track panel plugin id not type. [#83164](https://github.com/grafana/grafana/issues/83164), [@torkelo](https://github.com/torkelo) +- **AuthToken:** Remove client token rotation feature toggle. [#82886](https://github.com/grafana/grafana/issues/82886), [@kalleep](https://github.com/kalleep) +- **Plugins:** Enable feature toggle angularDeprecationUI by default. [#82880](https://github.com/grafana/grafana/issues/82880), [@xnyo](https://github.com/xnyo) +- **Table Component:** Improve text-wrapping behavior of cells. [#82872](https://github.com/grafana/grafana/issues/82872), [@ahuarte47](https://github.com/ahuarte47) +- **Alerting:** Dry-run legacy upgrade on startup. [#82835](https://github.com/grafana/grafana/issues/82835), [@JacobsonMT](https://github.com/JacobsonMT) +- **Tempo:** Upgrade @grafana/lezer-traceql patch version to use trace metrics syntax. [#82532](https://github.com/grafana/grafana/issues/82532), [@joey-grafana](https://github.com/joey-grafana) +- **Logs Panel:** Add CSV to download options. [#82480](https://github.com/grafana/grafana/issues/82480), [@gtk-grafana](https://github.com/gtk-grafana) +- **Folders:** Switch order of the columns in folder table indexes so that org_id becomes first. [#82454](https://github.com/grafana/grafana/issues/82454), [@papagian](https://github.com/papagian) +- **Logs panel:** Table UI - Guess string field types. [#82397](https://github.com/grafana/grafana/issues/82397), [@gtk-grafana](https://github.com/gtk-grafana) +- **Alerting:** Send alerts to APIv2 when using the Alertmanager contact point. [#82373](https://github.com/grafana/grafana/issues/82373), [@grobinson-grafana](https://github.com/grobinson-grafana) +- **Alerting:** Emit warning when creating or updating unusually large groups. [#82279](https://github.com/grafana/grafana/issues/82279), [@alexweav](https://github.com/alexweav) +- **Keybindings:** Change 'h' to 'mod+h' to open help modal. [#82253](https://github.com/grafana/grafana/issues/82253), [@tskarhed](https://github.com/tskarhed) +- **Chore:** Update arrow and prometheus dependencies. [#82215](https://github.com/grafana/grafana/issues/82215), [@ryantxu](https://github.com/ryantxu) +- **Alerting:** Enable group-level rule evaluation jittering by default, remove feature toggle. [#82212](https://github.com/grafana/grafana/issues/82212), [@alexweav](https://github.com/alexweav) +- **Loki Log Context:** Always show label filters with at least one parsed label. [#82211](https://github.com/grafana/grafana/issues/82211), [@svennergr](https://github.com/svennergr) +- **Logs Panel:** Table UI - better default column spacing. [#82205](https://github.com/grafana/grafana/issues/82205), [@gtk-grafana](https://github.com/gtk-grafana) +- **RBAC:** Migration to remove the scope from permissions where action is alert.instances:read. [#82202](https://github.com/grafana/grafana/issues/82202), [@IevaVasiljeva](https://github.com/IevaVasiljeva) +- **JWT Authentication:** Add support for specifying groups in auth.jwt for teamsync. [#82175](https://github.com/grafana/grafana/issues/82175), [@Jguer](https://github.com/Jguer) +- **Alerting:** GA alertingPreviewUpgrade and enable by default. [#82038](https://github.com/grafana/grafana/issues/82038), [@JacobsonMT](https://github.com/JacobsonMT) +- **Elasticsearch:** Apply ad-hoc filters to annotation queries. [#82032](https://github.com/grafana/grafana/issues/82032), [@mikelv92](https://github.com/mikelv92) +- **Alerting:** Show legacy provisioned alert rules warning. [#81902](https://github.com/grafana/grafana/issues/81902), [@gillesdemey](https://github.com/gillesdemey) +- **Tempo:** Support TraceQL metrics queries. [#81886](https://github.com/grafana/grafana/issues/81886), [@adrapereira](https://github.com/adrapereira) +- **Tempo:** Support backtick strings. [#81802](https://github.com/grafana/grafana/issues/81802), [@fabrizio-grafana](https://github.com/fabrizio-grafana) +- **Dashboards:** Remove `advancedDataSourcePicker` feature toggle. [#81790](https://github.com/grafana/grafana/issues/81790), [@Sergej-Vlasov](https://github.com/Sergej-Vlasov) +- **CloudWatch:** Remove references to pkg/infra/metrics. [#81744](https://github.com/grafana/grafana/issues/81744), [@iwysiu](https://github.com/iwysiu) +- **Licensing:** Redact license when overriden by env variable. [#81726](https://github.com/grafana/grafana/issues/81726), [@leandro-deveikis](https://github.com/leandro-deveikis) +- **Explore:** Disable cursor sync. [#81698](https://github.com/grafana/grafana/issues/81698), [@ifrost](https://github.com/ifrost) +- **Tempo:** Add custom headers middleware for grpc client. [#81693](https://github.com/grafana/grafana/issues/81693), [@aocenas](https://github.com/aocenas) +- **Chore:** Update test database initialization. [#81673](https://github.com/grafana/grafana/issues/81673), [@DanCech](https://github.com/DanCech) +- **Elasticsearch:** Implement CheckHealth method in the backend. [#81671](https://github.com/grafana/grafana/issues/81671), [@mikelv92](https://github.com/mikelv92) +- **Tooltips:** Hide dimension configuration when tooltip mode is hidden. [#81627](https://github.com/grafana/grafana/issues/81627), [@codeincarnate](https://github.com/codeincarnate) +- **Alerting:** Show warning when cp does not exist and invalidate the form. [#81621](https://github.com/grafana/grafana/issues/81621), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron) +- **User:** Add uid colum to user table. [#81615](https://github.com/grafana/grafana/issues/81615), [@ryantxu](https://github.com/ryantxu) +- **Cloudwatch:** Remove core imports from infra/log. [#81543](https://github.com/grafana/grafana/issues/81543), [@njvrzm](https://github.com/njvrzm) +- **Alerting:** Add pagination and improved search for notification policies. [#81535](https://github.com/grafana/grafana/issues/81535), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron) +- **Alerting:** Move action buttons in the alert list view. [#81341](https://github.com/grafana/grafana/issues/81341), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron) +- **Grafana/ui:** Add deprecation notices to the legacy layout components. [#81328](https://github.com/grafana/grafana/issues/81328), [@Clarity-89](https://github.com/Clarity-89) +- **Cloudwatch:** Deprecate cloudwatchNewRegionsHandler feature toggle and remove core imports from featuremgmt. [#81310](https://github.com/grafana/grafana/issues/81310), [@njvrzm](https://github.com/njvrzm) +- **Candlestick:** Add tooltip options. [#81307](https://github.com/grafana/grafana/issues/81307), [@adela-almasan](https://github.com/adela-almasan) +- **Folders:** Forbid performing operations on folders via dashboards HTTP API. [#81264](https://github.com/grafana/grafana/issues/81264), [@undef1nd](https://github.com/undef1nd) +- **Feature Management:** Move awsDatasourcesNewFormStyling to Public Preview. [#81257](https://github.com/grafana/grafana/issues/81257), [@idastambuk](https://github.com/idastambuk) +- **Alerting:** Update API to use folders' full paths. [#81214](https://github.com/grafana/grafana/issues/81214), [@yuri-tceretian](https://github.com/yuri-tceretian) +- **Datasources:** Add concurrency number to the settings. [#81212](https://github.com/grafana/grafana/issues/81212), [@itsmylife](https://github.com/itsmylife) +- **CloudWatch:** Remove dependencies on grafana/pkg/setting. [#81208](https://github.com/grafana/grafana/issues/81208), [@iwysiu](https://github.com/iwysiu) +- **Logs:** Table UI - Allow users to resize field selection section. [#81201](https://github.com/grafana/grafana/issues/81201), [@gtk-grafana](https://github.com/gtk-grafana) +- **Dashboards:** Remove emptyDashboardPage feature flag. [#81188](https://github.com/grafana/grafana/issues/81188), [@Sergej-Vlasov](https://github.com/Sergej-Vlasov) +- **Cloudwatch:** Import httpClient from grafana-plugin-sdk-go instead of grafana/infra. [#81187](https://github.com/grafana/grafana/issues/81187), [@idastambuk](https://github.com/idastambuk) +- **Logs:** Table UI - Enable feature flag by default (GA). [#81185](https://github.com/grafana/grafana/issues/81185), [@gtk-grafana](https://github.com/gtk-grafana) +- **Tempo:** Improve tags UX. [#81166](https://github.com/grafana/grafana/issues/81166), [@joey-grafana](https://github.com/joey-grafana) +- **Table:** Cell inspector auto-detecting JSON. [#81152](https://github.com/grafana/grafana/issues/81152), [@gtk-grafana](https://github.com/gtk-grafana) +- **Grafana/ui:** Add Space component. [#81145](https://github.com/grafana/grafana/issues/81145), [@Clarity-89](https://github.com/Clarity-89) +- **Grafana/ui:** Add deprecation notice to the Form component. [#81068](https://github.com/grafana/grafana/issues/81068), [@Clarity-89](https://github.com/Clarity-89) +- **Alerting:** Swap order between Annotations and Labels step in the alert rule form. [#81060](https://github.com/grafana/grafana/issues/81060), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron) +- **Plugins:** Change managedPluginsInstall to public preview. [#81053](https://github.com/grafana/grafana/issues/81053), [@oshirohugo](https://github.com/oshirohugo) +- **Tempo:** Add span, trace vars to trace to metrics interpolation. [#81046](https://github.com/grafana/grafana/issues/81046), [@joey-grafana](https://github.com/joey-grafana) +- **Tempo:** Support multiple filter expressions for service graph queries. [#81037](https://github.com/grafana/grafana/issues/81037), [@domasx2](https://github.com/domasx2) +- **Alerting:** Support for simplified notification settings in rule API. [#81011](https://github.com/grafana/grafana/issues/81011), [@yuri-tceretian](https://github.com/yuri-tceretian) +- **Plugins:** Add fuzzy search to plugins catalogue. [#81001](https://github.com/grafana/grafana/issues/81001), [@Ukochka](https://github.com/Ukochka) +- **CloudWatch:** Only override contextDialer when using PDC. [#80992](https://github.com/grafana/grafana/issues/80992), [@leandro-deveikis](https://github.com/leandro-deveikis) +- **Alerting:** Add a feature flag to periodically save states. [#80987](https://github.com/grafana/grafana/issues/80987), [@JohnnyQQQQ](https://github.com/JohnnyQQQQ) +- **RBAC:** Return the underlying error instead of internal server or bad request for managed permission endpoints. [#80974](https://github.com/grafana/grafana/issues/80974), [@IevaVasiljeva](https://github.com/IevaVasiljeva) +- **Correlations:** Enable correlations feature toggle by default. [#80881](https://github.com/grafana/grafana/issues/80881), [@ifrost](https://github.com/ifrost) +- **Transformations:** Focus search input on drawer open. [#80859](https://github.com/grafana/grafana/issues/80859), [@codeincarnate](https://github.com/codeincarnate) +- **Packaging:** Use the GRAFANA_HOME variable in postinst script on Debian. [#80853](https://github.com/grafana/grafana/issues/80853), [@denisse-dev](https://github.com/denisse-dev) +- **Visualizations:** Hue gradient mode now applies to the line color . [#80805](https://github.com/grafana/grafana/issues/80805), [@torkelo](https://github.com/torkelo) +- **Drawer:** Resizable via draggable edge . [#80796](https://github.com/grafana/grafana/issues/80796), [@torkelo](https://github.com/torkelo) +- **Alerting:** Add setting to distribute rule group evaluations over time. [#80766](https://github.com/grafana/grafana/issues/80766), [@alexweav](https://github.com/alexweav) +- **Logs Panel:** Permalink (copy shortlink). [#80764](https://github.com/grafana/grafana/issues/80764), [@gtk-grafana](https://github.com/gtk-grafana) +- **VizTooltips:** Copy to clipboard functionality. [#80761](https://github.com/grafana/grafana/issues/80761), [@adela-almasan](https://github.com/adela-almasan) +- **AuthN:** Support reloading SSO config after the sso settings have changed. [#80734](https://github.com/grafana/grafana/issues/80734), [@mgyongyosi](https://github.com/mgyongyosi) +- **Logs Panel:** Add total count to logs volume panel in explore. [#80730](https://github.com/grafana/grafana/issues/80730), [@gtk-grafana](https://github.com/gtk-grafana) +- **Caching:** Remove useCachingService feature toggle. [#80695](https://github.com/grafana/grafana/issues/80695), [@mmandrus](https://github.com/mmandrus) +- **Table:** Support showing data links inline. . [#80691](https://github.com/grafana/grafana/issues/80691), [@ryantxu](https://github.com/ryantxu) +- **Storage:** Add support for sortBy selector. [#80680](https://github.com/grafana/grafana/issues/80680), [@DanCech](https://github.com/DanCech) +- **Alerting:** Add metric counting rule groups per org. [#80669](https://github.com/grafana/grafana/issues/80669), [@alexweav](https://github.com/alexweav) +- **RBAC:** Cover plugin routes. [#80578](https://github.com/grafana/grafana/issues/80578), [@gamab](https://github.com/gamab) +- **Profiling:** Import godeltaprof/http/pprof. [#80509](https://github.com/grafana/grafana/issues/80509), [@korniltsev](https://github.com/korniltsev) +- **Tempo:** Add warning message when scope missing in TraceQL. [#80472](https://github.com/grafana/grafana/issues/80472), [@joey-grafana](https://github.com/joey-grafana) +- **Cloudwatch:** Move getNextRefIdChar util from app/core/utils to @grafana/data. [#80471](https://github.com/grafana/grafana/issues/80471), [@idastambuk](https://github.com/idastambuk) +- **DataFrame:** Add optional unique id definition. [#80428](https://github.com/grafana/grafana/issues/80428), [@aocenas](https://github.com/aocenas) +- **Canvas:** Add element snapping and alignment. [#80407](https://github.com/grafana/grafana/issues/80407), [@nmarrs](https://github.com/nmarrs) +- **Logs:** Add show context to dashboard panel. [#80403](https://github.com/grafana/grafana/issues/80403), [@svennergr](https://github.com/svennergr) +- **Canvas:** Support context menu in panel edit mode. [#80335](https://github.com/grafana/grafana/issues/80335), [@nmarrs](https://github.com/nmarrs) +- **VizTooltip:** Add sizing options. [#80306](https://github.com/grafana/grafana/issues/80306), [@Develer](https://github.com/Develer) +- **Plugins:** Parse defaultValues correctly for nested options. [#80302](https://github.com/grafana/grafana/issues/80302), [@oshirohugo](https://github.com/oshirohugo) +- **Geomap:** Support geojson styling properties. [#80272](https://github.com/grafana/grafana/issues/80272), [@drew08t](https://github.com/drew08t) +- **Runtime:** Add property for disabling caching. [#80245](https://github.com/grafana/grafana/issues/80245), [@aangelisc](https://github.com/aangelisc) +- **Alerting:** Log scheduler maxAttempts, guard against invalid retry counts, log retry errors. [#80234](https://github.com/grafana/grafana/issues/80234), [@alexweav](https://github.com/alexweav) +- **Alerting:** Improve integration with dashboards. [#80201](https://github.com/grafana/grafana/issues/80201), [@konrad147](https://github.com/konrad147) +- **Transformations:** Use an explicit join seperator when converting from an array to string field. [#80169](https://github.com/grafana/grafana/issues/80169), [@ryantxu](https://github.com/ryantxu) +- **Build:** Update plugin IDs list in build and release process. [#80160](https://github.com/grafana/grafana/issues/80160), [@fabrizio-grafana](https://github.com/fabrizio-grafana) +- **NestedFolders:** Support Shared with me folder for showing items you've been granted access to. [#80141](https://github.com/grafana/grafana/issues/80141), [@joshhunt](https://github.com/joshhunt) +- **Log Context:** Add highlighted words to log rows. [#80119](https://github.com/grafana/grafana/issues/80119), [@svennergr](https://github.com/svennergr) +- **Tempo:** Add `}` when `{` is inserted automatically. [#80113](https://github.com/grafana/grafana/issues/80113), [@harrymaurya05](https://github.com/harrymaurya05) +- **Time Range:** Copy-paste Time Range. [#80107](https://github.com/grafana/grafana/issues/80107), [@harisrozajac](https://github.com/harisrozajac) +- **PanelContext:** Remove deprecated onSplitOpen. [#80087](https://github.com/grafana/grafana/issues/80087), [@harisrozajac](https://github.com/harisrozajac) +- **Docs:** Add HAProxy rewrite information considering `serve_from_sub_path` setting. [#80062](https://github.com/grafana/grafana/issues/80062), [@simPod](https://github.com/simPod) +- **Table:** Keep expanded rows persistent when data changes if it has unique ID. [#80031](https://github.com/grafana/grafana/issues/80031), [@aocenas](https://github.com/aocenas) +- **SSO Config:** Add generic OAuth. [#79972](https://github.com/grafana/grafana/issues/79972), [@Clarity-89](https://github.com/Clarity-89) +- **FeatureFlags:** Remove the unsupported/undocumented option to read flags from a file. [#79959](https://github.com/grafana/grafana/issues/79959), [@ryantxu](https://github.com/ryantxu) +- **Transformations:** Add Group to Nested Tables Transformation. [#79952](https://github.com/grafana/grafana/issues/79952), [@codeincarnate](https://github.com/codeincarnate) +- **Cloudwatch Metrics:** Adjust error handling. [#79911](https://github.com/grafana/grafana/issues/79911), [@idastambuk](https://github.com/idastambuk) +- **Tempo:** Decouple Tempo from Grafana core. [#79888](https://github.com/grafana/grafana/issues/79888), [@fabrizio-grafana](https://github.com/fabrizio-grafana) +- **Table Panel:** Filter column values with operators or expressions. [#79853](https://github.com/grafana/grafana/issues/79853), [@ahuarte47](https://github.com/ahuarte47) +- **Chore:** Generate shorter UIDs. [#79843](https://github.com/grafana/grafana/issues/79843), [@ryantxu](https://github.com/ryantxu) +- **Alerting:** MuteTiming service return errutil + GetTiming by name. [#79772](https://github.com/grafana/grafana/issues/79772), [@yuri-tceretian](https://github.com/yuri-tceretian) +- **Azure Monitor:** Add select all subscription option for ARG queries. [#79582](https://github.com/grafana/grafana/issues/79582), [@alyssabull](https://github.com/alyssabull) +- **Alerting:** Enable sending notifications to a specific topic on Telegram. [#79546](https://github.com/grafana/grafana/issues/79546), [@th0th](https://github.com/th0th) +- **Logs Panel:** Table UI - Reordering table columns via drag-and-drop. [#79536](https://github.com/grafana/grafana/issues/79536), [@gtk-grafana](https://github.com/gtk-grafana) +- **Cloudwatch:** Add AWS/EMRServerless and AWS/KafkaConnect Metrics . [#79532](https://github.com/grafana/grafana/issues/79532), [@DugeraProve](https://github.com/DugeraProve) +- **Transformations:** Move transformation help to drawer component. [#79247](https://github.com/grafana/grafana/issues/79247), [@codeincarnate](https://github.com/codeincarnate) +- **Stat:** Support no value in spark line. [#78986](https://github.com/grafana/grafana/issues/78986), [@FOWind](https://github.com/FOWind) +- **NodeGraph:** Use layered layout instead of force based layout. [#78957](https://github.com/grafana/grafana/issues/78957), [@aocenas](https://github.com/aocenas) +- **Alerting:** Create alertingQueryOptimization feature flag for alert query optimization. [#78932](https://github.com/grafana/grafana/issues/78932), [@JacobsonMT](https://github.com/JacobsonMT) +- **Dashboard:** New EmbeddedDashboard runtime component . [#78916](https://github.com/grafana/grafana/issues/78916), [@torkelo](https://github.com/torkelo) +- **Alerting:** Show warning when query optimized. [#78751](https://github.com/grafana/grafana/issues/78751), [@JacobsonMT](https://github.com/JacobsonMT) +- **Alerting:** Add support for TTL for pushover for Mimir Alertmanager. [#78687](https://github.com/grafana/grafana/issues/78687), [@gillesdemey](https://github.com/gillesdemey) +- **Grafana/ui:** Enable removing values in multiselect opened state. [#78662](https://github.com/grafana/grafana/issues/78662), [@FOWind](https://github.com/FOWind) +- **SQL datasources:** Consistent interval handling. [#78517](https://github.com/grafana/grafana/issues/78517), [@gabor](https://github.com/gabor) +- **Alerting:** During legacy migration reduce the number of created silences. [#78505](https://github.com/grafana/grafana/issues/78505), [@JacobsonMT](https://github.com/JacobsonMT) +- **UI:** New share button and toolbar reorganize. [#77563](https://github.com/grafana/grafana/issues/77563), [@evictorero](https://github.com/evictorero) +- **Alerting:** Update rule API to address folders by UID. [#74600](https://github.com/grafana/grafana/issues/74600), [@papagian](https://github.com/papagian) +- **Reports:** Add uid column to the database. (Enterprise) +- **Plugins:** Add metrics for cloud plugin install. (Enterprise) +- **RBAC:** Make seeding resilient to failed plugin loading. (Enterprise) +- **Plugins:** Support disabling caching at a plugin instance level. (Enterprise) + +### Bug fixes + +- **GenAI:** Update the component only when the response is fully generated. [#83895](https://github.com/grafana/grafana/issues/83895), [@ivanortegaalba](https://github.com/ivanortegaalba) +- **LDAP:** Fix LDAP users authenticated via auth proxy not being able to use LDAP active sync. [#83751](https://github.com/grafana/grafana/issues/83751), [@Jguer](https://github.com/Jguer) +- **Tempo:** Better fallbacks for metrics query. [#83688](https://github.com/grafana/grafana/issues/83688), [@adrapereira](https://github.com/adrapereira) +- **Tempo:** Add template variable interpolation for filters. [#83667](https://github.com/grafana/grafana/issues/83667), [@joey-grafana](https://github.com/joey-grafana) +- **Elasticsearch:** Fix adhoc filters not applied in frontend mode. [#83597](https://github.com/grafana/grafana/issues/83597), [@svennergr](https://github.com/svennergr) +- **AuthProxy:** Invalidate previous cached item for user when changes are made to any header. [#83287](https://github.com/grafana/grafana/issues/83287), [@klesh](https://github.com/klesh) +- **Alerting:** Fix saving evaluation group. [#83234](https://github.com/grafana/grafana/issues/83234), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron) +- **QueryVariableEditor:** Select a variable ds does not work. [#83181](https://github.com/grafana/grafana/issues/83181), [@ivanortegaalba](https://github.com/ivanortegaalba) +- **Logs Panel:** Add option extra UI functionality for log context. [#83129](https://github.com/grafana/grafana/issues/83129), [@svennergr](https://github.com/svennergr) +- **Auth:** Fix email verification bypass when using basic authentication. [#82914](https://github.com/grafana/grafana/issues/82914), [@volcanonoodle](https://github.com/volcanonoodle) +- **LibraryPanels/RBAC:** Fix issue where folder scopes weren't being correctly inherited. [#82700](https://github.com/grafana/grafana/issues/82700), [@kaydelaney](https://github.com/kaydelaney) +- **Table Panel:** Fix display of ad-hoc filter actions. [#82442](https://github.com/grafana/grafana/issues/82442), [@codeincarnate](https://github.com/codeincarnate) +- **Loki:** Update `@grafana/lezer-logql` to `0.2.3` containing fix for ip label name. [#82378](https://github.com/grafana/grafana/issues/82378), [@ivanahuckova](https://github.com/ivanahuckova) +- **Alerting:** Fix slack double pound and email summary. [#82333](https://github.com/grafana/grafana/issues/82333), [@gillesdemey](https://github.com/gillesdemey) +- **Elasticsearch:** Fix resource calls for paths that include `:`. [#82327](https://github.com/grafana/grafana/issues/82327), [@ivanahuckova](https://github.com/ivanahuckova) +- **Alerting:** Return provenance of notification templates. [#82274](https://github.com/grafana/grafana/issues/82274), [@julienduchesne](https://github.com/julienduchesne) +- **LibraryPanels:** Fix issue with repeated library panels. [#82255](https://github.com/grafana/grafana/issues/82255), [@kaydelaney](https://github.com/kaydelaney) +- **Loki:** Fix fetching of values for label if no previous equality operator. [#82251](https://github.com/grafana/grafana/issues/82251), [@ivanahuckova](https://github.com/ivanahuckova) +- **Alerting:** Fix data races and improve testing. [#81994](https://github.com/grafana/grafana/issues/81994), [@diegommm](https://github.com/diegommm) +- **chore:** Fix typo in GraphTresholdsStyleMode enum. [#81960](https://github.com/grafana/grafana/issues/81960), [@paulJonesCalian](https://github.com/paulJonesCalian) +- **CloudWatch:** Fix code editor not resizing on mount when content height is > 200px. [#81911](https://github.com/grafana/grafana/issues/81911), [@kevinwcyu](https://github.com/kevinwcyu) +- **FieldOptions:** Revert scalable unit option as we already support this via custom prefix/suffixes . [#81893](https://github.com/grafana/grafana/issues/81893), [@torkelo](https://github.com/torkelo) +- **Browse Dashboards:** Imported dashboards now display immediately in the dashboard list. [#81819](https://github.com/grafana/grafana/issues/81819), [@ashharrison90](https://github.com/ashharrison90) +- **Elasticsearch:** Set middlewares from Grafana's `httpClientProvider`. [#81814](https://github.com/grafana/grafana/issues/81814), [@svennergr](https://github.com/svennergr) +- **Folders:** Fix failure to update folder in SQLite. [#81795](https://github.com/grafana/grafana/issues/81795), [@papagian](https://github.com/papagian) +- **Plugins:** Never disable add new data source for core plugins. [#81774](https://github.com/grafana/grafana/issues/81774), [@oshirohugo](https://github.com/oshirohugo) +- **Alerting:** Fixes for pending period. [#81718](https://github.com/grafana/grafana/issues/81718), [@gillesdemey](https://github.com/gillesdemey) +- **Alerting:** Fix editing group of nested folder. [#81665](https://github.com/grafana/grafana/issues/81665), [@gillesdemey](https://github.com/gillesdemey) +- **Plugins:** Don't auto prepend app sub url to plugin asset paths. [#81658](https://github.com/grafana/grafana/issues/81658), [@wbrowne](https://github.com/wbrowne) +- **Alerting:** Fix inconsistent AM raw config when applied via sync vs API. [#81655](https://github.com/grafana/grafana/issues/81655), [@JacobsonMT](https://github.com/JacobsonMT) +- **Alerting:** Fix support check for export with modifications. [#81602](https://github.com/grafana/grafana/issues/81602), [@gillesdemey](https://github.com/gillesdemey) +- **Alerting:** Fix selecting empty contact point value for notification policy inheritance. [#81482](https://github.com/grafana/grafana/issues/81482), [@gillesdemey](https://github.com/gillesdemey) +- **Alerting:** Fix child provisioned polices not being rendered as provisioned. [#81449](https://github.com/grafana/grafana/issues/81449), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron) +- **Tempo:** Fix durations in TraceQL. [#81418](https://github.com/grafana/grafana/issues/81418), [@fabrizio-grafana](https://github.com/fabrizio-grafana) +- **Logs:** Fix toggleable filters to be applied for specified query. [#81368](https://github.com/grafana/grafana/issues/81368), [@ivanahuckova](https://github.com/ivanahuckova) +- **Loki:** Fix label not being added to all subexpressions. [#81360](https://github.com/grafana/grafana/issues/81360), [@svennergr](https://github.com/svennergr) +- **Loki/Elastic:** Assert queryfix value to always be string. [#81349](https://github.com/grafana/grafana/issues/81349), [@svennergr](https://github.com/svennergr) +- **Tempo:** Add query ref in the query editor. [#81343](https://github.com/grafana/grafana/issues/81343), [@joey-grafana](https://github.com/joey-grafana) +- **Transformations:** Use the display name of the original y field for the predicted field of the regression analysis transformation. [#81332](https://github.com/grafana/grafana/issues/81332), [@oscarkilhed](https://github.com/oscarkilhed) +- **Field:** Fix perf regression in getUniqueFieldName(). [#81323](https://github.com/grafana/grafana/issues/81323), [@leeoniya](https://github.com/leeoniya) +- **Alerting:** Fix scheduler to group folders by the unique key (orgID and UID). [#81303](https://github.com/grafana/grafana/issues/81303), [@yuri-tceretian](https://github.com/yuri-tceretian) +- **Alerting:** Fix migration edge-case race condition for silences. [#81206](https://github.com/grafana/grafana/issues/81206), [@JacobsonMT](https://github.com/JacobsonMT) +- **Explore:** Set default time range to now-1h. [#81135](https://github.com/grafana/grafana/issues/81135), [@ifrost](https://github.com/ifrost) +- **Elasticsearch:** Fix URL creation and allowlist for `/_mapping` requests. [#80970](https://github.com/grafana/grafana/issues/80970), [@svennergr](https://github.com/svennergr) +- **Postgres:** Handle single quotes in table names in the query editor. [#80951](https://github.com/grafana/grafana/issues/80951), [@gabor](https://github.com/gabor) +- **Folders:** Fix creating/updating a folder whose title has leading and trailing spaces. [#80909](https://github.com/grafana/grafana/issues/80909), [@papagian](https://github.com/papagian) +- **Loki:** Fix missing timerange in query builder values request. [#80829](https://github.com/grafana/grafana/issues/80829), [@svennergr](https://github.com/svennergr) +- **Elasticsearch:** Fix showing of logs when `__source` is log message field. [#80804](https://github.com/grafana/grafana/issues/80804), [@ivanahuckova](https://github.com/ivanahuckova) +- **Pyroscope:** Fix stale value for query in query editor. [#80753](https://github.com/grafana/grafana/issues/80753), [@joey-grafana](https://github.com/joey-grafana) +- **Stat:** Fix data links that refer to fields. [#80693](https://github.com/grafana/grafana/issues/80693), [@ajwerner](https://github.com/ajwerner) +- **RBAC:** Clean up data source permissions after data source deletion. [#80654](https://github.com/grafana/grafana/issues/80654), [@IevaVasiljeva](https://github.com/IevaVasiljeva) +- **Alerting:** Fix MuteTiming Get API to return provenance status. [#80494](https://github.com/grafana/grafana/issues/80494), [@yuri-tceretian](https://github.com/yuri-tceretian) +- **Tempo:** Fix regression caused by #79938. [#80465](https://github.com/grafana/grafana/issues/80465), [@fabrizio-grafana](https://github.com/fabrizio-grafana) +- **Alerting:** Fix preview getting the correct queries from the form. [#80458](https://github.com/grafana/grafana/issues/80458), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron) +- **Alerting:** Fix firing alerts title when showing active in Insights panel. [#80414](https://github.com/grafana/grafana/issues/80414), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron) +- **Postgres:** Fix enabling the socks proxy. [#80361](https://github.com/grafana/grafana/issues/80361), [@gabor](https://github.com/gabor) +- **Alerting:** Fix group filter. [#80358](https://github.com/grafana/grafana/issues/80358), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron) +- **Alerting:** Increase size of kvstore value type for MySQL to LONGTEXT. [#80331](https://github.com/grafana/grafana/issues/80331), [@JacobsonMT](https://github.com/JacobsonMT) +- **Annotations:** Split cleanup into separate queries and deletes to avoid deadlocks on MySQL. [#80329](https://github.com/grafana/grafana/issues/80329), [@alexweav](https://github.com/alexweav) +- **Loki:** Fix bug duplicating parsed labels across multiple log lines. [#80292](https://github.com/grafana/grafana/issues/80292), [@svennergr](https://github.com/svennergr) +- **Alerting:** Fix NoData & Error alerts not resolving when rule is reset. [#80184](https://github.com/grafana/grafana/issues/80184), [@JacobsonMT](https://github.com/JacobsonMT) +- **Loki:** Fix metric time splitting to split starting with the start time. [#80085](https://github.com/grafana/grafana/issues/80085), [@svennergr](https://github.com/svennergr) +- **Rendering:** Fix streaming panels always reaching timeout. [#80022](https://github.com/grafana/grafana/issues/80022), [@AgnesToulet](https://github.com/AgnesToulet) +- **Plugins:** Fix colon in CallResource URL returning an error when creating plugin resource request. [#79746](https://github.com/grafana/grafana/issues/79746), [@GiedriusS](https://github.com/GiedriusS) +- **PDF:** Fix initialization when SMTP is disabled. (Enterprise) +- **PDF:** Fix repeated panels placement issue. (Enterprise) +- **Report CSV:** Fix timeout with streaming panels. (Enterprise) +- **RBAC:** Avoid repopulating removed basic role permissions if the permission scope has changed. (Enterprise) + +### Breaking changes + +We're adding a between the response of the ID token HD parameter and the list of allowed domains. This feature can be disabled through the configuration toggle `validate_hd `. Anyone using the legacy Google OAuth configuration should disable this validation if the ID Token response doesn't have the HD parameter. Issue [#83726](https://github.com/grafana/grafana/issues/83726) + +If you use an automated provisioning (eg, Terraform) for custom roles, and have provisioned a role that includes permission with action `alert.instances:read` and some scope, you will need to update the permission in your provisioning files by removing the scope. Issue [#82202](https://github.com/grafana/grafana/issues/82202) + +**The following breaking change occurs only when feature flag `nestedFolders` is enabled.** +If the folder title contains the symbol `/` (forward-slash) the notifications created from the rules that are placed in that folder will contain an escape sequence for that symbol in the label `grafana_folder`. +For example, the folder title is `Grafana / Folder`. Currently the label `grafana_folder` will contain the title as it is. If PR is merged - the label value will be `Grafana \/ Folder`. +This can break notifications if notification policies have matches that match that label and folder. Issue [#81214](https://github.com/grafana/grafana/issues/81214) + +`PanelContext.onSplitOpen` is removed. In the context of Explore, plugins should use `field.getLinks` to get a list of data link models. Issue [#80087](https://github.com/grafana/grafana/issues/80087) + +The unstable alert rule API has been changed and now expects a folder UID instead of the folder title as namespace path parameter. +I addition to this, the responses that used to return the folder title now return `/` to uniquely identify them. +Any consumers of the specific API should be appropriately adapted. Issue [#74600](https://github.com/grafana/grafana/issues/74600) + +### Plugin development fixes & changes + +- **Grafana/UI:** Add new Splitter component . [#82357](https://github.com/grafana/grafana/issues/82357), [@torkelo](https://github.com/torkelo) + + # 10.3.3 (2024-02-02) From 303a80cdb5b3393c9f014445568c487451e9d35b Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 6 Mar 2024 17:38:14 +0200 Subject: [PATCH 047/138] Release: Bump version to 10.4.1 (#83989) "Release: Updated versions in package to 10.4.1" Co-authored-by: grafana-delivery-bot[bot] <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> --- lerna.json | 2 +- package.json | 2 +- packages/grafana-data/package.json | 4 +- packages/grafana-e2e-selectors/package.json | 2 +- packages/grafana-e2e/package.json | 6 +- packages/grafana-eslint-rules/package.json | 2 +- packages/grafana-flamegraph/package.json | 6 +- .../grafana-o11y-ds-frontend/package.json | 2 +- packages/grafana-plugin-configs/package.json | 2 +- packages/grafana-prometheus/package.json | 2 +- packages/grafana-runtime/package.json | 10 +- packages/grafana-schema/package.json | 2 +- .../x/AlertGroupsPanelCfg_types.gen.ts | 2 +- .../x/AnnotationsListPanelCfg_types.gen.ts | 2 +- .../panelcfg/x/BarChartPanelCfg_types.gen.ts | 2 +- .../panelcfg/x/BarGaugePanelCfg_types.gen.ts | 2 +- .../x/CandlestickPanelCfg_types.gen.ts | 2 +- .../panelcfg/x/CanvasPanelCfg_types.gen.ts | 2 +- .../x/CloudWatchDataQuery_types.gen.ts | 2 +- .../x/DashboardListPanelCfg_types.gen.ts | 2 +- .../panelcfg/x/DatagridPanelCfg_types.gen.ts | 2 +- .../panelcfg/x/DebugPanelCfg_types.gen.ts | 2 +- .../x/ElasticsearchDataQuery_types.gen.ts | 2 +- .../panelcfg/x/GaugePanelCfg_types.gen.ts | 2 +- .../panelcfg/x/GeomapPanelCfg_types.gen.ts | 2 +- .../panelcfg/x/HeatmapPanelCfg_types.gen.ts | 2 +- .../panelcfg/x/HistogramPanelCfg_types.gen.ts | 2 +- .../logs/panelcfg/x/LogsPanelCfg_types.gen.ts | 2 +- .../dataquery/x/LokiDataQuery_types.gen.ts | 2 +- .../news/panelcfg/x/NewsPanelCfg_types.gen.ts | 2 +- .../panelcfg/x/NodeGraphPanelCfg_types.gen.ts | 2 +- .../panelcfg/x/PieChartPanelCfg_types.gen.ts | 2 +- .../x/PrometheusDataQuery_types.gen.ts | 2 +- .../stat/panelcfg/x/StatPanelCfg_types.gen.ts | 2 +- .../x/StateTimelinePanelCfg_types.gen.ts | 2 +- .../x/StatusHistoryPanelCfg_types.gen.ts | 2 +- .../panelcfg/x/TablePanelCfg_types.gen.ts | 2 +- .../text/panelcfg/x/TextPanelCfg_types.gen.ts | 2 +- .../x/TimeSeriesPanelCfg_types.gen.ts | 2 +- .../panelcfg/x/TrendPanelCfg_types.gen.ts | 2 +- .../panelcfg/x/XYChartPanelCfg_types.gen.ts | 2 +- packages/grafana-sql/package.json | 2 +- packages/grafana-ui/package.json | 8 +- .../internal/input-datasource/package.json | 6 +- .../datasource/azuremonitor/package.json | 14 +-- .../datasource/cloud-monitoring/package.json | 14 +-- .../grafana-pyroscope-datasource/package.json | 12 +-- .../grafana-testdata-datasource/package.json | 14 +-- .../app/plugins/datasource/parca/package.json | 12 +-- .../app/plugins/datasource/tempo/package.json | 4 +- yarn.lock | 98 +++++++++---------- 51 files changed, 142 insertions(+), 142 deletions(-) diff --git a/lerna.json b/lerna.json index 5c5153e0abfe..6522ef819e4e 100644 --- a/lerna.json +++ b/lerna.json @@ -1,4 +1,4 @@ { "npmClient": "yarn", - "version": "10.4.0-pre" + "version": "10.4.1" } diff --git a/package.json b/package.json index 6a655697b6ee..1f76b28d4ca9 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "license": "AGPL-3.0-only", "private": true, "name": "grafana", - "version": "10.4.0-pre", + "version": "10.4.1", "repository": "github:grafana/grafana", "scripts": { "prebuild": "yarn plugin:build", diff --git a/packages/grafana-data/package.json b/packages/grafana-data/package.json index 33d9452d6638..bfe0c4dacf22 100644 --- a/packages/grafana-data/package.json +++ b/packages/grafana-data/package.json @@ -2,7 +2,7 @@ "author": "Grafana Labs", "license": "Apache-2.0", "name": "@grafana/data", - "version": "10.4.0-pre", + "version": "10.4.1", "description": "Grafana Data Library", "keywords": [ "typescript" @@ -36,7 +36,7 @@ }, "dependencies": { "@braintree/sanitize-url": "7.0.0", - "@grafana/schema": "10.4.0-pre", + "@grafana/schema": "10.4.1", "@types/d3-interpolate": "^3.0.0", "@types/string-hash": "1.1.3", "d3-interpolate": "3.0.1", diff --git a/packages/grafana-e2e-selectors/package.json b/packages/grafana-e2e-selectors/package.json index d54bbf963fc8..8f2728b69bc9 100644 --- a/packages/grafana-e2e-selectors/package.json +++ b/packages/grafana-e2e-selectors/package.json @@ -2,7 +2,7 @@ "author": "Grafana Labs", "license": "Apache-2.0", "name": "@grafana/e2e-selectors", - "version": "10.4.0-pre", + "version": "10.4.1", "description": "Grafana End-to-End Test Selectors Library", "keywords": [ "cli", diff --git a/packages/grafana-e2e/package.json b/packages/grafana-e2e/package.json index e0939cf11701..d7174eb4c2a4 100644 --- a/packages/grafana-e2e/package.json +++ b/packages/grafana-e2e/package.json @@ -2,7 +2,7 @@ "author": "Grafana Labs", "license": "Apache-2.0", "name": "@grafana/e2e", - "version": "10.4.0-pre", + "version": "10.4.1", "description": "Grafana End-to-End Test Library", "keywords": [ "cli", @@ -63,8 +63,8 @@ "@babel/core": "7.23.2", "@babel/preset-env": "7.23.2", "@cypress/webpack-preprocessor": "5.17.1", - "@grafana/e2e-selectors": "10.4.0-pre", - "@grafana/schema": "10.4.0-pre", + "@grafana/e2e-selectors": "10.4.1", + "@grafana/schema": "10.4.1", "@grafana/tsconfig": "^1.2.0-rc1", "@mochajs/json-file-reporter": "^1.2.0", "babel-loader": "9.1.3", diff --git a/packages/grafana-eslint-rules/package.json b/packages/grafana-eslint-rules/package.json index 62e5641857c2..ea40fdb8c750 100644 --- a/packages/grafana-eslint-rules/package.json +++ b/packages/grafana-eslint-rules/package.json @@ -1,7 +1,7 @@ { "name": "@grafana/eslint-plugin", "description": "ESLint rules for use within the Grafana repo. Not suitable (or supported) for external use.", - "version": "10.4.0-pre", + "version": "10.4.1", "main": "./index.cjs", "author": "Grafana Labs", "license": "Apache-2.0", diff --git a/packages/grafana-flamegraph/package.json b/packages/grafana-flamegraph/package.json index 8f24565639cb..8bf806ccfed3 100644 --- a/packages/grafana-flamegraph/package.json +++ b/packages/grafana-flamegraph/package.json @@ -2,7 +2,7 @@ "author": "Grafana Labs", "license": "Apache-2.0", "name": "@grafana/flamegraph", - "version": "10.4.0-pre", + "version": "10.4.1", "description": "Grafana flamegraph visualization component", "keywords": [ "grafana", @@ -44,8 +44,8 @@ ], "dependencies": { "@emotion/css": "11.11.2", - "@grafana/data": "10.4.0-pre", - "@grafana/ui": "10.4.0-pre", + "@grafana/data": "10.4.1", + "@grafana/ui": "10.4.1", "@leeoniya/ufuzzy": "1.0.14", "d3": "^7.8.5", "lodash": "4.17.21", diff --git a/packages/grafana-o11y-ds-frontend/package.json b/packages/grafana-o11y-ds-frontend/package.json index f6a542f88282..c79fccb12a47 100644 --- a/packages/grafana-o11y-ds-frontend/package.json +++ b/packages/grafana-o11y-ds-frontend/package.json @@ -3,7 +3,7 @@ "license": "AGPL-3.0-only", "name": "@grafana/o11y-ds-frontend", "private": true, - "version": "10.4.0-pre", + "version": "10.4.1", "description": "Library to manage traces in Grafana.", "sideEffects": false, "repository": { diff --git a/packages/grafana-plugin-configs/package.json b/packages/grafana-plugin-configs/package.json index a117a7d4173b..29baea44439c 100644 --- a/packages/grafana-plugin-configs/package.json +++ b/packages/grafana-plugin-configs/package.json @@ -2,7 +2,7 @@ "name": "@grafana/plugin-configs", "description": "Shared dependencies and files for core plugins", "private": true, - "version": "10.4.0-pre", + "version": "10.4.1", "dependencies": { "tslib": "2.6.2" }, diff --git a/packages/grafana-prometheus/package.json b/packages/grafana-prometheus/package.json index 8294bc24415f..0524b52fda7f 100644 --- a/packages/grafana-prometheus/package.json +++ b/packages/grafana-prometheus/package.json @@ -2,7 +2,7 @@ "author": "Grafana Labs", "license": "AGPL-3.0-only", "name": "@grafana/prometheus", - "version": "10.4.0-pre", + "version": "10.4.1", "description": "Grafana Prometheus Library", "keywords": [ "typescript" diff --git a/packages/grafana-runtime/package.json b/packages/grafana-runtime/package.json index 802542945768..edbc156fc948 100644 --- a/packages/grafana-runtime/package.json +++ b/packages/grafana-runtime/package.json @@ -2,7 +2,7 @@ "author": "Grafana Labs", "license": "Apache-2.0", "name": "@grafana/runtime", - "version": "10.4.0-pre", + "version": "10.4.1", "description": "Grafana Runtime Library", "keywords": [ "grafana", @@ -37,11 +37,11 @@ "postpack": "mv package.json.bak package.json" }, "dependencies": { - "@grafana/data": "10.4.0-pre", - "@grafana/e2e-selectors": "10.4.0-pre", + "@grafana/data": "10.4.1", + "@grafana/e2e-selectors": "10.4.1", "@grafana/faro-web-sdk": "^1.3.6", - "@grafana/schema": "10.4.0-pre", - "@grafana/ui": "10.4.0-pre", + "@grafana/schema": "10.4.1", + "@grafana/ui": "10.4.1", "history": "4.10.1", "lodash": "4.17.21", "rxjs": "7.8.1", diff --git a/packages/grafana-schema/package.json b/packages/grafana-schema/package.json index 93a26a054ef5..cea6e56247c3 100644 --- a/packages/grafana-schema/package.json +++ b/packages/grafana-schema/package.json @@ -2,7 +2,7 @@ "author": "Grafana Labs", "license": "Apache-2.0", "name": "@grafana/schema", - "version": "10.4.0-pre", + "version": "10.4.1", "description": "Grafana Schema Library", "keywords": [ "typescript" diff --git a/packages/grafana-schema/src/raw/composable/alertgroups/panelcfg/x/AlertGroupsPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/alertgroups/panelcfg/x/AlertGroupsPanelCfg_types.gen.ts index 35171faad268..c755fbad6681 100644 --- a/packages/grafana-schema/src/raw/composable/alertgroups/panelcfg/x/AlertGroupsPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/alertgroups/panelcfg/x/AlertGroupsPanelCfg_types.gen.ts @@ -9,7 +9,7 @@ // // Run 'make gen-cue' from repository root to regenerate. -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; export interface Options { /** diff --git a/packages/grafana-schema/src/raw/composable/annotationslist/panelcfg/x/AnnotationsListPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/annotationslist/panelcfg/x/AnnotationsListPanelCfg_types.gen.ts index 38ed61a1e999..06588edf141f 100644 --- a/packages/grafana-schema/src/raw/composable/annotationslist/panelcfg/x/AnnotationsListPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/annotationslist/panelcfg/x/AnnotationsListPanelCfg_types.gen.ts @@ -9,7 +9,7 @@ // // Run 'make gen-cue' from repository root to regenerate. -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; export interface Options { limit: number; diff --git a/packages/grafana-schema/src/raw/composable/barchart/panelcfg/x/BarChartPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/barchart/panelcfg/x/BarChartPanelCfg_types.gen.ts index 0d84e7b958da..1d9f5049f24f 100644 --- a/packages/grafana-schema/src/raw/composable/barchart/panelcfg/x/BarChartPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/barchart/panelcfg/x/BarChartPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; export interface Options extends common.OptionsWithLegend, common.OptionsWithTooltip, common.OptionsWithTextFormatting { /** diff --git a/packages/grafana-schema/src/raw/composable/bargauge/panelcfg/x/BarGaugePanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/bargauge/panelcfg/x/BarGaugePanelCfg_types.gen.ts index 5da7e0a06a1a..b4d41f179037 100644 --- a/packages/grafana-schema/src/raw/composable/bargauge/panelcfg/x/BarGaugePanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/bargauge/panelcfg/x/BarGaugePanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; export interface Options extends common.SingleStatBaseOptions { displayMode: common.BarGaugeDisplayMode; diff --git a/packages/grafana-schema/src/raw/composable/candlestick/panelcfg/x/CandlestickPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/candlestick/panelcfg/x/CandlestickPanelCfg_types.gen.ts index 659a960d660d..18346b932501 100644 --- a/packages/grafana-schema/src/raw/composable/candlestick/panelcfg/x/CandlestickPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/candlestick/panelcfg/x/CandlestickPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; export enum VizDisplayMode { Candles = 'candles', diff --git a/packages/grafana-schema/src/raw/composable/canvas/panelcfg/x/CanvasPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/canvas/panelcfg/x/CanvasPanelCfg_types.gen.ts index 25f784c33056..76f2d9b77816 100644 --- a/packages/grafana-schema/src/raw/composable/canvas/panelcfg/x/CanvasPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/canvas/panelcfg/x/CanvasPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as ui from '@grafana/schema'; -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; export enum HorizontalConstraint { Center = 'center', diff --git a/packages/grafana-schema/src/raw/composable/cloudwatch/dataquery/x/CloudWatchDataQuery_types.gen.ts b/packages/grafana-schema/src/raw/composable/cloudwatch/dataquery/x/CloudWatchDataQuery_types.gen.ts index afa80f5f20d5..7eec44d663e6 100644 --- a/packages/grafana-schema/src/raw/composable/cloudwatch/dataquery/x/CloudWatchDataQuery_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/cloudwatch/dataquery/x/CloudWatchDataQuery_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; export interface MetricStat { /** diff --git a/packages/grafana-schema/src/raw/composable/dashboardlist/panelcfg/x/DashboardListPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/dashboardlist/panelcfg/x/DashboardListPanelCfg_types.gen.ts index c0d006f38d76..20b280d3231a 100644 --- a/packages/grafana-schema/src/raw/composable/dashboardlist/panelcfg/x/DashboardListPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/dashboardlist/panelcfg/x/DashboardListPanelCfg_types.gen.ts @@ -9,7 +9,7 @@ // // Run 'make gen-cue' from repository root to regenerate. -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; export interface Options { /** diff --git a/packages/grafana-schema/src/raw/composable/datagrid/panelcfg/x/DatagridPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/datagrid/panelcfg/x/DatagridPanelCfg_types.gen.ts index b7ce92a11283..98fd2e74fd41 100644 --- a/packages/grafana-schema/src/raw/composable/datagrid/panelcfg/x/DatagridPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/datagrid/panelcfg/x/DatagridPanelCfg_types.gen.ts @@ -9,7 +9,7 @@ // // Run 'make gen-cue' from repository root to regenerate. -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; export interface Options { selectedSeries: number; diff --git a/packages/grafana-schema/src/raw/composable/debug/panelcfg/x/DebugPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/debug/panelcfg/x/DebugPanelCfg_types.gen.ts index 992f1715bb9d..af4e5a02cfd8 100644 --- a/packages/grafana-schema/src/raw/composable/debug/panelcfg/x/DebugPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/debug/panelcfg/x/DebugPanelCfg_types.gen.ts @@ -9,7 +9,7 @@ // // Run 'make gen-cue' from repository root to regenerate. -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; export type UpdateConfig = { render: boolean, diff --git a/packages/grafana-schema/src/raw/composable/elasticsearch/dataquery/x/ElasticsearchDataQuery_types.gen.ts b/packages/grafana-schema/src/raw/composable/elasticsearch/dataquery/x/ElasticsearchDataQuery_types.gen.ts index 1430847da328..cdc3bec66894 100644 --- a/packages/grafana-schema/src/raw/composable/elasticsearch/dataquery/x/ElasticsearchDataQuery_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/elasticsearch/dataquery/x/ElasticsearchDataQuery_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; export type BucketAggregation = (DateHistogram | Histogram | Terms | Filters | GeoHashGrid | Nested); diff --git a/packages/grafana-schema/src/raw/composable/gauge/panelcfg/x/GaugePanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/gauge/panelcfg/x/GaugePanelCfg_types.gen.ts index 1e1bdab28614..fd321550ac14 100644 --- a/packages/grafana-schema/src/raw/composable/gauge/panelcfg/x/GaugePanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/gauge/panelcfg/x/GaugePanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; export interface Options extends common.SingleStatBaseOptions { minVizHeight: number; diff --git a/packages/grafana-schema/src/raw/composable/geomap/panelcfg/x/GeomapPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/geomap/panelcfg/x/GeomapPanelCfg_types.gen.ts index 22715f7efb8a..880ca9975871 100644 --- a/packages/grafana-schema/src/raw/composable/geomap/panelcfg/x/GeomapPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/geomap/panelcfg/x/GeomapPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as ui from '@grafana/schema'; -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; export interface Options { basemap: ui.MapLayerOptions; diff --git a/packages/grafana-schema/src/raw/composable/heatmap/panelcfg/x/HeatmapPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/heatmap/panelcfg/x/HeatmapPanelCfg_types.gen.ts index 85669926292a..6f0a56fc42a8 100644 --- a/packages/grafana-schema/src/raw/composable/heatmap/panelcfg/x/HeatmapPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/heatmap/panelcfg/x/HeatmapPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as ui from '@grafana/schema'; -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; /** * Controls the color mode of the heatmap diff --git a/packages/grafana-schema/src/raw/composable/histogram/panelcfg/x/HistogramPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/histogram/panelcfg/x/HistogramPanelCfg_types.gen.ts index 595f1b4d12da..b4ce7790f3de 100644 --- a/packages/grafana-schema/src/raw/composable/histogram/panelcfg/x/HistogramPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/histogram/panelcfg/x/HistogramPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; export interface Options extends common.OptionsWithLegend, common.OptionsWithTooltip { /** diff --git a/packages/grafana-schema/src/raw/composable/logs/panelcfg/x/LogsPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/logs/panelcfg/x/LogsPanelCfg_types.gen.ts index 78e86d19bb41..697ff2032263 100644 --- a/packages/grafana-schema/src/raw/composable/logs/panelcfg/x/LogsPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/logs/panelcfg/x/LogsPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; export interface Options { dedupStrategy: common.LogsDedupStrategy; diff --git a/packages/grafana-schema/src/raw/composable/loki/dataquery/x/LokiDataQuery_types.gen.ts b/packages/grafana-schema/src/raw/composable/loki/dataquery/x/LokiDataQuery_types.gen.ts index a89814adb3b4..00ba037a5e15 100644 --- a/packages/grafana-schema/src/raw/composable/loki/dataquery/x/LokiDataQuery_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/loki/dataquery/x/LokiDataQuery_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; export enum QueryEditorMode { Builder = 'builder', diff --git a/packages/grafana-schema/src/raw/composable/news/panelcfg/x/NewsPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/news/panelcfg/x/NewsPanelCfg_types.gen.ts index c53fdefa355d..462ed0ce12cc 100644 --- a/packages/grafana-schema/src/raw/composable/news/panelcfg/x/NewsPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/news/panelcfg/x/NewsPanelCfg_types.gen.ts @@ -9,7 +9,7 @@ // // Run 'make gen-cue' from repository root to regenerate. -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; export interface Options { /** diff --git a/packages/grafana-schema/src/raw/composable/nodegraph/panelcfg/x/NodeGraphPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/nodegraph/panelcfg/x/NodeGraphPanelCfg_types.gen.ts index 1df6d1a58641..9d7229c133a4 100644 --- a/packages/grafana-schema/src/raw/composable/nodegraph/panelcfg/x/NodeGraphPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/nodegraph/panelcfg/x/NodeGraphPanelCfg_types.gen.ts @@ -9,7 +9,7 @@ // // Run 'make gen-cue' from repository root to regenerate. -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; export interface ArcOption { /** diff --git a/packages/grafana-schema/src/raw/composable/piechart/panelcfg/x/PieChartPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/piechart/panelcfg/x/PieChartPanelCfg_types.gen.ts index 61cea8407ad8..185bd06b8dc8 100644 --- a/packages/grafana-schema/src/raw/composable/piechart/panelcfg/x/PieChartPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/piechart/panelcfg/x/PieChartPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; /** * Select the pie chart display style. diff --git a/packages/grafana-schema/src/raw/composable/prometheus/dataquery/x/PrometheusDataQuery_types.gen.ts b/packages/grafana-schema/src/raw/composable/prometheus/dataquery/x/PrometheusDataQuery_types.gen.ts index 3a31b3270eaa..c1c0c1234caa 100644 --- a/packages/grafana-schema/src/raw/composable/prometheus/dataquery/x/PrometheusDataQuery_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/prometheus/dataquery/x/PrometheusDataQuery_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; export enum QueryEditorMode { Builder = 'builder', diff --git a/packages/grafana-schema/src/raw/composable/stat/panelcfg/x/StatPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/stat/panelcfg/x/StatPanelCfg_types.gen.ts index 289f5994d4b8..3ee22187454c 100644 --- a/packages/grafana-schema/src/raw/composable/stat/panelcfg/x/StatPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/stat/panelcfg/x/StatPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; export interface Options extends common.SingleStatBaseOptions { colorMode: common.BigValueColorMode; diff --git a/packages/grafana-schema/src/raw/composable/statetimeline/panelcfg/x/StateTimelinePanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/statetimeline/panelcfg/x/StateTimelinePanelCfg_types.gen.ts index c61cc7994fd1..2854954366b5 100644 --- a/packages/grafana-schema/src/raw/composable/statetimeline/panelcfg/x/StateTimelinePanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/statetimeline/panelcfg/x/StateTimelinePanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as ui from '@grafana/schema'; -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; export interface Options extends ui.OptionsWithLegend, ui.OptionsWithTooltip, ui.OptionsWithTimezones { /** diff --git a/packages/grafana-schema/src/raw/composable/statushistory/panelcfg/x/StatusHistoryPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/statushistory/panelcfg/x/StatusHistoryPanelCfg_types.gen.ts index 1c1e77621dcb..6ce36c518f16 100644 --- a/packages/grafana-schema/src/raw/composable/statushistory/panelcfg/x/StatusHistoryPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/statushistory/panelcfg/x/StatusHistoryPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as ui from '@grafana/schema'; -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; export interface Options extends ui.OptionsWithLegend, ui.OptionsWithTooltip, ui.OptionsWithTimezones { /** diff --git a/packages/grafana-schema/src/raw/composable/table/panelcfg/x/TablePanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/table/panelcfg/x/TablePanelCfg_types.gen.ts index 6543c09cf458..f4ed813bddc5 100644 --- a/packages/grafana-schema/src/raw/composable/table/panelcfg/x/TablePanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/table/panelcfg/x/TablePanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as ui from '@grafana/schema'; -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; export interface Options { /** diff --git a/packages/grafana-schema/src/raw/composable/text/panelcfg/x/TextPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/text/panelcfg/x/TextPanelCfg_types.gen.ts index 94a0c6f67896..e8b90dfb22eb 100644 --- a/packages/grafana-schema/src/raw/composable/text/panelcfg/x/TextPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/text/panelcfg/x/TextPanelCfg_types.gen.ts @@ -9,7 +9,7 @@ // // Run 'make gen-cue' from repository root to regenerate. -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; export enum TextMode { Code = 'code', diff --git a/packages/grafana-schema/src/raw/composable/timeseries/panelcfg/x/TimeSeriesPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/timeseries/panelcfg/x/TimeSeriesPanelCfg_types.gen.ts index 4be736b87e7a..282b5e4841f6 100644 --- a/packages/grafana-schema/src/raw/composable/timeseries/panelcfg/x/TimeSeriesPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/timeseries/panelcfg/x/TimeSeriesPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; export interface Options extends common.OptionsWithTimezones { legend: common.VizLegendOptions; diff --git a/packages/grafana-schema/src/raw/composable/trend/panelcfg/x/TrendPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/trend/panelcfg/x/TrendPanelCfg_types.gen.ts index 2a9cf2d0f955..371487d2abdf 100644 --- a/packages/grafana-schema/src/raw/composable/trend/panelcfg/x/TrendPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/trend/panelcfg/x/TrendPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; /** * Identical to timeseries... except it does not have timezone settings diff --git a/packages/grafana-schema/src/raw/composable/xychart/panelcfg/x/XYChartPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/xychart/panelcfg/x/XYChartPanelCfg_types.gen.ts index 863c8252b68c..1ccd26619474 100644 --- a/packages/grafana-schema/src/raw/composable/xychart/panelcfg/x/XYChartPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/xychart/panelcfg/x/XYChartPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.0-pre"; +export const pluginVersion = "10.4.1"; /** * Auto is "table" in the UI diff --git a/packages/grafana-sql/package.json b/packages/grafana-sql/package.json index 57cd819cf5f6..39fa4d884876 100644 --- a/packages/grafana-sql/package.json +++ b/packages/grafana-sql/package.json @@ -3,7 +3,7 @@ "license": "AGPL-3.0-only", "private": true, "name": "@grafana/sql", - "version": "10.4.0-pre", + "version": "10.4.1", "repository": { "type": "git", "url": "http://github.com/grafana/grafana.git", diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index 6036034baf35..40f0e0fca722 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -2,7 +2,7 @@ "author": "Grafana Labs", "license": "Apache-2.0", "name": "@grafana/ui", - "version": "10.4.0-pre", + "version": "10.4.1", "description": "Grafana Components Library", "keywords": [ "grafana", @@ -50,10 +50,10 @@ "@emotion/css": "11.11.2", "@emotion/react": "11.11.3", "@floating-ui/react": "0.26.9", - "@grafana/data": "10.4.0-pre", - "@grafana/e2e-selectors": "10.4.0-pre", + "@grafana/data": "10.4.1", + "@grafana/e2e-selectors": "10.4.1", "@grafana/faro-web-sdk": "^1.3.6", - "@grafana/schema": "10.4.0-pre", + "@grafana/schema": "10.4.1", "@leeoniya/ufuzzy": "1.0.14", "@monaco-editor/react": "4.6.0", "@popperjs/core": "2.11.8", diff --git a/plugins-bundled/internal/input-datasource/package.json b/plugins-bundled/internal/input-datasource/package.json index a46c28fbeabb..123b0d9de3fa 100644 --- a/plugins-bundled/internal/input-datasource/package.json +++ b/plugins-bundled/internal/input-datasource/package.json @@ -1,6 +1,6 @@ { "name": "@grafana-plugins/input-datasource", - "version": "10.4.0-pre", + "version": "10.4.1", "description": "Input Datasource", "private": true, "repository": { @@ -28,8 +28,8 @@ "webpack": "5.76.0" }, "dependencies": { - "@grafana/data": "10.4.0-pre", - "@grafana/ui": "10.4.0-pre", + "@grafana/data": "10.4.1", + "@grafana/ui": "10.4.1", "react": "18.2.0", "tslib": "2.5.0" } diff --git a/public/app/plugins/datasource/azuremonitor/package.json b/public/app/plugins/datasource/azuremonitor/package.json index d81d275b6b1f..6440dcebfcd0 100644 --- a/public/app/plugins/datasource/azuremonitor/package.json +++ b/public/app/plugins/datasource/azuremonitor/package.json @@ -2,14 +2,14 @@ "name": "@grafana-plugins/grafana-azure-monitor-datasource", "description": "Grafana data source for Azure Monitor", "private": true, - "version": "10.4.0-pre", + "version": "10.4.1", "dependencies": { "@emotion/css": "11.11.2", - "@grafana/data": "10.4.0-pre", + "@grafana/data": "10.4.1", "@grafana/experimental": "1.7.10", - "@grafana/runtime": "10.4.0-pre", - "@grafana/schema": "10.4.0-pre", - "@grafana/ui": "10.4.0-pre", + "@grafana/runtime": "10.4.1", + "@grafana/schema": "10.4.1", + "@grafana/ui": "10.4.1", "@kusto/monaco-kusto": "^7.4.0", "fast-deep-equal": "^3.1.3", "i18next": "^23.0.0", @@ -23,8 +23,8 @@ "tslib": "2.6.2" }, "devDependencies": { - "@grafana/e2e-selectors": "10.4.0-pre", - "@grafana/plugin-configs": "10.4.0-pre", + "@grafana/e2e-selectors": "10.4.1", + "@grafana/plugin-configs": "10.4.1", "@testing-library/react": "14.2.1", "@testing-library/user-event": "14.5.2", "@types/jest": "29.5.12", diff --git a/public/app/plugins/datasource/cloud-monitoring/package.json b/public/app/plugins/datasource/cloud-monitoring/package.json index 5d8c0df358c3..c10deab27ee2 100644 --- a/public/app/plugins/datasource/cloud-monitoring/package.json +++ b/public/app/plugins/datasource/cloud-monitoring/package.json @@ -2,15 +2,15 @@ "name": "@grafana-plugins/stackdriver", "description": "Grafana data source for Google Cloud Monitoring", "private": true, - "version": "10.4.0-pre", + "version": "10.4.1", "dependencies": { "@emotion/css": "11.11.2", - "@grafana/data": "10.4.0-pre", + "@grafana/data": "10.4.1", "@grafana/experimental": "1.7.10", "@grafana/google-sdk": "0.1.2", - "@grafana/runtime": "10.4.0-pre", - "@grafana/schema": "10.4.0-pre", - "@grafana/ui": "10.4.0-pre", + "@grafana/runtime": "10.4.1", + "@grafana/schema": "10.4.1", + "@grafana/ui": "10.4.1", "@kusto/monaco-kusto": "^7.4.0", "debounce-promise": "3.1.2", "fast-deep-equal": "^3.1.3", @@ -25,8 +25,8 @@ "tslib": "2.6.2" }, "devDependencies": { - "@grafana/e2e-selectors": "10.4.0-pre", - "@grafana/plugin-configs": "10.4.0-pre", + "@grafana/e2e-selectors": "10.4.1", + "@grafana/plugin-configs": "10.4.1", "@testing-library/react": "14.2.1", "@testing-library/user-event": "14.5.2", "@types/debounce-promise": "3.1.9", diff --git a/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json b/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json index 3d1ba62c5234..552f138cb41e 100644 --- a/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json +++ b/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json @@ -2,13 +2,13 @@ "name": "@grafana-plugins/grafana-pyroscope-datasource", "description": "Continuous profiling for analysis of CPU and memory usage, down to the line number and throughout time. Saving infrastructure cost, improving performance, and increasing reliability.", "private": true, - "version": "10.4.0-pre", + "version": "10.4.1", "dependencies": { "@emotion/css": "11.11.2", - "@grafana/data": "10.4.0-pre", - "@grafana/runtime": "10.4.0-pre", - "@grafana/schema": "10.4.0-pre", - "@grafana/ui": "10.4.0-pre", + "@grafana/data": "10.4.1", + "@grafana/runtime": "10.4.1", + "@grafana/schema": "10.4.1", + "@grafana/ui": "10.4.1", "fast-deep-equal": "^3.1.3", "lodash": "4.17.21", "monaco-editor": "0.34.0", @@ -20,7 +20,7 @@ "tslib": "2.6.2" }, "devDependencies": { - "@grafana/plugin-configs": "10.4.0-pre", + "@grafana/plugin-configs": "10.4.1", "@testing-library/jest-dom": "6.4.2", "@testing-library/react": "14.2.1", "@testing-library/user-event": "14.5.2", diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/package.json b/public/app/plugins/datasource/grafana-testdata-datasource/package.json index 5819b4d0120f..710d93ff40f9 100644 --- a/public/app/plugins/datasource/grafana-testdata-datasource/package.json +++ b/public/app/plugins/datasource/grafana-testdata-datasource/package.json @@ -2,14 +2,14 @@ "name": "@grafana-plugins/grafana-testdata-datasource", "description": "Generates test data in different forms", "private": true, - "version": "10.4.0-pre", + "version": "10.4.1", "dependencies": { "@emotion/css": "11.11.2", - "@grafana/data": "10.4.0-pre", + "@grafana/data": "10.4.1", "@grafana/experimental": "1.7.10", - "@grafana/runtime": "10.4.0-pre", - "@grafana/schema": "10.4.0-pre", - "@grafana/ui": "10.4.0-pre", + "@grafana/runtime": "10.4.1", + "@grafana/schema": "10.4.1", + "@grafana/ui": "10.4.1", "d3-random": "^3.0.1", "lodash": "4.17.21", "micro-memoize": "^4.1.2", @@ -20,8 +20,8 @@ "uuid": "9.0.1" }, "devDependencies": { - "@grafana/e2e-selectors": "10.4.0-pre", - "@grafana/plugin-configs": "10.4.0-pre", + "@grafana/e2e-selectors": "10.4.1", + "@grafana/plugin-configs": "10.4.1", "@testing-library/react": "14.2.1", "@testing-library/user-event": "14.5.2", "@types/d3-random": "^3.0.2", diff --git a/public/app/plugins/datasource/parca/package.json b/public/app/plugins/datasource/parca/package.json index 1df0429b56e4..fa26883d82b0 100644 --- a/public/app/plugins/datasource/parca/package.json +++ b/public/app/plugins/datasource/parca/package.json @@ -2,13 +2,13 @@ "name": "@grafana-plugins/parca", "description": "Continuous profiling for analysis of CPU and memory usage, down to the line number and throughout time. Saving infrastructure cost, improving performance, and increasing reliability.", "private": true, - "version": "10.4.0-pre", + "version": "10.4.1", "dependencies": { "@emotion/css": "11.11.2", - "@grafana/data": "10.4.0-pre", - "@grafana/runtime": "10.4.0-pre", - "@grafana/schema": "10.4.0-pre", - "@grafana/ui": "10.4.0-pre", + "@grafana/data": "10.4.1", + "@grafana/runtime": "10.4.1", + "@grafana/schema": "10.4.1", + "@grafana/ui": "10.4.1", "lodash": "4.17.21", "monaco-editor": "0.34.0", "react": "18.2.0", @@ -17,7 +17,7 @@ "tslib": "2.6.2" }, "devDependencies": { - "@grafana/plugin-configs": "10.4.0-pre", + "@grafana/plugin-configs": "10.4.1", "@testing-library/react": "14.2.1", "@testing-library/user-event": "14.5.2", "@types/lodash": "4.14.202", diff --git a/public/app/plugins/datasource/tempo/package.json b/public/app/plugins/datasource/tempo/package.json index 679192a37768..2b14d8abdee5 100644 --- a/public/app/plugins/datasource/tempo/package.json +++ b/public/app/plugins/datasource/tempo/package.json @@ -2,7 +2,7 @@ "name": "@grafana-plugins/tempo", "description": "Grafana plugin for the Tempo data source.", "private": true, - "version": "10.4.0-pre", + "version": "10.4.1", "dependencies": { "@emotion/css": "11.11.2", "@grafana/data": "workspace:*", @@ -41,7 +41,7 @@ "uuid": "9.0.1" }, "devDependencies": { - "@grafana/plugin-configs": "10.4.0-pre", + "@grafana/plugin-configs": "10.4.1", "@testing-library/jest-dom": "6.4.2", "@testing-library/react": "14.2.1", "@testing-library/user-event": "14.5.2", diff --git a/yarn.lock b/yarn.lock index fe0f1545c546..43474fd6285f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3219,13 +3219,13 @@ __metadata: resolution: "@grafana-plugins/grafana-azure-monitor-datasource@workspace:public/app/plugins/datasource/azuremonitor" dependencies: "@emotion/css": "npm:11.11.2" - "@grafana/data": "npm:10.4.0-pre" - "@grafana/e2e-selectors": "npm:10.4.0-pre" + "@grafana/data": "npm:10.4.1" + "@grafana/e2e-selectors": "npm:10.4.1" "@grafana/experimental": "npm:1.7.10" - "@grafana/plugin-configs": "npm:10.4.0-pre" - "@grafana/runtime": "npm:10.4.0-pre" - "@grafana/schema": "npm:10.4.0-pre" - "@grafana/ui": "npm:10.4.0-pre" + "@grafana/plugin-configs": "npm:10.4.1" + "@grafana/runtime": "npm:10.4.1" + "@grafana/schema": "npm:10.4.1" + "@grafana/ui": "npm:10.4.1" "@kusto/monaco-kusto": "npm:^7.4.0" "@testing-library/react": "npm:14.2.1" "@testing-library/user-event": "npm:14.5.2" @@ -3259,11 +3259,11 @@ __metadata: resolution: "@grafana-plugins/grafana-pyroscope-datasource@workspace:public/app/plugins/datasource/grafana-pyroscope-datasource" dependencies: "@emotion/css": "npm:11.11.2" - "@grafana/data": "npm:10.4.0-pre" - "@grafana/plugin-configs": "npm:10.4.0-pre" - "@grafana/runtime": "npm:10.4.0-pre" - "@grafana/schema": "npm:10.4.0-pre" - "@grafana/ui": "npm:10.4.0-pre" + "@grafana/data": "npm:10.4.1" + "@grafana/plugin-configs": "npm:10.4.1" + "@grafana/runtime": "npm:10.4.1" + "@grafana/schema": "npm:10.4.1" + "@grafana/ui": "npm:10.4.1" "@testing-library/jest-dom": "npm:6.4.2" "@testing-library/react": "npm:14.2.1" "@testing-library/user-event": "npm:14.5.2" @@ -3298,13 +3298,13 @@ __metadata: resolution: "@grafana-plugins/grafana-testdata-datasource@workspace:public/app/plugins/datasource/grafana-testdata-datasource" dependencies: "@emotion/css": "npm:11.11.2" - "@grafana/data": "npm:10.4.0-pre" - "@grafana/e2e-selectors": "npm:10.4.0-pre" + "@grafana/data": "npm:10.4.1" + "@grafana/e2e-selectors": "npm:10.4.1" "@grafana/experimental": "npm:1.7.10" - "@grafana/plugin-configs": "npm:10.4.0-pre" - "@grafana/runtime": "npm:10.4.0-pre" - "@grafana/schema": "npm:10.4.0-pre" - "@grafana/ui": "npm:10.4.0-pre" + "@grafana/plugin-configs": "npm:10.4.1" + "@grafana/runtime": "npm:10.4.1" + "@grafana/schema": "npm:10.4.1" + "@grafana/ui": "npm:10.4.1" "@testing-library/react": "npm:14.2.1" "@testing-library/user-event": "npm:14.5.2" "@types/d3-random": "npm:^3.0.2" @@ -3333,9 +3333,9 @@ __metadata: version: 0.0.0-use.local resolution: "@grafana-plugins/input-datasource@workspace:plugins-bundled/internal/input-datasource" dependencies: - "@grafana/data": "npm:10.4.0-pre" + "@grafana/data": "npm:10.4.1" "@grafana/tsconfig": "npm:^1.2.0-rc1" - "@grafana/ui": "npm:10.4.0-pre" + "@grafana/ui": "npm:10.4.1" "@types/jest": "npm:26.0.15" "@types/react": "npm:18.0.28" copy-webpack-plugin: "npm:11.0.0" @@ -3357,11 +3357,11 @@ __metadata: resolution: "@grafana-plugins/parca@workspace:public/app/plugins/datasource/parca" dependencies: "@emotion/css": "npm:11.11.2" - "@grafana/data": "npm:10.4.0-pre" - "@grafana/plugin-configs": "npm:10.4.0-pre" - "@grafana/runtime": "npm:10.4.0-pre" - "@grafana/schema": "npm:10.4.0-pre" - "@grafana/ui": "npm:10.4.0-pre" + "@grafana/data": "npm:10.4.1" + "@grafana/plugin-configs": "npm:10.4.1" + "@grafana/runtime": "npm:10.4.1" + "@grafana/schema": "npm:10.4.1" + "@grafana/ui": "npm:10.4.1" "@testing-library/react": "npm:14.2.1" "@testing-library/user-event": "npm:14.5.2" "@types/lodash": "npm:4.14.202" @@ -3384,14 +3384,14 @@ __metadata: resolution: "@grafana-plugins/stackdriver@workspace:public/app/plugins/datasource/cloud-monitoring" dependencies: "@emotion/css": "npm:11.11.2" - "@grafana/data": "npm:10.4.0-pre" - "@grafana/e2e-selectors": "npm:10.4.0-pre" + "@grafana/data": "npm:10.4.1" + "@grafana/e2e-selectors": "npm:10.4.1" "@grafana/experimental": "npm:1.7.10" "@grafana/google-sdk": "npm:0.1.2" - "@grafana/plugin-configs": "npm:10.4.0-pre" - "@grafana/runtime": "npm:10.4.0-pre" - "@grafana/schema": "npm:10.4.0-pre" - "@grafana/ui": "npm:10.4.0-pre" + "@grafana/plugin-configs": "npm:10.4.1" + "@grafana/runtime": "npm:10.4.1" + "@grafana/schema": "npm:10.4.1" + "@grafana/ui": "npm:10.4.1" "@kusto/monaco-kusto": "npm:^7.4.0" "@testing-library/react": "npm:14.2.1" "@testing-library/user-event": "npm:14.5.2" @@ -3436,7 +3436,7 @@ __metadata: "@grafana/lezer-traceql": "npm:0.0.15" "@grafana/monaco-logql": "npm:^0.0.7" "@grafana/o11y-ds-frontend": "workspace:*" - "@grafana/plugin-configs": "npm:10.4.0-pre" + "@grafana/plugin-configs": "npm:10.4.1" "@grafana/runtime": "workspace:*" "@grafana/schema": "workspace:*" "@grafana/ui": "workspace:*" @@ -3504,12 +3504,12 @@ __metadata: languageName: node linkType: hard -"@grafana/data@npm:10.4.0-pre, @grafana/data@workspace:*, @grafana/data@workspace:packages/grafana-data": +"@grafana/data@npm:10.4.1, @grafana/data@workspace:*, @grafana/data@workspace:packages/grafana-data": version: 0.0.0-use.local resolution: "@grafana/data@workspace:packages/grafana-data" dependencies: "@braintree/sanitize-url": "npm:7.0.0" - "@grafana/schema": "npm:10.4.0-pre" + "@grafana/schema": "npm:10.4.1" "@grafana/tsconfig": "npm:^1.2.0-rc1" "@rollup/plugin-commonjs": "npm:25.0.7" "@rollup/plugin-json": "npm:6.1.0" @@ -3580,7 +3580,7 @@ __metadata: languageName: node linkType: hard -"@grafana/e2e-selectors@npm:10.4.0-pre, @grafana/e2e-selectors@workspace:*, @grafana/e2e-selectors@workspace:packages/grafana-e2e-selectors": +"@grafana/e2e-selectors@npm:10.4.1, @grafana/e2e-selectors@workspace:*, @grafana/e2e-selectors@workspace:packages/grafana-e2e-selectors": version: 0.0.0-use.local resolution: "@grafana/e2e-selectors@workspace:packages/grafana-e2e-selectors" dependencies: @@ -3606,8 +3606,8 @@ __metadata: "@babel/core": "npm:7.23.2" "@babel/preset-env": "npm:7.23.2" "@cypress/webpack-preprocessor": "npm:5.17.1" - "@grafana/e2e-selectors": "npm:10.4.0-pre" - "@grafana/schema": "npm:10.4.0-pre" + "@grafana/e2e-selectors": "npm:10.4.1" + "@grafana/schema": "npm:10.4.1" "@grafana/tsconfig": "npm:^1.2.0-rc1" "@mochajs/json-file-reporter": "npm:^1.2.0" "@rollup/plugin-node-resolve": "npm:15.2.3" @@ -3751,9 +3751,9 @@ __metadata: "@babel/preset-env": "npm:7.23.9" "@babel/preset-react": "npm:7.23.3" "@emotion/css": "npm:11.11.2" - "@grafana/data": "npm:10.4.0-pre" + "@grafana/data": "npm:10.4.1" "@grafana/tsconfig": "npm:^1.2.0-rc1" - "@grafana/ui": "npm:10.4.0-pre" + "@grafana/ui": "npm:10.4.1" "@leeoniya/ufuzzy": "npm:1.0.14" "@rollup/plugin-node-resolve": "npm:15.2.3" "@testing-library/jest-dom": "npm:^6.1.2" @@ -3860,7 +3860,7 @@ __metadata: languageName: unknown linkType: soft -"@grafana/plugin-configs@npm:10.4.0-pre, @grafana/plugin-configs@workspace:packages/grafana-plugin-configs": +"@grafana/plugin-configs@npm:10.4.1, @grafana/plugin-configs@workspace:packages/grafana-plugin-configs": version: 0.0.0-use.local resolution: "@grafana/plugin-configs@workspace:packages/grafana-plugin-configs" dependencies: @@ -3990,16 +3990,16 @@ __metadata: languageName: unknown linkType: soft -"@grafana/runtime@npm:10.4.0-pre, @grafana/runtime@workspace:*, @grafana/runtime@workspace:packages/grafana-runtime": +"@grafana/runtime@npm:10.4.1, @grafana/runtime@workspace:*, @grafana/runtime@workspace:packages/grafana-runtime": version: 0.0.0-use.local resolution: "@grafana/runtime@workspace:packages/grafana-runtime" dependencies: - "@grafana/data": "npm:10.4.0-pre" - "@grafana/e2e-selectors": "npm:10.4.0-pre" + "@grafana/data": "npm:10.4.1" + "@grafana/e2e-selectors": "npm:10.4.1" "@grafana/faro-web-sdk": "npm:^1.3.6" - "@grafana/schema": "npm:10.4.0-pre" + "@grafana/schema": "npm:10.4.1" "@grafana/tsconfig": "npm:^1.2.0-rc1" - "@grafana/ui": "npm:10.4.0-pre" + "@grafana/ui": "npm:10.4.1" "@rollup/plugin-commonjs": "npm:25.0.7" "@rollup/plugin-node-resolve": "npm:15.2.3" "@testing-library/dom": "npm:9.3.4" @@ -4053,7 +4053,7 @@ __metadata: languageName: node linkType: hard -"@grafana/schema@npm:10.4.0-pre, @grafana/schema@workspace:*, @grafana/schema@workspace:packages/grafana-schema": +"@grafana/schema@npm:10.4.1, @grafana/schema@workspace:*, @grafana/schema@workspace:packages/grafana-schema": version: 0.0.0-use.local resolution: "@grafana/schema@workspace:packages/grafana-schema" dependencies: @@ -4127,7 +4127,7 @@ __metadata: languageName: node linkType: hard -"@grafana/ui@npm:10.4.0-pre, @grafana/ui@workspace:*, @grafana/ui@workspace:packages/grafana-ui": +"@grafana/ui@npm:10.4.1, @grafana/ui@workspace:*, @grafana/ui@workspace:packages/grafana-ui": version: 0.0.0-use.local resolution: "@grafana/ui@workspace:packages/grafana-ui" dependencies: @@ -4135,10 +4135,10 @@ __metadata: "@emotion/css": "npm:11.11.2" "@emotion/react": "npm:11.11.3" "@floating-ui/react": "npm:0.26.9" - "@grafana/data": "npm:10.4.0-pre" - "@grafana/e2e-selectors": "npm:10.4.0-pre" + "@grafana/data": "npm:10.4.1" + "@grafana/e2e-selectors": "npm:10.4.1" "@grafana/faro-web-sdk": "npm:^1.3.6" - "@grafana/schema": "npm:10.4.0-pre" + "@grafana/schema": "npm:10.4.1" "@grafana/tsconfig": "npm:^1.2.0-rc1" "@leeoniya/ufuzzy": "npm:1.0.14" "@monaco-editor/react": "npm:4.6.0" From b48e2102b375a16a7682dca0a203e2d6fa19592d Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 6 Mar 2024 10:03:34 -0600 Subject: [PATCH 048/138] [v10.4.x] Configure Grafana docs: fix custom configuration file location (#83999) Configure Grafana docs: fix custom configuration file location (#83169) * Configure Grafana docs: fix custom configuration file location * Replace config file with `custom.ini` --------- Co-authored-by: Jack Baldry (cherry picked from commit ce827f951815c941609a89b03c02e30eb748df23) Co-authored-by: Pepe Cano <825430+ppcano@users.noreply.github.com> --- docs/sources/setup-grafana/configure-grafana/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/setup-grafana/configure-grafana/_index.md b/docs/sources/setup-grafana/configure-grafana/_index.md index bf00cb8c985f..4ae0253c2cf2 100644 --- a/docs/sources/setup-grafana/configure-grafana/_index.md +++ b/docs/sources/setup-grafana/configure-grafana/_index.md @@ -23,7 +23,7 @@ After you add custom options, [uncomment](#remove-comments-in-the-ini-files) the The default settings for a Grafana instance are stored in the `$WORKING_DIR/conf/defaults.ini` file. _Do not_ change this file. -Depending on your OS, your custom configuration file is either the `$WORKING_DIR/conf/defaults.ini` file or the `/usr/local/etc/grafana/grafana.ini` file. The custom configuration file path can be overridden using the `--config` parameter. +Depending on your OS, your custom configuration file is either the `$WORKING_DIR/conf/custom.ini` file or the `/usr/local/etc/grafana/grafana.ini` file. The custom configuration file path can be overridden using the `--config` parameter. ### Linux From b78ecddf56bcd7567c0defbe5a050170e32edeed Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 6 Mar 2024 11:41:19 -0500 Subject: [PATCH 049/138] [v10.4.x] Docs: comment in SSO for terraform video (#84013) Docs: comment in SSO for terraform video (#83978) * Commented in SSO for terraform video * Updated youtube link (cherry picked from commit 4bb5915183a8cf96199a24dd730b841c67cb0743) Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --- docs/sources/whatsnew/whats-new-in-v10-4.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/whatsnew/whats-new-in-v10-4.md b/docs/sources/whatsnew/whats-new-in-v10-4.md index 545d53486897..2c4c28d6e5f0 100644 --- a/docs/sources/whatsnew/whats-new-in-v10-4.md +++ b/docs/sources/whatsnew/whats-new-in-v10-4.md @@ -217,7 +217,7 @@ We are working on adding complete support for configuring all other supported OA ![Screenshot of the Authentication provider list page](/media/docs/grafana-cloud/screenshot-sso-settings-ui-public-prev-v10.4.png) - +{{< youtube id="xXW2eRTbjDY" >}} [Documentation](https://grafana.com/docs/grafana/next/setup-grafana/configure-security/configure-authentication/) From ee475ad250a24c09c87bf5994df346e5b610dca4 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 6 Mar 2024 11:40:18 -0600 Subject: [PATCH 050/138] [v10.4.x] disable_sanitize_html update (#84022) disable_sanitize_html update (#83643) * disable_sanitize_html update Added a note that states this configuration is not available for Grafana Cloud instances. * Update docs/sources/setup-grafana/configure-grafana/_index.md * Update docs/sources/setup-grafana/configure-grafana/_index.md --------- Co-authored-by: Christopher Moyer <35463610+chri2547@users.noreply.github.com> (cherry picked from commit 2142efc1a5fee5049a444b2b9a2e827f0137cd43) Co-authored-by: Dai Nguyen <88277570+ej25a@users.noreply.github.com> --- docs/sources/setup-grafana/configure-grafana/_index.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/sources/setup-grafana/configure-grafana/_index.md b/docs/sources/setup-grafana/configure-grafana/_index.md index 4ae0253c2cf2..8309031db5ad 100644 --- a/docs/sources/setup-grafana/configure-grafana/_index.md +++ b/docs/sources/setup-grafana/configure-grafana/_index.md @@ -2176,7 +2176,11 @@ Set to `true` if you want to test alpha panels that are not yet ready for genera ### disable_sanitize_html -If set to true Grafana will allow script tags in text panels. Not recommended as it enables XSS vulnerabilities. Default is false. This setting was introduced in Grafana v6.0. +{{% admonition type="note" %}} +This configuration is not available in Grafana Cloud instances. +{{% /admonition %}} + +If set to true Grafana will allow script tags in text panels. Not recommended as it enables XSS vulnerabilities. Default is false. ## [plugins] From 5c2b7e5c62e9ff824256e74ed7350d412cb34f3d Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 7 Mar 2024 09:16:19 +0100 Subject: [PATCH 051/138] [v10.4.x] Alerting docs: update the supported export template functionality (#84050) Alerting docs: update the supported export template functionality (#83816) (cherry picked from commit dbb55f291a79647f06827e6a6f9f51cd51c01506) Co-authored-by: Pepe Cano <825430+ppcano@users.noreply.github.com> --- .../export-alerting-resources/index.md | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/docs/sources/alerting/set-up/provision-alerting-resources/export-alerting-resources/index.md b/docs/sources/alerting/set-up/provision-alerting-resources/export-alerting-resources/index.md index 12b06c734bd8..001efde81aa2 100644 --- a/docs/sources/alerting/set-up/provision-alerting-resources/export-alerting-resources/index.md +++ b/docs/sources/alerting/set-up/provision-alerting-resources/export-alerting-resources/index.md @@ -86,7 +86,7 @@ To export contact points from the Grafana UI, complete the following steps. ### Export templates -Grafana currently doesn't offer an Export UI for notification templates, unlike other Alerting resources presented in this documentation. +Grafana currently doesn't offer an Export UI or [Export endpoint](#export-api-endpoints) for notification templates, unlike other Alerting resources presented in this documentation. However, you can export it by manually copying the content template and title directly from the Grafana UI. @@ -129,14 +129,17 @@ To export mute timings from the Grafana UI, complete the following steps. ## HTTP Alerting API -You can use the [Alerting HTTP API][alerting_http_provisioning] to return existing alerting resources in JSON and import them to another Grafana instance using the same endpoint. For instance: +You can use the [Alerting HTTP API][alerting_http_provisioning] to return existing alerting resources in JSON and import them to another Grafana instance using the same endpoint. -| Resource | Method / URI | Summary | -| ----------- | ------------------------------------- | ------------------------ | -| Alert rules | GET /api/v1/provisioning/alert-rules | Get all alert rules. | -| Alert rules | POST /api/v1/provisioning/alert-rules | Create a new alert rule. | +| Resource | URI | Methods | +| -------------------------------------------------------------- | ----------------------------------- | ---------------- | +| [Alert rules][alerting_http_alertrules] | /api/v1/provisioning/alert-rules | GET,POST,PUT,DEL | +| [Contact points][alerting_http_contactpoints] | /api/v1/provisioning/contact-points | GET,POST,PUT,DEL | +| [Notification policy tree][alerting_http_notificationpolicies] | /api/v1/provisioning/policies | GET,PUT,DEL | +| [Mute timings][alerting_http_mutetimings] | /api/v1/provisioning/mute-timings | GET,POST,PUT,DEL | +| [Templates][alerting_http_templates] | /api/v1/provisioning/templates | GET,PUT,DEL | -However, note these Alerting endpoints return a JSON format that is not compatible for provisioning through configuration files or Terraform, except the endpoints listed below. +However, note the standard endpoints return a JSON format that is not compatible for provisioning through configuration files or Terraform, except the `/export` endpoints listed below. ### Export API endpoints @@ -157,6 +160,22 @@ These endpoints accept a `download` parameter to download a file containing the {{% docs/reference %}} + +[alerting_http_alertrules]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning#alert-rules" +[alerting_http_alertrules]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/set-up/provision-alerting-resources/http-api-provisioning#alert-rules" + +[alerting_http_contactpoints]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning#contact-points" +[alerting_http_contactpoints]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/set-up/provision-alerting-resources/http-api-provisioning#contact-points" + +[alerting_http_notificationpolicies]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning#notification-policies" +[alerting_http_notificationpolicies]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/set-up/provision-alerting-resources/http-api-provisioning#notification-policies" + +[alerting_http_mutetimings]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning#mute-timings" +[alerting_http_mutetimings]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/set-up/provision-alerting-resources/http-api-provisioning#mute-timings" + +[alerting_http_templates]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/http-api-provisioning#templates" +[alerting_http_templates]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/set-up/provision-alerting-resources/http-api-provisioning#templates" + [alerting_tf_provisioning]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/terraform-provisioning" [alerting_tf_provisioning]: "/docs/grafana-cloud/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/terraform-provisioning" From b30b93df2cc87191b68d6d008c985e116022ec3b Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 7 Mar 2024 16:23:27 +0000 Subject: [PATCH 052/138] [v10.4.x] Update angular-plugins.md (#83664) Update angular-plugins.md (#83635) * Update angular-plugins.md Removes advice which only worked in `dev` instances. * Update angular-plugins.md Co-authored-by: Joseph Perez <45749060+josmperez@users.noreply.github.com> --------- Co-authored-by: Joseph Perez <45749060+josmperez@users.noreply.github.com> (cherry picked from commit 10721bfcd966176ecaf04127db983fa148d00881) Co-authored-by: David Harris --- docs/sources/developers/angular_deprecation/angular-plugins.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/developers/angular_deprecation/angular-plugins.md b/docs/sources/developers/angular_deprecation/angular-plugins.md index be830a5f7a68..e2c20b5aee55 100644 --- a/docs/sources/developers/angular_deprecation/angular-plugins.md +++ b/docs/sources/developers/angular_deprecation/angular-plugins.md @@ -48,7 +48,7 @@ Additionally, warning icons and messages will be displayed when browsing the cat ## Automatic migration of plugins -Certain legacy Grafana panel plugins automatically update to their React-based replacements when Angular support is disabled. This migration is usually available within the panel options, as shown in the screenshot below for World Map. Automatic migration can also be tested by appending `&__feature.autoMigrateOldPanels=true` to the dashboard URL in your browser. +Certain legacy Grafana panel plugins automatically update to their React-based replacements when Angular support is disabled. This migration is usually available within the panel options, as shown in the screenshot below for World Map. Automatic migration can be triggered by setting the feature toggle `autoMigrateOldPanels` to `true`. Automatic migration is supported for the plugins shown in the following table. Each of the target plugins are included in Grafana as Core plugins which don't require installation. From 595d967d6085ef71dc6d3def97f568598c8f3ce6 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 7 Mar 2024 16:41:51 +0000 Subject: [PATCH 053/138] [v10.4.x] Chore: Bump docker image versions (#84065) * Chore: Bump docker image versions (#84033) Bump docker image versions (cherry picked from commit 0236053f708e70dd8a7b0040516e2b3b862b7f77) * Add missing dependencies --------- Co-authored-by: Andreas Christou --- Dockerfile | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5c4d3d032fd9..5c1564966b45 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,9 @@ # syntax=docker/dockerfile:1 -ARG BASE_IMAGE=alpine:3.18.5 -ARG JS_IMAGE=node:20-alpine3.18 +ARG BASE_IMAGE=alpine:3.19.1 +ARG JS_IMAGE=node:20-alpine ARG JS_PLATFORM=linux/amd64 -ARG GO_IMAGE=golang:1.21.8-alpine3.18 +ARG GO_IMAGE=golang:1.21.8-alpine ARG GO_SRC=go-builder ARG JS_SRC=js-builder @@ -20,6 +20,8 @@ COPY packages packages COPY plugins-bundled plugins-bundled COPY public public +RUN apk add --no-cache make build-base python3 + RUN yarn install --immutable COPY tsconfig.json .eslintrc .editorconfig .browserslistrc .prettierrc.js ./ From 980352f0738677cd1b5647f8d713545342f272e5 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 7 Mar 2024 13:51:08 -0500 Subject: [PATCH 054/138] [v10.4.x] Embed two visualization videos from the Grafana for Beginners series (#84088) Embed two visualization videos from the Grafana for Beginners series (#83928) * Embed two visualization videos from Grafana for Beginners series * Implementing Isabel's recommendation on second video placement. * edited introductory sentence to the second video. * Added line between text and video --------- Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> (cherry picked from commit a15e48052f49cee0be0e8432d1ea3b4ce0310099) Co-authored-by: Lisa <60980933+LisaHJung@users.noreply.github.com> --- docs/sources/panels-visualizations/visualizations/_index.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/sources/panels-visualizations/visualizations/_index.md b/docs/sources/panels-visualizations/visualizations/_index.md index 6e17cc7c64df..b5c26e0f79ff 100644 --- a/docs/sources/panels-visualizations/visualizations/_index.md +++ b/docs/sources/panels-visualizations/visualizations/_index.md @@ -20,6 +20,8 @@ weight: 10 Grafana offers a variety of visualizations to support different use cases. This section of the documentation highlights the built-in visualizations, their options and typical usage. +{{< youtube id="JwF6FgeotaU" >}} + {{% admonition type="note" %}} If you are unsure which visualization to pick, Grafana can provide visualization suggestions based on the panel query. When you select a visualization, Grafana will show a preview with that visualization applied. {{% /admonition %}} @@ -51,6 +53,10 @@ If you are unsure which visualization to pick, Grafana can provide visualization - [Text][] can show markdown and html. - [News][] can show RSS feeds. +The following video shows you how to create gauge, time series line graph, stats, logs, and node graph visualizations: + +{{< youtube id="yNRnLyVntUw" >}} + ## Get more You can add more visualization types by installing panel [panel plugins](https://grafana.com/grafana/plugins/?type=panel). From 7f48c3168bc07b23f5fff2fe025751f5733aedd9 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 7 Mar 2024 13:00:48 -0600 Subject: [PATCH 055/138] [v10.4.x] docs: adds alt text to images where missing (#84093) docs: adds alt text to images where missing (#84028) * adds alt text * makes prettier (cherry picked from commit 8c7090bc110be5b651d02894a050dd33f331a021) Co-authored-by: Christopher Moyer <35463610+chri2547@users.noreply.github.com> --- docs/sources/fundamentals/intro-histograms/index.md | 4 ++-- docs/sources/fundamentals/timeseries-dimensions/index.md | 2 +- docs/sources/fundamentals/timeseries/index.md | 2 +- .../configure-authentication/enhanced-ldap/index.md | 4 ++-- .../configure-authentication/ldap/index.md | 8 ++++---- .../configure-security/configure-team-sync.md | 5 +++-- 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/docs/sources/fundamentals/intro-histograms/index.md b/docs/sources/fundamentals/intro-histograms/index.md index 4b78139e3910..21b1c85e866b 100644 --- a/docs/sources/fundamentals/intro-histograms/index.md +++ b/docs/sources/fundamentals/intro-histograms/index.md @@ -32,7 +32,7 @@ and the bar height represents the frequency (such as count) of values that fell This _histogram_ shows the value distribution of a couple of time series. You can easily see that most values land between 240-300 with a peak between 260-280. -![](/static/img/docs/v43/heatmap_histogram.png) +![Histogram example](/static/img/docs/v43/heatmap_histogram.png) Here is an example showing height distribution of people. @@ -48,7 +48,7 @@ A _heatmap_ is like a histogram, but over time, where each time slice represents In this example, you can clearly see what values are more common and how they trend over time. -![](/static/img/docs/v43/heatmap_histogram_over_time.png) +![Heatmap example](/static/img/docs/v43/heatmap_histogram_over_time.png) For more information about heatmap visualization options, refer to [Heatmap][heatmap]. diff --git a/docs/sources/fundamentals/timeseries-dimensions/index.md b/docs/sources/fundamentals/timeseries-dimensions/index.md index b42fb1482d37..3e1e73d50227 100644 --- a/docs/sources/fundamentals/timeseries-dimensions/index.md +++ b/docs/sources/fundamentals/timeseries-dimensions/index.md @@ -29,7 +29,7 @@ In [Introduction to time series][time-series-databases], the concept of _labels_ With time series data, the data often contain more than a single series, and is a set of multiple time series. Many Grafana data sources support this type of data. -{{< figure src="/static/img/docs/example_graph_multi_dim.png" class="docs-image--no-shadow" max-width="850px" >}} +{{< figure src="/static/img/docs/example_graph_multi_dim.png" class="docs-image--no-shadow" max-width="850px" alt="Temperature by location" >}} The common case is issuing a single query for a measurement with one or more additional properties as dimensions. For example, querying a temperature measurement along with a location property. In this case, multiple series are returned back from that single query and each series has unique location as a dimension. diff --git a/docs/sources/fundamentals/timeseries/index.md b/docs/sources/fundamentals/timeseries/index.md index c08915ea2952..aaa0df85d3c9 100644 --- a/docs/sources/fundamentals/timeseries/index.md +++ b/docs/sources/fundamentals/timeseries/index.md @@ -32,7 +32,7 @@ Temperature data like this is one example of what we call a _time series_ — a Tables are useful when you want to identify individual measurements, but they make it difficult to see the big picture. A more common visualization for time series is the _graph_, which instead places each measurement along a time axis. Visual representations like the graph make it easier to discover patterns and features of the data that otherwise would be difficult to see. -{{< figure src="/static/img/docs/example_graph.png" class="docs-image--no-shadow" max-width="850px" >}} +{{< figure src="/static/img/docs/example_graph.png" class="docs-image--no-shadow" max-width="850px" alt="Temperature data displayed on dashboard" >}} Temperature data like the one in the example, is far from the only example of a time series. Other examples of time series are: diff --git a/docs/sources/setup-grafana/configure-security/configure-authentication/enhanced-ldap/index.md b/docs/sources/setup-grafana/configure-security/configure-authentication/enhanced-ldap/index.md index 02aea423bd06..fd02e51fcb85 100644 --- a/docs/sources/setup-grafana/configure-security/configure-authentication/enhanced-ldap/index.md +++ b/docs/sources/setup-grafana/configure-security/configure-authentication/enhanced-ldap/index.md @@ -30,11 +30,11 @@ The enhanced LDAP integration adds additional functionality on top of the [LDAP ## LDAP group synchronization for teams -{{< figure src="/static/img/docs/enterprise/team_members_ldap.png" class="docs-image--no-shadow docs-image--right" max-width= "600px" >}} - With enhanced LDAP integration, you can set up synchronization between LDAP groups and teams. This enables LDAP users that are members of certain LDAP groups to automatically be added or removed as members to certain teams in Grafana. +![LDAP group synchronization](/static/img/docs/enterprise/team_members_ldap.png) + Grafana keeps track of all synchronized users in teams, and you can see which users have been synchronized from LDAP in the team members list, see `LDAP` label in screenshot. This mechanism allows Grafana to remove an existing synchronized user from a team when its LDAP group membership changes. This mechanism also allows you to manually add a user as member of a team, and it will not be removed when the user signs in. This gives you flexibility to combine LDAP group memberships and Grafana team memberships. diff --git a/docs/sources/setup-grafana/configure-security/configure-authentication/ldap/index.md b/docs/sources/setup-grafana/configure-security/configure-authentication/ldap/index.md index 9e62c44a5b4d..eece776c8815 100644 --- a/docs/sources/setup-grafana/configure-security/configure-authentication/ldap/index.md +++ b/docs/sources/setup-grafana/configure-security/configure-authentication/ldap/index.md @@ -151,19 +151,19 @@ Grafana has an LDAP debug view built-in which allows you to test your LDAP confi Within this view, you'll be able to see which LDAP servers are currently reachable and test your current configuration. -{{< figure src="/static/img/docs/ldap_debug.png" class="docs-image--no-shadow" max-width="600px" >}} +{{< figure src="/static/img/docs/ldap_debug.png" class="docs-image--no-shadow" max-width="600px" alt="LDAP testing" >}} To use the debug view, complete the following steps: 1. Type the username of a user that exists within any of your LDAP server(s) 1. Then, press "Run" -1. If the user is found within any of your LDAP instances, the mapping information is displayed +1. If the user is found within any of your LDAP instances, the mapping information is displayed. -{{< figure src="/static/img/docs/ldap_debug_mapping_testing.png" class="docs-image--no-shadow" max-width="600px" >}} +{{< figure src="/static/img/docs/ldap_debug_mapping_testing.png" class="docs-image--no-shadow" max-width="600px" alt="LDAP mapping displayed" >}} [Grafana Enterprise]({{< relref "../../../../introduction/grafana-enterprise" >}}) users with [enhanced LDAP integration]({{< relref "../enhanced-ldap" >}}) enabled can also see sync status in the debug view. This requires the `ldap.status:read` permission. -{{< figure src="/static/img/docs/ldap_sync_debug.png" class="docs-image--no-shadow" max-width="600px" >}} +{{< figure src="/static/img/docs/ldap_sync_debug.png" class="docs-image--no-shadow" max-width="600px" alt="LDAP sync status" >}} ### Bind and bind password diff --git a/docs/sources/setup-grafana/configure-security/configure-team-sync.md b/docs/sources/setup-grafana/configure-security/configure-team-sync.md index f7410d14c711..07f251ad25cb 100644 --- a/docs/sources/setup-grafana/configure-security/configure-team-sync.md +++ b/docs/sources/setup-grafana/configure-security/configure-team-sync.md @@ -40,11 +40,12 @@ This mechanism allows Grafana to remove an existing synchronized user from a tea If you have already grouped some users into a team, then you can synchronize that team with an external group. -{{< figure src="/static/img/docs/enterprise/team_add_external_group.png" class="docs-image--no-shadow docs-image--right" max-width= "600px" >}} - 1. In Grafana, navigate to **Administration > Users and access > Teams**. 1. Select a team. 1. Go to the External group sync tab, and click **Add group**. + + ![External group sync](/static/img/docs/enterprise/team_add_external_group.png) + 1. Insert the value of the group you want to sync with. This becomes the Grafana `GroupID`. Examples: From 32e7839cb8f040707066376b9c8b2e81f63ade62 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Mon, 11 Mar 2024 17:10:52 +0200 Subject: [PATCH 056/138] [v10.4.x] Dashboard: Fix issue where out-of-view shared query panels caused blank dependent panels (#84197) Dashboard: Fix issue where out-of-view shared query panels caused blank dependent panels (#83966) (cherry picked from commit d8b8a2c2b0c4e56739ae4d77f70b014d7e2fb690) Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com> --- .../dashgrid/PanelStateWrapper.test.tsx | 2 ++ .../features/dashboard/state/DashboardModel.ts | 17 ++++++++++++++--- .../app/features/dashboard/state/PanelModel.ts | 2 +- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/public/app/features/dashboard/dashgrid/PanelStateWrapper.test.tsx b/public/app/features/dashboard/dashgrid/PanelStateWrapper.test.tsx index 8b6be6c4b987..c46d74b3728d 100644 --- a/public/app/features/dashboard/dashgrid/PanelStateWrapper.test.tsx +++ b/public/app/features/dashboard/dashgrid/PanelStateWrapper.test.tsx @@ -74,6 +74,8 @@ function setupTestContext(options: Partial) { ); + // Needed so mocks work + props.panel.refreshWhenInView = false; return { rerender, props, subject, store }; } diff --git a/public/app/features/dashboard/state/DashboardModel.ts b/public/app/features/dashboard/state/DashboardModel.ts index b4b5d3376ad0..4e970f3d9d45 100644 --- a/public/app/features/dashboard/state/DashboardModel.ts +++ b/public/app/features/dashboard/state/DashboardModel.ts @@ -440,11 +440,22 @@ export class DashboardModel implements TimeModel { return; } - for (const panel of this.panels) { - if (!this.otherPanelInFullscreen(panel) && (event.refreshAll || event.panelIds.includes(panel.id))) { - panel.refresh(); + const panelsToRefresh = this.panels.filter( + (panel) => !this.otherPanelInFullscreen(panel) && (event.refreshAll || event.panelIds.includes(panel.id)) + ); + + // We have to mark every panel as refreshWhenInView /before/ we actually refresh any + // in case there is a shared query, as otherwise that might refresh before the source panel is + // marked for refresh, preventing the panel from updating + if (!this.isSnapshot()) { + for (const panel of panelsToRefresh) { + panel.refreshWhenInView = true; } } + + for (const panel of panelsToRefresh) { + panel.refresh(); + } } render() { diff --git a/public/app/features/dashboard/state/PanelModel.ts b/public/app/features/dashboard/state/PanelModel.ts index fcf1307a2844..73c802beac3c 100644 --- a/public/app/features/dashboard/state/PanelModel.ts +++ b/public/app/features/dashboard/state/PanelModel.ts @@ -203,7 +203,7 @@ export class PanelModel implements DataConfigSource, IPanelModel { cacheTimeout?: string | null; queryCachingTTL?: number | null; isNew?: boolean; - refreshWhenInView = false; + refreshWhenInView = true; cachedPluginOptions: Record = {}; legend?: { show: boolean; sort?: string; sortDesc?: boolean }; From 5d46a9ca18cab207f6d2d9989bc26f3adc46f412 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Mon, 11 Mar 2024 12:56:43 -0400 Subject: [PATCH 057/138] [v10.4.x] Docs: corrected data source management information (#84209) corrected the minor details (#84046) * corrected the minor details Making minor changes after the PR merged on Data sources and Data source administration. https://github.com/grafana/grafana/pull/83712 * Apply suggestions from code review Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> * Update docs/sources/panels-visualizations/_index.md Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> * Ran prettier --------- Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> Co-authored-by: Isabel Matwawana (cherry picked from commit cfc7ea92daf4b05c2ba84c5a81fb256938271b08) Co-authored-by: Usman Ahmad --- docs/sources/panels-visualizations/_index.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/sources/panels-visualizations/_index.md b/docs/sources/panels-visualizations/_index.md index af1f7843323e..dbb1f5d71c73 100644 --- a/docs/sources/panels-visualizations/_index.md +++ b/docs/sources/panels-visualizations/_index.md @@ -30,8 +30,13 @@ Panels can be dragged, dropped, and resized to rearrange them on the dashboard. Before you add a panel, ensure that you have configured a data source. -- For more information about adding and managing data sources as an administrator, refer to [Data source management][]. -- For details about using specific data sources, refer to [Data sources][]. +- For details about using data sources, refer to [Data sources][]. + +- For more information about managing data sources as an administrator, refer to [Data source management][]. + + {{% admonition type="note" %}} + [Data source management](https://grafana.com/docs/grafana//administration/data-source-management/) is only available in [Grafana Enterprise](https://grafana.com/docs/grafana//introduction/grafana-enterprise/) and [Grafana Cloud](https://grafana.com/docs/grafana-cloud/). + {{% /admonition %}} This section includes the following sub topics: From ab89de7e852d8a9bd03c3c6a1e9fda2d638de788 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Mon, 11 Mar 2024 14:21:18 -0400 Subject: [PATCH 058/138] [v10.4.x] Docs: fix broken link (#84220) Docs: fix broken link (#84103) * Fixed broken link * Removed trailing slash * Ran prettier (cherry picked from commit ffd0bdafe4848ce043460aa9e3b1da381dde6550) Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --- docs/sources/developers/angular_deprecation/angular-plugins.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/developers/angular_deprecation/angular-plugins.md b/docs/sources/developers/angular_deprecation/angular-plugins.md index e2c20b5aee55..377a7a61b8e2 100644 --- a/docs/sources/developers/angular_deprecation/angular-plugins.md +++ b/docs/sources/developers/angular_deprecation/angular-plugins.md @@ -111,7 +111,7 @@ This table lists plugins which we have detected as having a dependency on Angula | blackmirror1-statusbygroup-panel | Status By Group Panel | Migrate - Browse included visualizations and plugins catalog for potential alternatives. | | novalabs-annotations-panel | Annotation Panel | Migrate - Browse included visualizations and plugins catalog for potential alternatives. | | jasonlashua-prtg-datasource | PRTG | Migrate - Browse included data sources and plugins catalog for potential alternatives. | -| ryantxu-annolist-panel | Annotation List | Migrate - Consider [annotations list]({{< relref "../../panels-visualizations/visualizations/annotation-list" >}}) (core). | +| ryantxu-annolist-panel | Annotation List | Migrate - Consider [annotations list]({{< relref "../../panels-visualizations/visualizations/annotations" >}}) (core). | | cloudflare-app | Cloudflare Grafana App | Migrate - Consider using the [Cloudflare Dashboard](https://dash.cloudflare.com/?to=/:account/:zone/analytics/dns) or [DNS Analytics API](https://developers.cloudflare.com/api/operations/dns-analytics-table). | | smartmakers-trafficlight-panel | TrafficLight | Migrate - Consider [Traffic Light](https://grafana.com/grafana/plugins/heywesty-trafficlight-panel/) as a potential alternative. | | zuburqan-parity-report-panel | Parity Report | Migrate - Browse included visualizations and plugins catalog for potential alternatives. | From 1b43fc90d4e90fc0d14f85190f1875d4efc490e7 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Mon, 11 Mar 2024 18:22:21 +0000 Subject: [PATCH 059/138] [v10.4.x] Docs: add missing alt text (#84216) Docs: add missing alt text (#84102) Added missing alt text (cherry picked from commit e2cc5e57e59530cf0d7e0f8a978bc434c728b3a4) Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --- docs/sources/whatsnew/whats-new-in-v10-3.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/whatsnew/whats-new-in-v10-3.md b/docs/sources/whatsnew/whats-new-in-v10-3.md index 8085ea549f92..e0922b0a0518 100644 --- a/docs/sources/whatsnew/whats-new-in-v10-3.md +++ b/docs/sources/whatsnew/whats-new-in-v10-3.md @@ -365,7 +365,7 @@ Derived fields or data links are a concept to add correlations based on your log The following example would add the derived field `traceID regex` based on a regular expression and another `app label` field based on the `app` label. -{{< figure src="/media/docs/grafana/2024-01-05_loki-derived-fields.png" >}} +{{< figure src="/media/docs/grafana/2024-01-05_loki-derived-fields.png" alt="Derived fields added based on a regular expression and an app label">}} ### InfluxDB native SQL support From e430baa819cb3e3a9c2221c5c5b0907e02965b55 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Mon, 11 Mar 2024 21:20:46 +0200 Subject: [PATCH 060/138] [v10.4.x] docs: update angular deprecation notice (#84228) docs: update angular deprecation notice (#84227) update docs (cherry picked from commit efbcd53119efffd6e9509845f1d54b5369fcac1e) Co-authored-by: David Harris --- docs/sources/developers/angular_deprecation/_index.md | 8 +++++--- .../developers/angular_deprecation/angular-plugins.md | 1 - 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/sources/developers/angular_deprecation/_index.md b/docs/sources/developers/angular_deprecation/_index.md index 89b3037c1ae5..6799f2eebd59 100644 --- a/docs/sources/developers/angular_deprecation/_index.md +++ b/docs/sources/developers/angular_deprecation/_index.md @@ -22,17 +22,19 @@ AngularJS is an old frontend framework whose active development stopped many yea ## When will Angular plugins stop working? -Our goal is to transfer all the remaining Angular code to the core of Grafana before Grafana 10 is released in Summer 2023. Once this is done, the option "[angular_support_enabled](https://github.com/grafana/grafana/blob/d61bcdf4ca5e69489e0067c56fbe7f0bfdf84ee4/conf/defaults.ini#L362)" will be disabled by default for new Grafana Cloud users, resulting in the inability to use Angular plugins. In case you still rely on AngularJS-based plugins developed internally or by the community, you will need to enable this option to continue using them. Following the release of Grafana 10 we will be migrating Grafana Cloud users where possible and disabling Angular support when appropriate, we will also be introducing new features to help all users identify how they are impacted and to warn of the use of deprecated plugins within the Grafana UI. +In Grafana 11, which will be released in preview in April 2024 and generally available in May, we will change the default behavior of the [angular_support_enabled](https://github.com/grafana/grafana/blob/d61bcdf4ca5e69489e0067c56fbe7f0bfdf84ee4/conf/defaults.ini#L362) configuration parameter to turn off support for AngularJS based plugins. In case you still rely on [AngularJS-based plugins]({{< relref "./angular-plugins/" >}}) developed internally or by the community, you will need to enable this option to continue using them. + +New Grafana Cloud users will be unable to request for support to be added to their instance. ## When will we remove Angular support completely? -Our plan is to completely remove support for Angular plugins in version 11, which will be released in 2024. This means that all plugins that depend on Angular will stop working and the temporary option introduced in version 10 to enable Angular will be removed. +Our current plan is to completely remove any remaining support for Angular plugins in version 12. Including the removal of the [angular_support_enabled](https://github.com/grafana/grafana/blob/d61bcdf4ca5e69489e0067c56fbe7f0bfdf84ee4/conf/defaults.ini#L362) configuration parameter. ## How do I migrate an Angular plugin to React? Depending on if it’s a data source plugin, panel plugin, or app plugin the process will differ. -For panels, the rendering logic could in some cases be easily preserved but all options need to be redone to use the declarative options framework. For data source plugins the query editor and config options will likely need a total rewrite. +For panels, the rendering logic could in some cases be easily preserved, but all options need to be redone to use the declarative options framework. For data source plugins the query editor and config options will likely need a total rewrite. ## How do I encourage a community plugin to migrate? diff --git a/docs/sources/developers/angular_deprecation/angular-plugins.md b/docs/sources/developers/angular_deprecation/angular-plugins.md index 377a7a61b8e2..d565cb5a2e19 100644 --- a/docs/sources/developers/angular_deprecation/angular-plugins.md +++ b/docs/sources/developers/angular_deprecation/angular-plugins.md @@ -201,7 +201,6 @@ This table lists plugins which we have detected as having a dependency on Angula | stagemonitor-elasticsearch-app | stagemonitor Elasticsearch | Migrate - Browse included data sources and plugins catalog for potential alternatives. | | tdengine-datasource | TDengine Datasource | Update - Note the minimum version for React is 3.3.0. We recommend the latest. | | vertica-grafana-datasource | Vertica | Update - Note the minimum version for React is 2.0.0. We recommend the latest. | -| vonage-status-panel | Status Panel | Wait - Updated version may become available, or browse included visualizations and plugins catalog for potential alternatives. | | voxter-app | Voxter VoIP Platform Metrics | Migrate - Browse included data sources and plugins catalog for potential alternatives. | | graph | Graph (old) | Migrate - Note that this is replaced by [Time Series]({{< relref "../../panels-visualizations/visualizations/time-series" >}}) (core) - This plugin should migrate when Angular is disabled. Also consider Bar Chart or Histogram if appropriate. | | table-old | Table (old) | Migrate - Note that this is replaced by [Table]({{< relref "../../panels-visualizations/visualizations/table" >}}) (core) - This plugin should migrate when AngularJS is disabled. | From 9bbd9cf4caf9f728195a11edc9f4edea87703fbd Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Tue, 12 Mar 2024 12:55:30 +0200 Subject: [PATCH 061/138] [v10.4.x] Postgres: Allow disabling SNI on SSL-enabled connections (#84249) Postgres: Allow disabling SNI on SSL-enabled connections (#83892) * Postgres: Allow disabling SNI on SSL-enabled connections * Update docs/sources/setup-grafana/configure-grafana/_index.md Co-authored-by: Christopher Moyer <35463610+chri2547@users.noreply.github.com> --------- Co-authored-by: Christopher Moyer <35463610+chri2547@users.noreply.github.com> (cherry picked from commit 22d8258e48a870cdccbb53542ecf7d0d511b68c8) Co-authored-by: Sofia Papagiannaki <1632407+papagian@users.noreply.github.com> --- conf/defaults.ini | 3 + conf/sample.ini | 3 + .../setup-grafana/configure-grafana/_index.md | 4 + pkg/services/sqlstore/database_config.go | 6 ++ pkg/services/sqlstore/database_config_test.go | 76 +++++++++++++++++++ 5 files changed, 92 insertions(+) diff --git a/conf/defaults.ini b/conf/defaults.ini index 67bc7e72e43b..047a59f859cf 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -134,6 +134,9 @@ log_queries = # For "mysql", use either "true", "false", or "skip-verify". ssl_mode = disable +# For "postregs", use either "1" to enable or "0" to disable SNI +ssl_sni = + # Database drivers may support different transaction isolation levels. # Currently, only "mysql" driver supports isolation levels. # If the value is empty - driver's default isolation level is applied. diff --git a/conf/sample.ini b/conf/sample.ini index e60d15e9bdf2..3f3ed68e7cf6 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -124,6 +124,9 @@ # For "mysql", use either "true", "false", or "skip-verify". ;ssl_mode = disable +# For "postregs", use either "1" to enable or "0" to disable SNI +;ssl_sni = + # Database drivers may support different transaction isolation levels. # Currently, only "mysql" driver supports isolation levels. # If the value is empty - driver's default isolation level is applied. diff --git a/docs/sources/setup-grafana/configure-grafana/_index.md b/docs/sources/setup-grafana/configure-grafana/_index.md index 8309031db5ad..ebabb5a122ee 100644 --- a/docs/sources/setup-grafana/configure-grafana/_index.md +++ b/docs/sources/setup-grafana/configure-grafana/_index.md @@ -388,6 +388,10 @@ Set to `true` to log the sql calls and execution times. For Postgres, use use any [valid libpq `sslmode`](https://www.postgresql.org/docs/current/libpq-ssl.html#LIBPQ-SSL-SSLMODE-STATEMENTS), e.g.`disable`, `require`, `verify-full`, etc. For MySQL, use either `true`, `false`, or `skip-verify`. +### ssl_sni + +For Postgres, set to `0` to disable [Server Name Indication](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-SSLSNI). This is enabled by default on SSL-enabled connections. + ### isolation_level Only the MySQL driver supports isolation levels in Grafana. In case the value is empty, the driver's default isolation level is applied. Available options are "READ-UNCOMMITTED", "READ-COMMITTED", "REPEATABLE-READ" or "SERIALIZABLE". diff --git a/pkg/services/sqlstore/database_config.go b/pkg/services/sqlstore/database_config.go index 1b627d0515e2..f1ada93097ea 100644 --- a/pkg/services/sqlstore/database_config.go +++ b/pkg/services/sqlstore/database_config.go @@ -25,6 +25,7 @@ type DatabaseConfig struct { Pwd string Path string SslMode string + SSLSNI string CaCertPath string ClientKeyPath string ClientCertPath string @@ -101,6 +102,7 @@ func (dbCfg *DatabaseConfig) readConfig(cfg *setting.Cfg) error { dbCfg.ConnMaxLifetime = sec.Key("conn_max_lifetime").MustInt(14400) dbCfg.SslMode = sec.Key("ssl_mode").String() + dbCfg.SSLSNI = sec.Key("ssl_sni").String() dbCfg.CaCertPath = sec.Key("ca_cert_path").String() dbCfg.ClientKeyPath = sec.Key("client_key_path").String() dbCfg.ClientCertPath = sec.Key("client_cert_path").String() @@ -168,12 +170,16 @@ func (dbCfg *DatabaseConfig) buildConnectionString(cfg *setting.Cfg, features fe args := []any{dbCfg.User, addr.Host, addr.Port, dbCfg.Name, dbCfg.SslMode, dbCfg.ClientCertPath, dbCfg.ClientKeyPath, dbCfg.CaCertPath} + for i, arg := range args { if arg == "" { args[i] = "''" } } cnnstr = fmt.Sprintf("user=%s host=%s port=%s dbname=%s sslmode=%s sslcert=%s sslkey=%s sslrootcert=%s", args...) + if dbCfg.SSLSNI != "" { + cnnstr += fmt.Sprintf(" sslsni=%s", dbCfg.SSLSNI) + } if dbCfg.Pwd != "" { cnnstr += fmt.Sprintf(" password=%s", dbCfg.Pwd) } diff --git a/pkg/services/sqlstore/database_config_test.go b/pkg/services/sqlstore/database_config_test.go index 942cdc235615..cd13fc3b8faf 100644 --- a/pkg/services/sqlstore/database_config_test.go +++ b/pkg/services/sqlstore/database_config_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/require" "github.com/grafana/grafana/pkg/services/featuremgmt" + "github.com/grafana/grafana/pkg/services/sqlstore/migrator" "github.com/grafana/grafana/pkg/setting" ) @@ -145,3 +146,78 @@ func makeDatabaseTestConfig(t *testing.T, tc databaseConfigTest) *setting.Cfg { return cfg } +func TestBuildConnectionStringPostgres(t *testing.T) { + testCases := []struct { + name string + dbCfg *DatabaseConfig + expectedConnStr string + }{ + { + name: "Postgres with sslmode disable", + dbCfg: &DatabaseConfig{ + Type: migrator.Postgres, + User: "grafana", + Pwd: "password", + Host: "127.0.0.1:5432", + Name: "grafana_test", + SslMode: "disable", + }, + expectedConnStr: "user=grafana host=127.0.0.1 port=5432 dbname=grafana_test sslmode=disable sslcert='' sslkey='' sslrootcert='' password=password", + }, + { + name: "Postgres with sslmode verify-ca", + dbCfg: &DatabaseConfig{ + Type: migrator.Postgres, + User: "grafana", + Pwd: "password", + Host: "127.0.0.1:5432", + Name: "grafana_test", + SslMode: "verify-ca", + CaCertPath: "/path/to/ca_cert", + ClientKeyPath: "/path/to/client_key", + ClientCertPath: "/path/to/client_cert", + }, + expectedConnStr: "user=grafana host=127.0.0.1 port=5432 dbname=grafana_test sslmode=verify-ca sslcert=/path/to/client_cert sslkey=/path/to/client_key sslrootcert=/path/to/ca_cert password=password", + }, + { + name: "Postgres with sslmode verify-ca without SNI", + dbCfg: &DatabaseConfig{ + Type: migrator.Postgres, + User: "grafana", + Pwd: "password", + Host: "127.0.0.1:5432", + Name: "grafana_test", + SslMode: "verify-ca", + CaCertPath: "/path/to/ca_cert", + ClientKeyPath: "/path/to/client_key", + ClientCertPath: "/path/to/client_cert", + SSLSNI: "0", + }, + expectedConnStr: "user=grafana host=127.0.0.1 port=5432 dbname=grafana_test sslmode=verify-ca sslcert=/path/to/client_cert sslkey=/path/to/client_key sslrootcert=/path/to/ca_cert sslsni=0 password=password", + }, + { + name: "Postgres with sslmode verify-ca with SNI", + dbCfg: &DatabaseConfig{ + Type: migrator.Postgres, + User: "grafana", + Pwd: "password", + Host: "127.0.0.1:5432", + Name: "grafana_test", + SslMode: "verify-ca", + CaCertPath: "/path/to/ca_cert", + ClientKeyPath: "/path/to/client_key", + ClientCertPath: "/path/to/client_cert", + SSLSNI: "1", + }, + expectedConnStr: "user=grafana host=127.0.0.1 port=5432 dbname=grafana_test sslmode=verify-ca sslcert=/path/to/client_cert sslkey=/path/to/client_key sslrootcert=/path/to/ca_cert sslsni=1 password=password", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.dbCfg.buildConnectionString(&setting.Cfg{}, nil) + assert.NoError(t, err) + assert.Equal(t, tc.expectedConnStr, tc.dbCfg.ConnectionString) + }) + } +} From 0a0e9f70cd1a36afce8623f7ae66a601047cc88b Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Tue, 12 Mar 2024 12:46:58 +0100 Subject: [PATCH 062/138] [v10.4.x] OrgUsers: Refactor change `LastSeenAtAge` from '10 years' to 'Never' (#84260) OrgUsers: Refactor change `LastSeenAtAge` from '10 years' to 'Never' (#84247) * refactor: change lastseenatage to Never * removed unncessecary fragments (cherry picked from commit fbfaf8e003e6f07de698387dca8ce0d509e2c4dc) Co-authored-by: Eric Leijonmarck --- public/app/features/admin/Users/OrgUsersTable.tsx | 5 ++++- public/app/features/admin/Users/UsersTable.tsx | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/public/app/features/admin/Users/OrgUsersTable.tsx b/public/app/features/admin/Users/OrgUsersTable.tsx index 99f0a9ea40c7..55918b8ce958 100644 --- a/public/app/features/admin/Users/OrgUsersTable.tsx +++ b/public/app/features/admin/Users/OrgUsersTable.tsx @@ -15,6 +15,7 @@ import { Pagination, Stack, Tag, + Text, Tooltip, } from '@grafana/ui'; import { UserRolePicker } from 'app/core/components/RolePicker/UserRolePicker'; @@ -107,7 +108,9 @@ export const OrgUsersTable = ({ { id: 'lastSeenAtAge', header: 'Last active', - cell: ({ cell: { value } }: Cell<'lastSeenAtAge'>) => value, + cell: ({ cell: { value } }: Cell<'lastSeenAtAge'>) => { + return <>{value && value === '10 years' ? Never : value}; + }, sortType: (a, b) => new Date(a.original.lastSeenAt).getTime() - new Date(b.original.lastSeenAt).getTime(), }, { diff --git a/public/app/features/admin/Users/UsersTable.tsx b/public/app/features/admin/Users/UsersTable.tsx index fd7cdbb68139..18ce295ce75f 100644 --- a/public/app/features/admin/Users/UsersTable.tsx +++ b/public/app/features/admin/Users/UsersTable.tsx @@ -117,7 +117,7 @@ export const UsersTable = ({ iconName: 'question-circle', }, cell: ({ cell: { value } }: Cell<'lastSeenAtAge'>) => { - return <>{value && <>{value === '10 years' ? Never : value}}; + return <>{value && value === '10 years' ? Never : value}; }, sortType: (a, b) => new Date(a.original.lastSeenAt!).getTime() - new Date(b.original.lastSeenAt!).getTime(), }, From 1d582410abc54dba3f838a9e3b77be68591fa82a Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Tue, 12 Mar 2024 15:37:40 +0200 Subject: [PATCH 063/138] [v10.4.x] Users: Add back check for undefined / null for value for `lastSeenAtAge` in table view (#84285) Users: Add back check for undefined / null for value for `lastSeenAtAge` in table view (#84265) bug: add check for undefined / null for value (cherry picked from commit 0cb9f2bb8d7602547a4f4c1e0350612cfaf3afcf) Co-authored-by: Eric Leijonmarck --- public/app/features/admin/Users/OrgUsersTable.tsx | 2 +- public/app/features/admin/Users/UsersTable.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/app/features/admin/Users/OrgUsersTable.tsx b/public/app/features/admin/Users/OrgUsersTable.tsx index 55918b8ce958..135413ae534b 100644 --- a/public/app/features/admin/Users/OrgUsersTable.tsx +++ b/public/app/features/admin/Users/OrgUsersTable.tsx @@ -109,7 +109,7 @@ export const OrgUsersTable = ({ id: 'lastSeenAtAge', header: 'Last active', cell: ({ cell: { value } }: Cell<'lastSeenAtAge'>) => { - return <>{value && value === '10 years' ? Never : value}; + return <>{value && <>{value === '10 years' ? Never : value}}; }, sortType: (a, b) => new Date(a.original.lastSeenAt).getTime() - new Date(b.original.lastSeenAt).getTime(), }, diff --git a/public/app/features/admin/Users/UsersTable.tsx b/public/app/features/admin/Users/UsersTable.tsx index 18ce295ce75f..fd7cdbb68139 100644 --- a/public/app/features/admin/Users/UsersTable.tsx +++ b/public/app/features/admin/Users/UsersTable.tsx @@ -117,7 +117,7 @@ export const UsersTable = ({ iconName: 'question-circle', }, cell: ({ cell: { value } }: Cell<'lastSeenAtAge'>) => { - return <>{value && value === '10 years' ? Never : value}; + return <>{value && <>{value === '10 years' ? Never : value}}; }, sortType: (a, b) => new Date(a.original.lastSeenAt!).getTime() - new Date(b.original.lastSeenAt!).getTime(), }, From 0b50a9bfe3e90d5020e99370e28f94542abcfe15 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Tue, 12 Mar 2024 13:46:29 -0400 Subject: [PATCH 064/138] [v10.4.x] Docs: add table visualization for logs entry to what's new (#84316) Docs: add table visualization for logs entry to what's new (#84313) Added new entry (cherry picked from commit 9da48a8a48b1d12e73dd04bf50716a221c24c0b8) Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --- docs/sources/whatsnew/whats-new-in-v10-4.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/sources/whatsnew/whats-new-in-v10-4.md b/docs/sources/whatsnew/whats-new-in-v10-4.md index 2c4c28d6e5f0..9eb850639589 100644 --- a/docs/sources/whatsnew/whats-new-in-v10-4.md +++ b/docs/sources/whatsnew/whats-new-in-v10-4.md @@ -264,3 +264,19 @@ You can find more information and how to configure the plugin [on Github](https: {{< figure src="/media/images/dashboards/surrealdb-dashboard-example.png" >}} [Documentation](https://grafana.com/grafana/plugins/grafana-surrealdb-datasource/) + +## Table Visualization for Logs + + + +_Generally available in all editions of Grafana_ + +The table visualization for logs, announced in public preview for Grafana 10.3, is generally available in Cloud (all editions) and with Grafana 10.4. + +New to the table visualization with 10.4: + +- the ability to sort columns +- data type autodetection of fields +- autodetection and clean formatting of json fields + +Try it out today! From e86530166524253607abeac784f1a04fbb61e71f Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Tue, 12 Mar 2024 15:45:55 -0400 Subject: [PATCH 065/138] [v10.4.x] Docs: clarify query formatting for time range variable queries (#84325) Docs: clarify query formatting for time range variable queries (#84074) * Added time range variable guidance * Reworded * Applied review suggestion (cherry picked from commit e552e21221d9e958b1f9ff6bb162fe764bd81d8d) Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --- .../panels-visualizations/configure-data-links/index.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/sources/panels-visualizations/configure-data-links/index.md b/docs/sources/panels-visualizations/configure-data-links/index.md index b2fda39c1ac2..9996e398e38d 100644 --- a/docs/sources/panels-visualizations/configure-data-links/index.md +++ b/docs/sources/panels-visualizations/configure-data-links/index.md @@ -76,6 +76,8 @@ These variables allow you to include the current time range in the data link URL | `__from` | For more information, refer to [Global variables][]. | | `__to` | For more information, refer to [Global variables][]. | +When you create data links using time range variables like `__url_time_range` in the URL, you have to form the query parameter syntax yourself; that is, you must format the URL by appending query parameters using the question mark (`?`) and ampersand (`&`) syntax. These characters aren't automatically generated. + ### Series variables Series-specific variables are available under `__series` namespace: @@ -107,6 +109,8 @@ Value-specific variables are available under `__value` namespace: Using value-specific variables in data links can show different results depending on the set option of Tooltip mode. +When you create data links using time range variables like `__value.time` in the URL, you have to form the query parameter syntax yourself; that is, you must add the question mark (`?`) and ampersand (`&`). These characters aren't automatically generated. + ### Data variables To access values and labels from other fields use: From 27107326d57852352531e73784c89d90279db3a0 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 13 Mar 2024 13:51:49 +0200 Subject: [PATCH 066/138] [v10.4.x] SSO: fix mergeSettings() in case the DB contains empty URLs (#84344) SSO: fix mergeSettings() in case the DB contains empty URLs (#84290) * fix mergeSettings() in case the db contains empty strings * use correct github urls in test * overwrite only urls * update comment for mergeSettings() (cherry picked from commit 2acd48d1c2f86c584d60871cd59d36fd4db95746) Co-authored-by: Mihai Doarna --- .../ssosettings/ssosettingsimpl/service.go | 16 +++++++++ .../ssosettingsimpl/service_test.go | 36 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/pkg/services/ssosettings/ssosettingsimpl/service.go b/pkg/services/ssosettings/ssosettingsimpl/service.go index 9466848d7cea..b753f75cc8d9 100644 --- a/pkg/services/ssosettings/ssosettingsimpl/service.go +++ b/pkg/services/ssosettings/ssosettingsimpl/service.go @@ -433,6 +433,7 @@ func removeSecrets(settings map[string]any) map[string]any { // mergeSettings merges two maps in a way that the values from the first map are preserved // and the values from the second map are added only if they don't exist in the first map +// or if they contain empty URLs. func mergeSettings(storedSettings, systemSettings map[string]any) map[string]any { settings := make(map[string]any) @@ -443,6 +444,12 @@ func mergeSettings(storedSettings, systemSettings map[string]any) map[string]any for k, v := range systemSettings { if _, ok := settings[k]; !ok { settings[k] = v + } else if isURL(k) && isEmptyString(settings[k]) { + // Overwrite all URL settings from the DB containing an empty string with their value + // from the system settings. This fixes an issue with empty auth_url, api_url and token_url + // from the DB not being replaced with their values defined in the system settings for + // the Google provider. + settings[k] = v } } @@ -486,6 +493,15 @@ func isSecret(fieldName string) bool { return false } +func isURL(fieldName string) bool { + return strings.HasSuffix(fieldName, "_url") +} + +func isEmptyString(val any) bool { + _, ok := val.(string) + return ok && val == "" +} + func isNewSecretValue(value string) bool { return value != setting.RedactedPassword } diff --git a/pkg/services/ssosettings/ssosettingsimpl/service_test.go b/pkg/services/ssosettings/ssosettingsimpl/service_test.go index 6f736c5479ee..10fa239fdbb5 100644 --- a/pkg/services/ssosettings/ssosettingsimpl/service_test.go +++ b/pkg/services/ssosettings/ssosettingsimpl/service_test.go @@ -185,6 +185,42 @@ func TestService_GetForProvider(t *testing.T) { }, wantErr: true, }, + { + name: "correctly merge the DB and system settings", + setup: func(env testEnv) { + env.store.ExpectedSSOSetting = &models.SSOSettings{ + Provider: "github", + Settings: map[string]any{ + "enabled": true, + "auth_url": "", + "api_url": "https://overwritten-api.com/user", + "team_ids": "", + }, + Source: models.DB, + } + env.fallbackStrategy.ExpectedIsMatch = true + env.fallbackStrategy.ExpectedConfigs = map[string]map[string]any{ + "github": { + "auth_url": "https://github.com/login/oauth/authorize", + "token_url": "https://github.com/login/oauth/access_token", + "api_url": "https://api.github.com/user", + "team_ids": "10,11,12", + }, + } + }, + want: &models.SSOSettings{ + Provider: "github", + Settings: map[string]any{ + "enabled": true, + "auth_url": "https://github.com/login/oauth/authorize", + "token_url": "https://github.com/login/oauth/access_token", + "api_url": "https://overwritten-api.com/user", + "team_ids": "", + }, + Source: models.DB, + }, + wantErr: false, + }, } for _, tc := range testCases { From af6316a8f65d30bef6561c26222e22e2f62eed73 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 13 Mar 2024 13:40:28 +0100 Subject: [PATCH 067/138] [v10.4.x] Alerting: Improve alert list panel and alert rules toolbar permissions handling (#84345) Alerting: Improve alert list panel and alert rules toolbar permissions handling (#83954) * Improve alert list panel and alert rules toolbar permissions handling * Refactor permission checking, add tests * Remove unneccessary act wrapper * Fix test error (cherry picked from commit a4acd9d204f3b9560bab2b344dd0e64be41de747) Co-authored-by: Konrad Lalik --- .../alerting/unified/initAlerting.tsx | 26 +++++++++----- .../panel/alertlist/UnifiedAlertList.tsx | 31 +++++++++------- .../panel/alertlist/UnifiedalertList.test.tsx | 36 ++++++++++--------- public/app/plugins/panel/alertlist/module.tsx | 4 +-- 4 files changed, 57 insertions(+), 40 deletions(-) diff --git a/public/app/features/alerting/unified/initAlerting.tsx b/public/app/features/alerting/unified/initAlerting.tsx index 7ae82186e5ff..e043057330f4 100644 --- a/public/app/features/alerting/unified/initAlerting.tsx +++ b/public/app/features/alerting/unified/initAlerting.tsx @@ -1,21 +1,29 @@ import React from 'react'; import { config } from '@grafana/runtime'; +import { contextSrv } from 'app/core/services/context_srv'; import { addCustomRightAction } from '../../dashboard/components/DashNav/DashNav'; +import { getRulesPermissions } from './utils/access-control'; +import { GRAFANA_RULES_SOURCE_NAME } from './utils/datasource'; + const AlertRulesToolbarButton = React.lazy( () => import(/* webpackChunkName: "alert-rules-toolbar-button" */ './integration/AlertRulesToolbarButton') ); export function initAlerting() { - addCustomRightAction({ - show: () => config.unifiedAlertingEnabled || (config.featureToggles.alertingPreviewUpgrade ?? false), - component: ({ dashboard }) => ( - - {dashboard && } - - ), - index: -2, - }); + const grafanaRulesPermissions = getRulesPermissions(GRAFANA_RULES_SOURCE_NAME); + + if (contextSrv.hasPermission(grafanaRulesPermissions.read)) { + addCustomRightAction({ + show: () => config.unifiedAlertingEnabled || (config.featureToggles.alertingPreviewUpgrade ?? false), + component: ({ dashboard }) => ( + + {dashboard && } + + ), + index: -2, + }); + } } diff --git a/public/app/plugins/panel/alertlist/UnifiedAlertList.tsx b/public/app/plugins/panel/alertlist/UnifiedAlertList.tsx index 890f8b238339..c6676c6ad42e 100644 --- a/public/app/plugins/panel/alertlist/UnifiedAlertList.tsx +++ b/public/app/plugins/panel/alertlist/UnifiedAlertList.tsx @@ -16,7 +16,6 @@ import { useStyles2, } from '@grafana/ui'; import { config } from 'app/core/config'; -import { contextSrv } from 'app/core/services/context_srv'; import alertDef from 'app/features/alerting/state/alertDef'; import { alertRuleApi } from 'app/features/alerting/unified/api/alertRuleApi'; import { INSTANCES_DISPLAY_LIMIT } from 'app/features/alerting/unified/components/rules/RuleDetails'; @@ -38,9 +37,10 @@ import { flattenCombinedRules, getFirstActiveAt } from 'app/features/alerting/un import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv'; import { DashboardModel } from 'app/features/dashboard/state'; import { Matcher } from 'app/plugins/datasource/alertmanager/types'; -import { AccessControlAction, ThunkDispatch, useDispatch } from 'app/types'; +import { ThunkDispatch, useDispatch } from 'app/types'; import { PromAlertingRuleState } from 'app/types/unified-alerting-dto'; +import { AlertingAction, useAlertingAbility } from '../../../features/alerting/unified/hooks/useAbilities'; import { getAlertingRule } from '../../../features/alerting/unified/utils/rules'; import { AlertingRule, CombinedRuleWithLocation } from '../../../types/unified-alerting'; @@ -93,9 +93,10 @@ const fetchPromAndRuler = ({ } }; -export function UnifiedAlertList(props: PanelProps) { +function UnifiedAlertList(props: PanelProps) { const dispatch = useDispatch(); const [limitInstances, toggleLimit] = useToggle(true); + const [, gmaViewAllowed] = useAlertingAbility(AlertingAction.ViewAlertRule); const { usePrometheusRulesByNamespaceQuery } = alertRuleApi; @@ -137,7 +138,7 @@ export function UnifiedAlertList(props: PanelProps) { // If the datasource is not defined we should NOT skip the query // Undefined dataSourceName means that there is no datasource filter applied and we should fetch all the rules - const shouldFetchGrafanaRules = !dataSourceName || dataSourceName === GRAFANA_RULES_SOURCE_NAME; + const shouldFetchGrafanaRules = (!dataSourceName || dataSourceName === GRAFANA_RULES_SOURCE_NAME) && gmaViewAllowed; //For grafana managed rules, get the result using RTK Query to avoid the need of using the redux store //See https://github.com/grafana/grafana/pull/70482 @@ -217,15 +218,6 @@ export function UnifiedAlertList(props: PanelProps) { const havePreviousResults = Object.values(promRulesRequests).some((state) => state.result); - if ( - !contextSrv.hasPermission(AccessControlAction.AlertingRuleRead) && - !contextSrv.hasPermission(AccessControlAction.AlertingRuleExternalRead) - ) { - return ( - Sorry, you do not have the required permissions to read alert rules - ); - } - return (
@@ -456,3 +448,16 @@ export const getStyles = (theme: GrafanaTheme2) => ({ display: none; `, }); + +export function UnifiedAlertListPanel(props: PanelProps) { + const [, gmaReadAllowed] = useAlertingAbility(AlertingAction.ViewAlertRule); + const [, externalReadAllowed] = useAlertingAbility(AlertingAction.ViewExternalAlertRule); + + if (!gmaReadAllowed && !externalReadAllowed) { + return ( + Sorry, you do not have the required permissions to read alert rules + ); + } + + return ; +} diff --git a/public/app/plugins/panel/alertlist/UnifiedalertList.test.tsx b/public/app/plugins/panel/alertlist/UnifiedalertList.test.tsx index 22d963ddf4c1..d4847dd8289c 100644 --- a/public/app/plugins/panel/alertlist/UnifiedalertList.test.tsx +++ b/public/app/plugins/panel/alertlist/UnifiedalertList.test.tsx @@ -2,7 +2,6 @@ import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; import { Provider } from 'react-redux'; -import { act } from 'react-test-renderer'; import { byRole, byText } from 'testing-library-selector'; import { FieldConfigSource, getDefaultTimeRange, LoadingState, PanelProps, PluginExtensionTypes } from '@grafana/data'; @@ -25,7 +24,7 @@ import { } from '../../../features/alerting/unified/mocks'; import { GRAFANA_RULES_SOURCE_NAME } from '../../../features/alerting/unified/utils/datasource'; -import { UnifiedAlertList } from './UnifiedAlertList'; +import { UnifiedAlertListPanel } from './UnifiedAlertList'; import { GroupMode, SortOrder, UnifiedAlertListOptions, ViewMode } from './types'; import * as utils from './util'; @@ -159,20 +158,20 @@ const renderPanel = (options: Partial = defaultOptions) return render( - + ); }; describe('UnifiedAlertList', () => { + jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(true); + it('subscribes to the dashboard refresh interval', async () => { jest.spyOn(defaultProps, 'replaceVariables').mockReturnValue('severity=critical'); - await act(async () => { - renderPanel(); - }); + renderPanel(); - expect(dashboard.events.subscribe).toHaveBeenCalledTimes(1); + await waitFor(() => expect(dashboard.events.subscribe).toHaveBeenCalledTimes(1)); expect(dashboard.events.subscribe.mock.calls[0][0]).toEqual(TimeRangeUpdatedEvent); }); @@ -180,21 +179,18 @@ describe('UnifiedAlertList', () => { await waitFor(() => { expect(screen.queryByText('Loading...')).not.toBeInTheDocument(); }); - jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(true); const filterAlertsSpy = jest.spyOn(utils, 'filterAlerts'); const replaceVarsSpy = jest.spyOn(defaultProps, 'replaceVariables').mockReturnValue('severity=critical'); const user = userEvent.setup(); - await act(async () => { - renderPanel({ - alertInstanceLabelFilter: '$label', - dashboardAlerts: false, - alertName: '', - datasource: GRAFANA_RULES_SOURCE_NAME, - folder: undefined, - }); + renderPanel({ + alertInstanceLabelFilter: '$label', + dashboardAlerts: false, + alertName: '', + datasource: GRAFANA_RULES_SOURCE_NAME, + folder: undefined, }); await waitFor(() => { @@ -222,4 +218,12 @@ describe('UnifiedAlertList', () => { expect.anything() ); }); + + it('should render authorization error when user has no permission', async () => { + jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(false); + + renderPanel(); + + expect(screen.getByRole('alert', { name: 'Permission required' })).toBeInTheDocument(); + }); }); diff --git a/public/app/plugins/panel/alertlist/module.tsx b/public/app/plugins/panel/alertlist/module.tsx index 8250c7fd4d46..0bb5d10eeedc 100644 --- a/public/app/plugins/panel/alertlist/module.tsx +++ b/public/app/plugins/panel/alertlist/module.tsx @@ -17,7 +17,7 @@ import { GRAFANA_DATASOURCE_NAME } from '../../../features/alerting/unified/util import { AlertList } from './AlertList'; import { alertListPanelMigrationHandler } from './AlertListMigrationHandler'; import { GroupBy } from './GroupByWithLoading'; -import { UnifiedAlertList } from './UnifiedAlertList'; +import { UnifiedAlertListPanel } from './UnifiedAlertList'; import { AlertListSuggestionsSupplier } from './suggestions'; import { AlertListOptions, GroupMode, ShowOption, SortOrder, UnifiedAlertListOptions, ViewMode } from './types'; @@ -156,7 +156,7 @@ const alertList = new PanelPlugin(AlertList) .setMigrationHandler(alertListPanelMigrationHandler) .setSuggestionsSupplier(new AlertListSuggestionsSupplier()); -const unifiedAlertList = new PanelPlugin(UnifiedAlertList).setPanelOptions((builder) => { +const unifiedAlertList = new PanelPlugin(UnifiedAlertListPanel).setPanelOptions((builder) => { builder .addRadio({ path: 'viewMode', From 45e78b36bf88c24e46afff154d64b00080891b63 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 13 Mar 2024 14:04:46 +0100 Subject: [PATCH 068/138] [v10.4.x] Auth: Only call rotate token if we have a session expiry cookie (#84181) Auth: Only call rotate token if we have a session expiry cookie (#84169) Only call rotate token if we have a session expiry cookie (cherry picked from commit 4272483c54a55d807788c163963b70071343eba4) Co-authored-by: Karl Persson --- public/app/core/services/backend_srv.ts | 11 ++++++----- public/app/core/specs/backend_srv.test.ts | 5 +++++ public/app/core/utils/auth.ts | 4 ++++ 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/public/app/core/services/backend_srv.ts b/public/app/core/services/backend_srv.ts index be9a2c01cbff..559fbff18ff3 100644 --- a/public/app/core/services/backend_srv.ts +++ b/public/app/core/services/backend_srv.ts @@ -19,7 +19,7 @@ import { AppEvents, DataQueryErrorType } from '@grafana/data'; import { BackendSrv as BackendService, BackendSrvRequest, config, FetchError, FetchResponse } from '@grafana/runtime'; import appEvents from 'app/core/app_events'; import { getConfig } from 'app/core/config'; -import { getSessionExpiry } from 'app/core/utils/auth'; +import { getSessionExpiry, hasSessionExpiry } from 'app/core/utils/auth'; import { loadUrlToken } from 'app/core/utils/urlToken'; import { DashboardModel } from 'app/features/dashboard/state'; import { DashboardSearchItem } from 'app/features/search/types'; @@ -390,10 +390,11 @@ export class BackendSrv implements BackendService { } let authChecker = this.loginPing(); - - const expired = getSessionExpiry() * 1000 < Date.now(); - if (expired) { - authChecker = this.rotateToken(); + if (hasSessionExpiry()) { + const expired = getSessionExpiry() * 1000 < Date.now(); + if (expired) { + authChecker = this.rotateToken(); + } } return from(authChecker).pipe( diff --git a/public/app/core/specs/backend_srv.test.ts b/public/app/core/specs/backend_srv.test.ts index 54118ce553f3..075ec6f0095d 100644 --- a/public/app/core/specs/backend_srv.test.ts +++ b/public/app/core/specs/backend_srv.test.ts @@ -86,6 +86,11 @@ const getTestContext = (overides?: object, mockFromFetch = true) => { }; }; +jest.mock('app/core/utils/auth', () => ({ + getSessionExpiry: () => 1, + hasSessionExpiry: () => true, +})); + describe('backendSrv', () => { describe('parseRequestOptions', () => { it.each` diff --git a/public/app/core/utils/auth.ts b/public/app/core/utils/auth.ts index 42d99cd59c97..8c6b69cc028b 100644 --- a/public/app/core/utils/auth.ts +++ b/public/app/core/utils/auth.ts @@ -11,3 +11,7 @@ export function getSessionExpiry() { return parseInt(expiresStr, 10); } + +export function hasSessionExpiry() { + return document.cookie.split('; ').findIndex((row) => row.startsWith('grafana_session_expiry=')) > -1; +} From 1d73820ac7ae5f944fbf2d203e1bec2e0eb68f37 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 13 Mar 2024 16:49:56 +0000 Subject: [PATCH 069/138] [v10.4.x] docs: update angular guidance (#84396) docs: update angular guidance (#84363) * docs: update angular guidance * Update docs/sources/developers/angular_deprecation/_index.md Co-authored-by: Jack Baldry * Update docs/sources/developers/angular_deprecation/_index.md Co-authored-by: Jack Baldry * update --------- Co-authored-by: Jack Baldry (cherry picked from commit d3ef762cb99b0c31e7de1c8056729c1d41dfaf5e) Co-authored-by: David Harris --- .../developers/angular_deprecation/_index.md | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/docs/sources/developers/angular_deprecation/_index.md b/docs/sources/developers/angular_deprecation/_index.md index 6799f2eebd59..060e3931dfea 100644 --- a/docs/sources/developers/angular_deprecation/_index.md +++ b/docs/sources/developers/angular_deprecation/_index.md @@ -14,7 +14,20 @@ weight: 500 # Angular support deprecation -Angular plugin support is deprecated and will be removed in a future release. There are still many community plugins that rely on Grafana's Angular plugin support to work. The same is true for many internal (private) plugins that have been developed by Grafana users over the years. Grafana version 9 has a server configuration option that is global to the entire instance and controls whether Angular plugin support is available or not. By default, Angular support is still enabled, but that will change soon once we complete the migration of all Angular code in the core product. +Angular plugin support is deprecated and will be removed in a future release. +There are legacy core Grafana visualizations and external plugins that rely on Grafana's Angular plugin support to work. The same is likely true for [private plugins](https://grafana.com/legal/plugins/) that have been developed by Grafana users for use on their own instances over the years. +From Grafana v9 and onwards, there is a [server configuration option](https://github.com/grafana/grafana/blob/d61bcdf4ca5e69489e0067c56fbe7f0bfdf84ee4/conf/defaults.ini#L362) that's global to the entire instance and controls whether Angular plugin support is available or not. +In Grafana 11, we will change the default value for the configuration to remove support. + +Warning messages are displayed if a dashboard depends on an a panel visualization or data source which requires AngularJS as shown in the following video: + +{{< youtube id="XlEVs6g8dC8" >}} + +To avoid disruption: + +- Ensure that you are running the latest version of plugins by following this guide on [updating]({{< relref "../../administration/plugin-management/#update-a-plugin" >}}). Many panels and data sources have migrated from AngularJS. +- If you are using legacy Core Grafana visualizations such as Graph or Table-old, migrate to their replacements using the provided [automatic migrations]({{< relref "./angular-plugins/#automatic-migration-of-plugins" >}}). +- Review the [list of current Angular plugins]({{< relref "./angular-plugins/" >}}) to discover which Core and external plugins are impacted, and whether an update or alternative is required. ## Why are we deprecating Angular support? @@ -30,6 +43,11 @@ New Grafana Cloud users will be unable to request for support to be added to the Our current plan is to completely remove any remaining support for Angular plugins in version 12. Including the removal of the [angular_support_enabled](https://github.com/grafana/grafana/blob/d61bcdf4ca5e69489e0067c56fbe7f0bfdf84ee4/conf/defaults.ini#L362) configuration parameter. +## A dashboard I use is displaying a warning, what do I need to do? + +A dashboard displays warnings when one or more panel visualizations or data sources in the dashboard have a dependency on Angular. +Contact your system administrator to advise them of the issue or follow the preceding guidance on avoiding disruption. + ## How do I migrate an Angular plugin to React? Depending on if it’s a data source plugin, panel plugin, or app plugin the process will differ. From f4a9aa11711ddaaf697889b2ea80cc7a3f2a4001 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 13 Mar 2024 19:31:12 +0200 Subject: [PATCH 070/138] [v10.4.x] Loki: Fix null pointer exception in case request returned an error (#84401) Loki: Fix null pointer exception in case request returned an error (#84398) Loki: Fix nullpointer in case query returned an error (cherry picked from commit 34f9bff9e031cde4e7817611c373dcd9e19b4d75) Co-authored-by: Sven Grossmann --- pkg/tsdb/loki/loki.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkg/tsdb/loki/loki.go b/pkg/tsdb/loki/loki.go index 68e1466623b6..df2302d77275 100644 --- a/pkg/tsdb/loki/loki.go +++ b/pkg/tsdb/loki/loki.go @@ -240,6 +240,11 @@ func executeQuery(ctx context.Context, query *lokiQuery, req *backend.QueryDataR defer span.End() queryRes, err := runQuery(ctx, api, query, responseOpts, plog) + if queryRes == nil { + // we always want to return a backend.DataResponse object, even if we received just an error + queryRes = &backend.DataResponse{} + } + if err != nil { span.RecordError(err) span.SetStatus(codes.Error, err.Error()) From 335aa31bdef588ef8319786d236e6ee2af64b001 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 13 Mar 2024 15:23:02 -0400 Subject: [PATCH 071/138] [v10.4.x] Alerting: Add "Keep Last State" backend functionality (#84406) Alerting: Add "Keep Last State" backend functionality (#83940) * Implement keep last state for state transitions * Respect For duration when keeping state * Only keep transition from recording an annotation * Add keep last state option for nodata/error in UI (cherry picked from commit 10dc6c6d75d95f76e49c21329968161519cc0c88) Co-authored-by: William Wernert --- pkg/services/ngalert/migration/alert_rule.go | 6 +- pkg/services/ngalert/models/alert_rule.go | 12 + pkg/services/ngalert/state/historian/core.go | 6 + pkg/services/ngalert/state/manager.go | 19 +- .../ngalert/state/manager_private_test.go | 754 +++++++++++++++++- pkg/services/ngalert/state/manager_test.go | 140 ++++ pkg/services/ngalert/state/state.go | 88 +- pkg/services/ngalert/state/state_test.go | 9 + .../rule-editor/GrafanaAlertStatePicker.tsx | 1 + public/app/types/unified-alerting-dto.ts | 2 +- 10 files changed, 995 insertions(+), 42 deletions(-) diff --git a/pkg/services/ngalert/migration/alert_rule.go b/pkg/services/ngalert/migration/alert_rule.go index a47ddb1f4c3d..393b8b1fbaa0 100644 --- a/pkg/services/ngalert/migration/alert_rule.go +++ b/pkg/services/ngalert/migration/alert_rule.go @@ -235,7 +235,7 @@ func transNoData(l log.Logger, s string) ngmodels.NoDataState { case legacymodels.NoDataSetAlerting: return ngmodels.Alerting case legacymodels.NoDataKeepState: - return ngmodels.NoData // "keep last state" translates to no data because we now emit a special alert when the state is "noData". The result is that the evaluation will not return firing and instead we'll raise the special alert. + return ngmodels.KeepLast default: l.Warn("Unable to translate execution of NoData state. Using default execution", "old", s, "new", ngmodels.NoData) return ngmodels.NoData @@ -247,9 +247,7 @@ func transExecErr(l log.Logger, s string) ngmodels.ExecutionErrorState { case "", legacymodels.ExecutionErrorSetAlerting: return ngmodels.AlertingErrState case legacymodels.ExecutionErrorKeepState: - // Keep last state is translated to error as we now emit a - // DatasourceError alert when the state is error - return ngmodels.ErrorErrState + return ngmodels.KeepLastErrState case legacymodels.ExecutionErrorSetOk: return ngmodels.OkErrState default: diff --git a/pkg/services/ngalert/models/alert_rule.go b/pkg/services/ngalert/models/alert_rule.go index c73c21b04bf0..320d29386b55 100644 --- a/pkg/services/ngalert/models/alert_rule.go +++ b/pkg/services/ngalert/models/alert_rule.go @@ -7,6 +7,7 @@ import ( "fmt" "sort" "strconv" + "strings" "time" "github.com/google/go-cmp/cmp" @@ -53,6 +54,8 @@ func NoDataStateFromString(state string) (NoDataState, error) { return NoData, nil case string(OK): return OK, nil + case string(KeepLast): + return KeepLast, nil default: return "", fmt.Errorf("unknown NoData state option %s", state) } @@ -62,6 +65,7 @@ const ( Alerting NoDataState = "Alerting" NoData NoDataState = "NoData" OK NoDataState = "OK" + KeepLast NoDataState = "KeepLast" ) // swagger:enum ExecutionErrorState @@ -79,6 +83,8 @@ func ErrStateFromString(opt string) (ExecutionErrorState, error) { return ErrorErrState, nil case string(OkErrState): return OkErrState, nil + case string(KeepLastErrState): + return KeepLastErrState, nil default: return "", fmt.Errorf("unknown Error state option %s", opt) } @@ -88,6 +94,7 @@ const ( AlertingErrState ExecutionErrorState = "Alerting" ErrorErrState ExecutionErrorState = "Error" OkErrState ExecutionErrorState = "OK" + KeepLastErrState ExecutionErrorState = "KeepLast" ) const ( @@ -137,8 +144,13 @@ const ( StateReasonPaused = "Paused" StateReasonUpdated = "Updated" StateReasonRuleDeleted = "RuleDeleted" + StateReasonKeepLast = "KeepLast" ) +func ConcatReasons(reasons ...string) string { + return strings.Join(reasons, ", ") +} + var ( // InternalLabelNameSet are labels that grafana automatically include as part of the labelset. InternalLabelNameSet = map[string]struct{}{ diff --git a/pkg/services/ngalert/state/historian/core.go b/pkg/services/ngalert/state/historian/core.go index 24d477c21f01..cbeb4f452053 100644 --- a/pkg/services/ngalert/state/historian/core.go +++ b/pkg/services/ngalert/state/historian/core.go @@ -41,6 +41,12 @@ func ShouldRecordAnnotation(t state.StateTransition) bool { return false } + // Do not log transitions when keeping last state + toKeepLast := strings.Contains(t.StateReason, models.StateReasonKeepLast) && !strings.Contains(t.PreviousStateReason, models.StateReasonKeepLast) + if toKeepLast { + return false + } + // Do not record transitions between Normal and Normal (NoData) if t.State.State == eval.Normal && t.PreviousState == eval.Normal { if (t.State.StateReason == "" && t.PreviousStateReason == models.StateReasonNoData) || diff --git a/pkg/services/ngalert/state/manager.go b/pkg/services/ngalert/state/manager.go index 4b0f11e397ee..da6d614ff5ef 100644 --- a/pkg/services/ngalert/state/manager.go +++ b/pkg/services/ngalert/state/manager.go @@ -316,14 +316,14 @@ func (st *Manager) ProcessEvalResults(ctx context.Context, evaluatedAt time.Time } func (st *Manager) setNextStateForRule(ctx context.Context, alertRule *ngModels.AlertRule, results eval.Results, extraLabels data.Labels, logger log.Logger) []StateTransition { - if st.applyNoDataAndErrorToAllStates && results.IsNoData() && (alertRule.NoDataState == ngModels.Alerting || alertRule.NoDataState == ngModels.OK) { // If it is no data, check the mapping and switch all results to the new state + if st.applyNoDataAndErrorToAllStates && results.IsNoData() && (alertRule.NoDataState == ngModels.Alerting || alertRule.NoDataState == ngModels.OK || alertRule.NoDataState == ngModels.KeepLast) { // If it is no data, check the mapping and switch all results to the new state // TODO aggregate UID of datasources that returned NoData into one and provide as auxiliary info, probably annotation transitions := st.setNextStateForAll(ctx, alertRule, results[0], logger) if len(transitions) > 0 { return transitions // if there are no current states for the rule. Create ones for each result } } - if st.applyNoDataAndErrorToAllStates && results.IsError() && (alertRule.ExecErrState == ngModels.AlertingErrState || alertRule.ExecErrState == ngModels.OkErrState) { + if st.applyNoDataAndErrorToAllStates && results.IsError() && (alertRule.ExecErrState == ngModels.AlertingErrState || alertRule.ExecErrState == ngModels.OkErrState || alertRule.ExecErrState == ngModels.KeepLastErrState) { // TODO squash all errors into one, and provide as annotation transitions := st.setNextStateForAll(ctx, alertRule, results[0], logger) if len(transitions) > 0 { @@ -352,6 +352,7 @@ func (st *Manager) setNextStateForAll(ctx context.Context, alertRule *ngModels.A // Set the current state based on evaluation results func (st *Manager) setNextState(ctx context.Context, alertRule *ngModels.AlertRule, currentState *State, result eval.Result, logger log.Logger) StateTransition { start := st.clock.Now() + currentState.LastEvaluationTime = result.EvaluatedAt currentState.EvaluationDuration = result.EvaluationDuration currentState.Results = append(currentState.Results, Evaluation{ @@ -392,10 +393,10 @@ func (st *Manager) setNextState(ctx context.Context, alertRule *ngModels.AlertRu switch result.State { case eval.Normal: logger.Debug("Setting next state", "handler", "resultNormal") - resultNormal(currentState, alertRule, result, logger) + resultNormal(currentState, alertRule, result, logger, "") case eval.Alerting: logger.Debug("Setting next state", "handler", "resultAlerting") - resultAlerting(currentState, alertRule, result, logger) + resultAlerting(currentState, alertRule, result, logger, "") case eval.Error: logger.Debug("Setting next state", "handler", "resultError") resultError(currentState, alertRule, result, logger) @@ -412,7 +413,7 @@ func (st *Manager) setNextState(ctx context.Context, alertRule *ngModels.AlertRu if currentState.State != result.State && result.State != eval.Normal && result.State != eval.Alerting { - currentState.StateReason = result.State.String() + currentState.StateReason = resultStateReason(result, alertRule) } // Set Resolved property so the scheduler knows to send a postable alert @@ -446,6 +447,14 @@ func (st *Manager) setNextState(ctx context.Context, alertRule *ngModels.AlertRu return nextState } +func resultStateReason(result eval.Result, rule *ngModels.AlertRule) string { + if rule.ExecErrState == ngModels.KeepLastErrState || rule.NoDataState == ngModels.KeepLast { + return ngModels.ConcatReasons(result.State.String(), ngModels.StateReasonKeepLast) + } + + return result.State.String() +} + func (st *Manager) GetAll(orgID int64) []*State { allStates := st.cache.getAll(orgID, st.doNotSaveNormalState) return allStates diff --git a/pkg/services/ngalert/state/manager_private_test.go b/pkg/services/ngalert/state/manager_private_test.go index 681e44a38f14..798b37a0720b 100644 --- a/pkg/services/ngalert/state/manager_private_test.go +++ b/pkg/services/ngalert/state/manager_private_test.go @@ -812,6 +812,7 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { ngmodels.NoData: baseRuleWith(ngmodels.WithNoDataExecAs(ngmodels.NoData)), ngmodels.Alerting: baseRuleWith(ngmodels.WithNoDataExecAs(ngmodels.Alerting)), ngmodels.OK: baseRuleWith(ngmodels.WithNoDataExecAs(ngmodels.OK)), + ngmodels.KeepLast: baseRuleWith(ngmodels.WithNoDataExecAs(ngmodels.KeepLast)), } type noDataTestCase struct { @@ -919,6 +920,24 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLast: { + t1: { + { + PreviousState: eval.Normal, + State: &State{ + Labels: labels["system + rule + no-data"], + State: eval.Normal, + StateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t1, eval.NoData), + }, + StartsAt: t1, + EndsAt: t1, + LastEvaluationTime: t1, + }, + }, + }, + }, }, }, { @@ -985,6 +1004,24 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLast: { + t2: { + { + PreviousState: eval.Normal, + State: &State{ + Labels: labels["system + rule + no-data"], + State: eval.Normal, + StateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t2, eval.NoData), + }, + StartsAt: t2, + EndsAt: t2, + LastEvaluationTime: t2, + }, + }, + }, + }, }, expectedTransitionsApplyNoDataErrorToAllStates: map[ngmodels.NoDataState]map[time.Time][]StateTransition{ ngmodels.Alerting: { @@ -1025,6 +1062,25 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLast: { + t2: { + { + PreviousState: eval.Normal, + State: &State{ + Labels: labels["system + rule + labels1"], + State: eval.Normal, + StateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t1, eval.Normal), + newEvaluation(t2, eval.NoData), + }, + StartsAt: t1, + EndsAt: t1, + LastEvaluationTime: t2, + }, + }, + }, + }, }, }, { @@ -1202,6 +1258,55 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLast: { + t3: { + { + PreviousState: eval.Normal, + State: &State{ + Labels: labels["system + rule + labels1"], + State: eval.Normal, + StateReason: ngmodels.StateReasonMissingSeries, + Results: []Evaluation{ + newEvaluation(t1, eval.Normal), + }, + StartsAt: t1, + EndsAt: t3, + LastEvaluationTime: t3, + }, + }, + { + PreviousState: eval.Alerting, + State: &State{ + Labels: labels["system + rule + labels2"], + State: eval.Normal, + StateReason: ngmodels.StateReasonMissingSeries, + Results: []Evaluation{ + newEvaluation(t1, eval.Alerting), + }, + StartsAt: t1, + EndsAt: t3, + LastEvaluationTime: t3, + Resolved: true, + }, + }, + { + PreviousState: eval.Normal, + PreviousStateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + State: &State{ + Labels: labels["system + rule + no-data"], + State: eval.Normal, + StateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t2, eval.NoData), + newEvaluation(t3, eval.NoData), + }, + StartsAt: t2, + EndsAt: t2, + LastEvaluationTime: t3, + }, + }, + }, + }, }, expectedTransitionsApplyNoDataErrorToAllStates: map[ngmodels.NoDataState]map[time.Time][]StateTransition{ ngmodels.Alerting: { @@ -1345,6 +1450,76 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLast: { + t2: { + { + PreviousState: eval.Normal, + State: &State{ + Labels: labels["system + rule + labels1"], + State: eval.Normal, + StateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t1, eval.Normal), + newEvaluation(t2, eval.NoData), + }, + StartsAt: t1, + EndsAt: t1, + LastEvaluationTime: t2, + }, + }, + { + PreviousState: eval.Alerting, + State: &State{ + Labels: labels["system + rule + labels2"], + State: eval.Alerting, + StateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t1, eval.Alerting), + newEvaluation(t2, eval.NoData), + }, + StartsAt: t1, + EndsAt: t2.Add(ResendDelay * 4), + LastEvaluationTime: t2, + }, + }, + }, + t3: { + { + PreviousState: eval.Normal, + PreviousStateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + State: &State{ + Labels: labels["system + rule + labels1"], + State: eval.Normal, + StateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t1, eval.Normal), + newEvaluation(t2, eval.NoData), + newEvaluation(t3, eval.NoData), + }, + StartsAt: t1, + EndsAt: t1, + LastEvaluationTime: t3, + }, + }, + { + PreviousState: eval.Alerting, + PreviousStateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + State: &State{ + Labels: labels["system + rule + labels2"], + State: eval.Alerting, + StateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t1, eval.Alerting), + newEvaluation(t2, eval.NoData), + newEvaluation(t3, eval.NoData), + }, + StartsAt: t1, + EndsAt: t3.Add(ResendDelay * 4), + LastEvaluationTime: t3, + }, + }, + }, + }, }, }, { @@ -1533,6 +1708,53 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLast: { + t3: { + { + PreviousState: eval.Normal, + State: &State{ + Labels: labels["system + rule + labels1"], + State: eval.Normal, + StateReason: ngmodels.StateReasonMissingSeries, + Results: []Evaluation{ + newEvaluation(t1, eval.Normal), + }, + StartsAt: t1, + EndsAt: t3, + LastEvaluationTime: t3, + }, + }, + { + PreviousState: eval.Pending, + State: &State{ + Labels: labels["system + rule + labels2"], + State: eval.Normal, + StateReason: ngmodels.StateReasonMissingSeries, + Results: []Evaluation{ + newEvaluation(t1, eval.Alerting), + }, + StartsAt: t1, + EndsAt: t3, + LastEvaluationTime: t3, + }, + }, + { + PreviousState: eval.Normal, + PreviousStateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + State: &State{ + Labels: labels["system + rule + no-data"], + State: eval.Normal, + StateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t3, eval.NoData), + }, + StartsAt: t2, + EndsAt: t2, + LastEvaluationTime: t3, + }, + }, + }, + }, }, expectedTransitionsApplyNoDataErrorToAllStates: map[ngmodels.NoDataState]map[time.Time][]StateTransition{ ngmodels.Alerting: { @@ -1663,6 +1885,70 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLast: { + t2: { + { + PreviousState: eval.Normal, + State: &State{ + Labels: labels["system + rule + labels1"], + State: eval.Normal, + StateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t2, eval.NoData), + }, + StartsAt: t1, + EndsAt: t1, + LastEvaluationTime: t2, + }, + }, + { + PreviousState: eval.Pending, + State: &State{ + Labels: labels["system + rule + labels2"], + State: eval.Alerting, + StateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t2, eval.NoData), + }, + StartsAt: t2, + EndsAt: t2.Add(ResendDelay * 4), + LastEvaluationTime: t2, + }, + }, + }, + t3: { + { + PreviousState: eval.Normal, + PreviousStateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + State: &State{ + Labels: labels["system + rule + labels1"], + State: eval.Normal, + StateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t3, eval.NoData), + }, + StartsAt: t1, + EndsAt: t1, + LastEvaluationTime: t3, + }, + }, + { + PreviousState: eval.Alerting, + PreviousStateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + State: &State{ + Labels: labels["system + rule + labels2"], + State: eval.Alerting, + StateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t3, eval.NoData), + }, + StartsAt: t2, + EndsAt: t3.Add(ResendDelay * 4), + LastEvaluationTime: t3, + }, + }, + }, + }, }, }, { @@ -1734,6 +2020,24 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLast: { + t3: { + { + PreviousState: eval.Pending, + State: &State{ + Labels: labels["system + rule + labels1"], + State: eval.Alerting, + Results: []Evaluation{ + newEvaluation(t1, eval.Alerting), + newEvaluation(t3, eval.Alerting), + }, + StartsAt: t3, + EndsAt: t3.Add(ResendDelay * 4), + LastEvaluationTime: t3, + }, + }, + }, + }, }, expectedTransitionsApplyNoDataErrorToAllStates: map[ngmodels.NoDataState]map[time.Time][]StateTransition{ ngmodels.Alerting: { @@ -1774,6 +2078,25 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLast: { + t3: { + { + PreviousState: eval.Pending, + PreviousStateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + State: &State{ + Labels: labels["system + rule + labels1"], + State: eval.Alerting, + Results: []Evaluation{ + newEvaluation(t2, eval.NoData), + newEvaluation(t3, eval.Alerting), + }, + StartsAt: t3, + EndsAt: t3.Add(ResendDelay * 4), + LastEvaluationTime: t3, + }, + }, + }, + }, }, }, { @@ -1889,6 +2212,39 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLast: { + t3: { + { + PreviousState: eval.Normal, + State: &State{ + Labels: labels["system + rule + labels1"], + State: eval.Normal, + Results: []Evaluation{ + newEvaluation(t2, eval.Normal), + newEvaluation(t3, eval.Normal), + }, + StartsAt: t2, + EndsAt: t2, + LastEvaluationTime: t3, + }, + }, + { + PreviousState: eval.Normal, + PreviousStateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + State: &State{ + Labels: labels["system + rule + no-data"], + State: eval.Normal, + StateReason: ngmodels.StateReasonMissingSeries, + Results: []Evaluation{ + newEvaluation(t1, eval.NoData), + }, + StartsAt: t1, + EndsAt: t3, + LastEvaluationTime: t3, + }, + }, + }, + }, }, }, { @@ -1955,6 +2311,24 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLast: { + t2: { + { + PreviousState: eval.Normal, + State: &State{ + Labels: labels["system + rule + no-data"], + State: eval.Normal, + StateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t2, eval.NoData), + }, + StartsAt: t2, + EndsAt: t2, + LastEvaluationTime: t2, + }, + }, + }, + }, }, expectedTransitionsApplyNoDataErrorToAllStates: map[ngmodels.NoDataState]map[time.Time][]StateTransition{ ngmodels.Alerting: { @@ -1995,10 +2369,29 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLast: { + t2: { + { + PreviousState: eval.Normal, + State: &State{ + Labels: labels["system + rule"], + State: eval.Normal, + StateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t1, eval.Normal), + newEvaluation(t2, eval.NoData), + }, + StartsAt: t1, + EndsAt: t1, + LastEvaluationTime: t2, + }, + }, + }, + }, }, }, { - desc: "t1[{}:alerting] t2[NoData] t3[NoData] at t3", + desc: "t1[{}:alerting] t2[NoData] t3[NoData] at t2,t3", results: map[time.Time]eval.Results{ t1: { newResult(eval.WithState(eval.Alerting)), @@ -2129,6 +2522,41 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLast: { + t3: { + { + PreviousState: eval.Alerting, + State: &State{ + Labels: labels["system + rule"], + State: eval.Normal, + StateReason: ngmodels.StateReasonMissingSeries, + Results: []Evaluation{ + newEvaluation(t1, eval.Alerting), + }, + StartsAt: t1, + EndsAt: t3, + LastEvaluationTime: t3, + Resolved: true, + }, + }, + { + PreviousState: eval.Normal, + PreviousStateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + State: &State{ + Labels: labels["system + rule + no-data"], + State: eval.Normal, + StateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t2, eval.NoData), + newEvaluation(t3, eval.NoData), + }, + StartsAt: t2, + EndsAt: t2, + LastEvaluationTime: t3, + }, + }, + }, + }, }, expectedTransitionsApplyNoDataErrorToAllStates: map[ngmodels.NoDataState]map[time.Time][]StateTransition{ ngmodels.Alerting: { @@ -2184,25 +2612,63 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { StartsAt: t2, EndsAt: t2, LastEvaluationTime: t2, - Resolved: true, + Resolved: true, + }, + }, + }, + t3: { + { + PreviousState: eval.Normal, + PreviousStateReason: eval.NoData.String(), + State: &State{ + Labels: labels["system + rule"], + State: eval.Normal, + StateReason: eval.NoData.String(), + Results: []Evaluation{ + newEvaluation(t1, eval.Alerting), + newEvaluation(t2, eval.NoData), + newEvaluation(t3, eval.NoData), + }, + StartsAt: t2, + EndsAt: t2, + LastEvaluationTime: t3, + }, + }, + }, + }, + ngmodels.KeepLast: { + t2: { + { + PreviousState: eval.Alerting, + State: &State{ + Labels: labels["system + rule"], + State: eval.Alerting, + StateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t1, eval.Alerting), + newEvaluation(t2, eval.NoData), + }, + StartsAt: t1, + EndsAt: t2.Add(ResendDelay * 4), + LastEvaluationTime: t2, }, }, }, t3: { { - PreviousState: eval.Normal, - PreviousStateReason: eval.NoData.String(), + PreviousState: eval.Alerting, + PreviousStateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), State: &State{ Labels: labels["system + rule"], - State: eval.Normal, - StateReason: eval.NoData.String(), + State: eval.Alerting, + StateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), Results: []Evaluation{ newEvaluation(t1, eval.Alerting), newEvaluation(t2, eval.NoData), newEvaluation(t3, eval.NoData), }, - StartsAt: t2, - EndsAt: t2, + StartsAt: t1, + EndsAt: t3.Add(ResendDelay * 4), LastEvaluationTime: t3, }, }, @@ -2294,6 +2760,24 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLast: { + t3: { + { + PreviousState: eval.Pending, + State: &State{ + Labels: labels["system + rule"], + State: eval.Alerting, + Results: []Evaluation{ + newEvaluation(t1, eval.Alerting), + newEvaluation(t3, eval.Alerting), + }, + StartsAt: t3, + EndsAt: t3.Add(ResendDelay * 4), + LastEvaluationTime: t3, + }, + }, + }, + }, }, expectedTransitionsApplyNoDataErrorToAllStates: map[ngmodels.NoDataState]map[time.Time][]StateTransition{ ngmodels.Alerting: { @@ -2334,6 +2818,25 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLast: { + t3: { + { + PreviousState: eval.Pending, + PreviousStateReason: ngmodels.ConcatReasons(eval.NoData.String(), ngmodels.StateReasonKeepLast), + State: &State{ + Labels: labels["system + rule"], + State: eval.Alerting, + Results: []Evaluation{ + newEvaluation(t2, eval.NoData), + newEvaluation(t3, eval.Alerting), + }, + StartsAt: t3, + EndsAt: t3.Add(ResendDelay * 4), + LastEvaluationTime: t3, + }, + }, + }, + }, }, }, } @@ -2350,6 +2853,7 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { ngmodels.ErrorErrState: baseRuleWith(ngmodels.WithErrorExecAs(ngmodels.ErrorErrState)), ngmodels.AlertingErrState: baseRuleWith(ngmodels.WithErrorExecAs(ngmodels.AlertingErrState)), ngmodels.OkErrState: baseRuleWith(ngmodels.WithErrorExecAs(ngmodels.OkErrState)), + ngmodels.KeepLastErrState: baseRuleWith(ngmodels.WithErrorExecAs(ngmodels.KeepLastErrState)), } cacheID := func(lbls data.Labels) string { @@ -2472,6 +2976,24 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLastErrState: { + t1: { + { + PreviousState: eval.Normal, + State: &State{ + Labels: labels["system + rule"], + State: eval.Normal, + StateReason: ngmodels.ConcatReasons(eval.Error.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t1, eval.Error), + }, + StartsAt: t1, + EndsAt: t1, + LastEvaluationTime: t1, + }, + }, + }, + }, }, }, { @@ -2540,6 +3062,24 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLastErrState: { + t1: { + { + PreviousState: eval.Normal, + State: &State{ + Labels: labels["system + rule"], + State: eval.Normal, + StateReason: ngmodels.ConcatReasons(eval.Error.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t1, eval.Error), + }, + StartsAt: t1, + EndsAt: t1, + LastEvaluationTime: t1, + }, + }, + }, + }, }, }, { @@ -2613,6 +3153,24 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLastErrState: { + t2: { + { + PreviousState: eval.Normal, + State: &State{ + Labels: labels["system + rule"], + State: eval.Normal, + StateReason: ngmodels.ConcatReasons(eval.Error.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t2, eval.Error), + }, + StartsAt: t2, + EndsAt: t2, + LastEvaluationTime: t2, + }, + }, + }, + }, }, expectedTransitionsApplyNoDataErrorToAllStates: map[ngmodels.ExecutionErrorState]map[time.Time][]StateTransition{ ngmodels.AlertingErrState: { @@ -2652,6 +3210,24 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLastErrState: { + t2: { + { + PreviousState: eval.Pending, + State: &State{ + Labels: labels["system + rule + labels1"], + State: eval.Alerting, + StateReason: ngmodels.ConcatReasons(eval.Error.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t2, eval.Error), + }, + StartsAt: t2, + EndsAt: t2.Add(ResendDelay * 4), + LastEvaluationTime: t2, + }, + }, + }, + }, }, }, { @@ -2724,6 +3300,24 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLastErrState: { + t2: { + { + PreviousState: eval.Normal, + State: &State{ + Labels: labels["system + rule"], + State: eval.Normal, + StateReason: ngmodels.ConcatReasons(eval.Error.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t2, eval.Error), + }, + StartsAt: t2, + EndsAt: t2, + LastEvaluationTime: t2, + }, + }, + }, + }, }, expectedTransitionsApplyNoDataErrorToAllStates: map[ngmodels.ExecutionErrorState]map[time.Time][]StateTransition{ ngmodels.AlertingErrState: { @@ -2765,6 +3359,25 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLastErrState: { + t2: { + { + PreviousState: eval.Normal, + State: &State{ + Labels: labels["system + rule + labels1"], + State: eval.Normal, + StateReason: ngmodels.ConcatReasons(eval.Error.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t1, eval.Normal), + newEvaluation(t2, eval.Error), + }, + StartsAt: t1, + EndsAt: t1, + LastEvaluationTime: t2, + }, + }, + }, + }, }, }, { @@ -2886,6 +3499,39 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLastErrState: { + t3: { + { + PreviousState: eval.Normal, + State: &State{ + Labels: labels["system + rule + labels1"], + State: eval.Normal, + Results: []Evaluation{ + newEvaluation(t2, eval.Normal), + newEvaluation(t3, eval.Normal), + }, + StartsAt: t2, + EndsAt: t2, + LastEvaluationTime: t3, + }, + }, + { + PreviousState: eval.Normal, + PreviousStateReason: ngmodels.ConcatReasons(eval.Error.String(), ngmodels.StateReasonKeepLast), + State: &State{ + Labels: labels["system + rule"], + State: eval.Normal, + StateReason: ngmodels.StateReasonMissingSeries, + Results: []Evaluation{ + newEvaluation(t1, eval.Error), + }, + StartsAt: t1, + EndsAt: t3, + LastEvaluationTime: t3, + }, + }, + }, + }, }, }, { @@ -2961,6 +3607,25 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLastErrState: { + t2: { + { + PreviousState: eval.Normal, + State: &State{ + Labels: labels["system + rule"], + State: eval.Normal, + StateReason: ngmodels.ConcatReasons(eval.Error.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t1, eval.Normal), + newEvaluation(t2, eval.Error), + }, + StartsAt: t1, + EndsAt: t1, + LastEvaluationTime: t2, + }, + }, + }, + }, }, }, { @@ -3049,6 +3714,24 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLastErrState: { + t2: { + { + PreviousState: eval.Pending, + State: &State{ + Labels: labels["system + rule"], + State: eval.Alerting, + StateReason: ngmodels.ConcatReasons(eval.Error.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t2, eval.Error), + }, + StartsAt: t2, + EndsAt: t2.Add(ResendDelay * 4), + LastEvaluationTime: t2, + }, + }, + }, + }, }, }, { @@ -3178,6 +3861,42 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLastErrState: { + t2: { + { + PreviousState: eval.Pending, + State: &State{ + Labels: labels["system + rule"], + State: eval.Pending, + StateReason: ngmodels.ConcatReasons(eval.Error.String(), ngmodels.StateReasonKeepLast), + Results: []Evaluation{ + newEvaluation(t1, eval.Alerting), + newEvaluation(t2, eval.Error), + }, + StartsAt: t1, + EndsAt: t1.Add(ResendDelay * 4), + LastEvaluationTime: t2, + }, + }, + }, + t3: { + { + PreviousState: eval.Pending, + PreviousStateReason: ngmodels.ConcatReasons(eval.Error.String(), ngmodels.StateReasonKeepLast), + State: &State{ + Labels: labels["system + rule"], + State: eval.Alerting, + Results: []Evaluation{ + newEvaluation(t2, eval.Error), + newEvaluation(t3, eval.Alerting), + }, + StartsAt: t3, + EndsAt: t3.Add(ResendDelay * 4), + LastEvaluationTime: t3, + }, + }, + }, + }, }, }, { @@ -3248,6 +3967,25 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) { }, }, }, + ngmodels.KeepLastErrState: { + t2: { + { + PreviousState: eval.Normal, + PreviousStateReason: ngmodels.ConcatReasons(eval.Error.String(), ngmodels.StateReasonKeepLast), + State: &State{ + Labels: labels["system + rule"], + State: eval.Normal, + Results: []Evaluation{ + newEvaluation(t1, eval.Error), + newEvaluation(t2, eval.Normal), + }, + StartsAt: t1, + EndsAt: t1, + LastEvaluationTime: t2, + }, + }, + }, + }, }, }, } diff --git a/pkg/services/ngalert/state/manager_test.go b/pkg/services/ngalert/state/manager_test.go index cd856fb66a91..38a7519f8468 100644 --- a/pkg/services/ngalert/state/manager_test.go +++ b/pkg/services/ngalert/state/manager_test.go @@ -875,6 +875,76 @@ func TestProcessEvalResults(t *testing.T) { }, }, }, + { + desc: "normal -> normal (NoData, KeepLastState) -> alerting -> alerting (NoData, KeepLastState) - keeps last state when result is NoData and NoDataState is KeepLast", + alertRule: baseRuleWith(models.WithForNTimes(0), models.WithNoDataExecAs(models.KeepLast)), + evalResults: map[time.Time]eval.Results{ + t1: { + newResult(eval.WithState(eval.Normal), eval.WithLabels(labels1)), + }, + t2: { + newResult(eval.WithState(eval.NoData), eval.WithLabels(labels1)), // TODO fix it because NoData does not have same labels + }, + t3: { + newResult(eval.WithState(eval.Alerting), eval.WithLabels(labels1)), + }, + tn(4): { + newResult(eval.WithState(eval.NoData), eval.WithLabels(labels1)), // TODO fix it because NoData does not have same labels + }, + }, + expectedAnnotations: 1, + expectedStates: []*state.State{ + { + Labels: labels["system + rule + labels1"], + ResultFingerprint: labels1.Fingerprint(), + State: eval.Alerting, + StateReason: models.ConcatReasons(eval.NoData.String(), models.StateReasonKeepLast), + Results: []state.Evaluation{ + newEvaluation(t1, eval.Normal), + newEvaluation(t2, eval.NoData), + newEvaluation(t3, eval.Alerting), + newEvaluation(tn(4), eval.NoData), + }, + StartsAt: t3, + EndsAt: tn(4).Add(state.ResendDelay * 4), + LastEvaluationTime: tn(4), + }, + }, + }, + { + desc: "normal -> pending -> pending (NoData, KeepLastState) -> alerting (NoData, KeepLastState) - keep last state respects For when result is NoData", + alertRule: baseRuleWith(models.WithForNTimes(2), models.WithNoDataExecAs(models.KeepLast)), + evalResults: map[time.Time]eval.Results{ + t1: { + newResult(eval.WithState(eval.Normal), eval.WithLabels(labels1)), + }, + t2: { + newResult(eval.WithState(eval.Alerting), eval.WithLabels(labels1)), + }, + t3: { + newResult(eval.WithState(eval.NoData), eval.WithLabels(labels1)), // TODO fix it because NoData does not have same labels + }, + tn(4): { + newResult(eval.WithState(eval.NoData), eval.WithLabels(labels1)), // TODO fix it because NoData does not have same labels + }, + }, + expectedAnnotations: 2, + expectedStates: []*state.State{ + { + Labels: labels["system + rule + labels1"], + ResultFingerprint: labels1.Fingerprint(), + State: eval.Alerting, + StateReason: models.ConcatReasons(eval.NoData.String(), models.StateReasonKeepLast), + Results: []state.Evaluation{ + newEvaluation(t3, eval.NoData), + newEvaluation(tn(4), eval.NoData), + }, + StartsAt: tn(4), + EndsAt: tn(4).Add(state.ResendDelay * 4), + LastEvaluationTime: tn(4), + }, + }, + }, { desc: "normal -> normal when result is NoData and NoDataState is ok", alertRule: baseRuleWith(models.WithNoDataExecAs(models.OK)), @@ -1012,6 +1082,76 @@ func TestProcessEvalResults(t *testing.T) { }, }, }, + { + desc: "normal -> normal (Error, KeepLastState) -> alerting -> alerting (Error, KeepLastState) - keeps last state when result is Error and ExecErrState is KeepLast", + alertRule: baseRuleWith(models.WithForNTimes(0), models.WithErrorExecAs(models.KeepLastErrState)), + evalResults: map[time.Time]eval.Results{ + t1: { + newResult(eval.WithState(eval.Normal), eval.WithLabels(labels1)), + }, + t2: { + newResult(eval.WithError(expr.MakeQueryError("A", "datasource_uid_1", errors.New("this is an error"))), eval.WithLabels(labels1)), // TODO fix it because error labels are different + }, + t3: { + newResult(eval.WithState(eval.Alerting), eval.WithLabels(labels1)), + }, + tn(4): { + newResult(eval.WithError(expr.MakeQueryError("A", "datasource_uid_1", errors.New("this is an error"))), eval.WithLabels(labels1)), // TODO fix it because error labels are different + }, + }, + expectedAnnotations: 1, + expectedStates: []*state.State{ + { + Labels: labels["system + rule + labels1"], + ResultFingerprint: labels1.Fingerprint(), + State: eval.Alerting, + StateReason: models.ConcatReasons(eval.Error.String(), models.StateReasonKeepLast), + Results: []state.Evaluation{ + newEvaluation(t1, eval.Normal), + newEvaluation(t2, eval.Error), + newEvaluation(t3, eval.Alerting), + newEvaluation(tn(4), eval.Error), + }, + StartsAt: t3, + EndsAt: tn(4).Add(state.ResendDelay * 4), + LastEvaluationTime: tn(4), + }, + }, + }, + { + desc: "normal -> pending -> pending (Error, KeepLastState) -> alerting (Error, KeepLastState) - keep last state respects For when result is Error", + alertRule: baseRuleWith(models.WithForNTimes(2), models.WithErrorExecAs(models.KeepLastErrState)), + evalResults: map[time.Time]eval.Results{ + t1: { + newResult(eval.WithState(eval.Normal), eval.WithLabels(labels1)), + }, + t2: { + newResult(eval.WithState(eval.Alerting), eval.WithLabels(labels1)), + }, + t3: { + newResult(eval.WithError(expr.MakeQueryError("A", "datasource_uid_1", errors.New("this is an error"))), eval.WithLabels(labels1)), // TODO fix it because error labels are different + }, + tn(4): { + newResult(eval.WithError(expr.MakeQueryError("A", "datasource_uid_1", errors.New("this is an error"))), eval.WithLabels(labels1)), // TODO fix it because error labels are different + }, + }, + expectedAnnotations: 2, + expectedStates: []*state.State{ + { + Labels: labels["system + rule + labels1"], + ResultFingerprint: labels1.Fingerprint(), + State: eval.Alerting, + StateReason: models.ConcatReasons(eval.Error.String(), models.StateReasonKeepLast), + Results: []state.Evaluation{ + newEvaluation(t3, eval.Error), + newEvaluation(tn(4), eval.Error), + }, + StartsAt: tn(4), + EndsAt: tn(4).Add(state.ResendDelay * 4), + LastEvaluationTime: tn(4), + }, + }, + }, { desc: "normal -> normal when result is Error and ExecErrState is OK", alertRule: baseRuleWith(models.WithForNTimes(6), models.WithErrorExecAs(models.OkErrState)), diff --git a/pkg/services/ngalert/state/state.go b/pkg/services/ngalert/state/state.go index 6a1f3b2bab1c..11c86f6b10e4 100644 --- a/pkg/services/ngalert/state/state.go +++ b/pkg/services/ngalert/state/state.go @@ -191,7 +191,7 @@ func NewEvaluationValues(m map[string]eval.NumberValueCapture) map[string]*float return result } -func resultNormal(state *State, _ *models.AlertRule, result eval.Result, logger log.Logger) { +func resultNormal(state *State, _ *models.AlertRule, result eval.Result, logger log.Logger, reason string) { if state.State == eval.Normal { logger.Debug("Keeping state", "state", state.State) } else { @@ -206,11 +206,11 @@ func resultNormal(state *State, _ *models.AlertRule, result eval.Result, logger "next_ends_at", nextEndsAt) // Normal states have the same start and end timestamps - state.SetNormal("", nextEndsAt, nextEndsAt) + state.SetNormal(reason, nextEndsAt, nextEndsAt) } } -func resultAlerting(state *State, rule *models.AlertRule, result eval.Result, logger log.Logger) { +func resultAlerting(state *State, rule *models.AlertRule, result eval.Result, logger log.Logger, reason string) { switch state.State { case eval.Alerting: prevEndsAt := state.EndsAt @@ -235,7 +235,7 @@ func resultAlerting(state *State, rule *models.AlertRule, result eval.Result, lo state.EndsAt, "next_ends_at", nextEndsAt) - state.SetAlerting("", result.EvaluatedAt, nextEndsAt) + state.SetAlerting(reason, result.EvaluatedAt, nextEndsAt) } default: nextEndsAt := nextEndsTime(rule.IntervalSeconds, result.EvaluatedAt) @@ -250,7 +250,7 @@ func resultAlerting(state *State, rule *models.AlertRule, result eval.Result, lo state.EndsAt, "next_ends_at", nextEndsAt) - state.SetPending("", result.EvaluatedAt, nextEndsAt) + state.SetPending(reason, result.EvaluatedAt, nextEndsAt) } else { logger.Debug("Changing state", "previous_state", @@ -261,18 +261,20 @@ func resultAlerting(state *State, rule *models.AlertRule, result eval.Result, lo state.EndsAt, "next_ends_at", nextEndsAt) - state.SetAlerting("", result.EvaluatedAt, nextEndsAt) + state.SetAlerting(reason, result.EvaluatedAt, nextEndsAt) } } } + func resultError(state *State, rule *models.AlertRule, result eval.Result, logger log.Logger) { + handlerStr := "resultError" + switch rule.ExecErrState { case models.AlertingErrState: - logger.Debug("Execution error state is Alerting", "handler", "resultAlerting", "previous_handler", "resultError") - resultAlerting(state, rule, result, logger) + logger.Debug("Execution error state is Alerting", "handler", "resultAlerting", "previous_handler", handlerStr) + resultAlerting(state, rule, result, logger, models.StateReasonError) // This is a special case where Alerting and Pending should also have an error and reason state.Error = result.Error - state.StateReason = models.StateReasonError case models.ErrorErrState: if state.State == eval.Error { prevEndsAt := state.EndsAt @@ -316,8 +318,11 @@ func resultError(state *State, rule *models.AlertRule, result eval.Result, logge } } case models.OkErrState: - logger.Debug("Execution error state is Normal", "handler", "resultNormal", "previous_handler", "resultError") - resultNormal(state, rule, result, logger) + logger.Debug("Execution error state is Normal", "handler", "resultNormal", "previous_handler", handlerStr) + resultNormal(state, rule, result, logger, "") // TODO: Should we add a reason? + case models.KeepLastErrState: + logger := logger.New("previous_handler", handlerStr) + resultKeepLast(state, rule, result, logger) default: err := fmt.Errorf("unsupported execution error state: %s", rule.ExecErrState) state.SetError(err, state.StartsAt, nextEndsTime(rule.IntervalSeconds, result.EvaluatedAt)) @@ -326,11 +331,12 @@ func resultError(state *State, rule *models.AlertRule, result eval.Result, logge } func resultNoData(state *State, rule *models.AlertRule, result eval.Result, logger log.Logger) { + handlerStr := "resultNoData" + switch rule.NoDataState { case models.Alerting: - logger.Debug("Execution no data state is Alerting", "handler", "resultAlerting", "previous_handler", "resultNoData") - resultAlerting(state, rule, result, logger) - state.StateReason = models.StateReasonNoData + logger.Debug("Execution no data state is Alerting", "handler", "resultAlerting", "previous_handler", handlerStr) + resultAlerting(state, rule, result, logger, models.StateReasonNoData) case models.NoData: if state.State == eval.NoData { prevEndsAt := state.EndsAt @@ -357,9 +363,11 @@ func resultNoData(state *State, rule *models.AlertRule, result eval.Result, logg state.SetNoData("", result.EvaluatedAt, nextEndsAt) } case models.OK: - logger.Debug("Execution no data state is Normal", "handler", "resultNormal", "previous_handler", "resultNoData") - resultNormal(state, rule, result, logger) - state.StateReason = models.StateReasonNoData + logger.Debug("Execution no data state is Normal", "handler", "resultNormal", "previous_handler", handlerStr) + resultNormal(state, rule, result, logger, models.StateReasonNoData) + case models.KeepLast: + logger := logger.New("previous_handler", handlerStr) + resultKeepLast(state, rule, result, logger) default: err := fmt.Errorf("unsupported no data state: %s", rule.NoDataState) state.SetError(err, state.StartsAt, nextEndsTime(rule.IntervalSeconds, result.EvaluatedAt)) @@ -367,6 +375,31 @@ func resultNoData(state *State, rule *models.AlertRule, result eval.Result, logg } } +func resultKeepLast(state *State, rule *models.AlertRule, result eval.Result, logger log.Logger) { + reason := models.ConcatReasons(result.State.String(), models.StateReasonKeepLast) + + switch state.State { + case eval.Alerting: + logger.Debug("Execution keep last state is Alerting", "handler", "resultAlerting") + resultAlerting(state, rule, result, logger, reason) + case eval.Pending: + // respect 'for' setting on rule + if result.EvaluatedAt.Sub(state.StartsAt) >= rule.For { + logger.Debug("Execution keep last state is Pending", "handler", "resultAlerting") + resultAlerting(state, rule, result, logger, reason) + } else { + logger.Debug("Ignoring set next state to pending") + } + case eval.Normal: + logger.Debug("Execution keep last state is Normal", "handler", "resultNormal") + resultNormal(state, rule, result, logger, reason) + default: + // this should not happen, add as failsafe + logger.Debug("Reverting invalid state to normal", "handler", "resultNormal") + resultNormal(state, rule, result, logger, reason) + } +} + func (a *State) NeedsSending(resendDelay time.Duration) bool { switch a.State { case eval.Pending: @@ -486,21 +519,28 @@ func FormatStateAndReason(state eval.State, reason string) string { // ParseFormattedState parses a state string in the format "state (reason)" // and returns the state and reason separately. func ParseFormattedState(stateStr string) (eval.State, string, error) { - split := strings.Split(stateStr, " ") - if len(split) == 0 { - return -1, "", errors.New("invalid state format") + p := 0 + // walk string until we find a space + for i, c := range stateStr { + if c == ' ' { + p = i + break + } + } + if p == 0 { + p = len(stateStr) } - state, err := eval.ParseStateString(split[0]) + state, err := eval.ParseStateString(stateStr[:p]) if err != nil { return -1, "", err } - var reason string - if len(split) > 1 { - reason = strings.Trim(split[1], "()") + if p == len(stateStr) { + return state, "", nil } + reason := strings.Trim(stateStr[p+1:], "()") return state, reason, nil } diff --git a/pkg/services/ngalert/state/state_test.go b/pkg/services/ngalert/state/state_test.go index 870f0b1d87d4..1684b7036c17 100644 --- a/pkg/services/ngalert/state/state_test.go +++ b/pkg/services/ngalert/state/state_test.go @@ -681,6 +681,15 @@ func TestParseFormattedState(t *testing.T) { require.Equal(t, ngmodels.StateReasonMissingSeries, reason) }) + t.Run("should parse formatted state with concatenated reasons", func(t *testing.T) { + stateStr := "Normal (Error, KeepLast)" + s, reason, err := ParseFormattedState(stateStr) + require.NoError(t, err) + + require.Equal(t, eval.Normal, s) + require.Equal(t, ngmodels.ConcatReasons(ngmodels.StateReasonError, ngmodels.StateReasonKeepLast), reason) + }) + t.Run("should error on empty string", func(t *testing.T) { stateStr := "" _, _, err := ParseFormattedState(stateStr) diff --git a/public/app/features/alerting/unified/components/rule-editor/GrafanaAlertStatePicker.tsx b/public/app/features/alerting/unified/components/rule-editor/GrafanaAlertStatePicker.tsx index ee732387de36..1494cc9a1359 100644 --- a/public/app/features/alerting/unified/components/rule-editor/GrafanaAlertStatePicker.tsx +++ b/public/app/features/alerting/unified/components/rule-editor/GrafanaAlertStatePicker.tsx @@ -15,6 +15,7 @@ const options: SelectableValue[] = [ { value: GrafanaAlertStateDecision.NoData, label: 'No Data' }, { value: GrafanaAlertStateDecision.OK, label: 'OK' }, { value: GrafanaAlertStateDecision.Error, label: 'Error' }, + { value: GrafanaAlertStateDecision.KeepLast, label: 'Keep Last State' }, ]; export const GrafanaAlertStatePicker = ({ includeNoData, includeError, ...props }: Props) => { diff --git a/public/app/types/unified-alerting-dto.ts b/public/app/types/unified-alerting-dto.ts index 923339e22f2c..c7d8251c10c4 100644 --- a/public/app/types/unified-alerting-dto.ts +++ b/public/app/types/unified-alerting-dto.ts @@ -178,7 +178,7 @@ export interface RulerAlertingRuleDTO extends RulerRuleBaseDTO { export enum GrafanaAlertStateDecision { Alerting = 'Alerting', NoData = 'NoData', - KeepLastState = 'KeepLastState', + KeepLast = 'KeepLast', OK = 'OK', Error = 'Error', } From 3f596e8e8c63b57bfba50952f266b8b6bbc27349 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 14 Mar 2024 09:08:16 +0100 Subject: [PATCH 072/138] [v10.4.x] Alerting docs: document HTTP API to create templates (#84424) Alerting docs: document HTTP API to create templates (#84055) (cherry picked from commit e1d9aa5a7b37113f6ba649d777aeba9331b83ce3) Co-authored-by: Pepe Cano <825430+ppcano@users.noreply.github.com> --- .../export-alerting-resources/index.md | 14 +++++++------- .../sources/shared/alerts/alerting_provisioning.md | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/sources/alerting/set-up/provision-alerting-resources/export-alerting-resources/index.md b/docs/sources/alerting/set-up/provision-alerting-resources/export-alerting-resources/index.md index 001efde81aa2..212ae9e9f44b 100644 --- a/docs/sources/alerting/set-up/provision-alerting-resources/export-alerting-resources/index.md +++ b/docs/sources/alerting/set-up/provision-alerting-resources/export-alerting-resources/index.md @@ -131,13 +131,13 @@ To export mute timings from the Grafana UI, complete the following steps. You can use the [Alerting HTTP API][alerting_http_provisioning] to return existing alerting resources in JSON and import them to another Grafana instance using the same endpoint. -| Resource | URI | Methods | -| -------------------------------------------------------------- | ----------------------------------- | ---------------- | -| [Alert rules][alerting_http_alertrules] | /api/v1/provisioning/alert-rules | GET,POST,PUT,DEL | -| [Contact points][alerting_http_contactpoints] | /api/v1/provisioning/contact-points | GET,POST,PUT,DEL | -| [Notification policy tree][alerting_http_notificationpolicies] | /api/v1/provisioning/policies | GET,PUT,DEL | -| [Mute timings][alerting_http_mutetimings] | /api/v1/provisioning/mute-timings | GET,POST,PUT,DEL | -| [Templates][alerting_http_templates] | /api/v1/provisioning/templates | GET,PUT,DEL | +| Resource | URI | +| -------------------------------------------------------------- | ----------------------------------- | +| [Alert rules][alerting_http_alertrules] | /api/v1/provisioning/alert-rules | +| [Contact points][alerting_http_contactpoints] | /api/v1/provisioning/contact-points | +| [Notification policy tree][alerting_http_notificationpolicies] | /api/v1/provisioning/policies | +| [Mute timings][alerting_http_mutetimings] | /api/v1/provisioning/mute-timings | +| [Templates][alerting_http_templates] | /api/v1/provisioning/templates | However, note the standard endpoints return a JSON format that is not compatible for provisioning through configuration files or Terraform, except the `/export` endpoints listed below. diff --git a/docs/sources/shared/alerts/alerting_provisioning.md b/docs/sources/shared/alerts/alerting_provisioning.md index eb7df8a9cac1..cfaca0ffcb89 100644 --- a/docs/sources/shared/alerts/alerting_provisioning.md +++ b/docs/sources/shared/alerts/alerting_provisioning.md @@ -157,12 +157,12 @@ For managing resources related to [data source-managed alerts]({{< relref "/docs ### Templates -| Method | URI | Name | Summary | -| ------ | ------------------------------------ | ----------------------------------------------- | ------------------------------------------ | -| DELETE | /api/v1/provisioning/templates/:name | [route delete template](#route-delete-template) | Delete a template. | -| GET | /api/v1/provisioning/templates/:name | [route get template](#route-get-template) | Get a notification template. | -| GET | /api/v1/provisioning/templates | [route get templates](#route-get-templates) | Get all notification templates. | -| PUT | /api/v1/provisioning/templates/:name | [route put template](#route-put-template) | Updates an existing notification template. | +| Method | URI | Name | Summary | +| ------ | ------------------------------------ | ----------------------------------------------- | ----------------------------------------- | +| DELETE | /api/v1/provisioning/templates/:name | [route delete template](#route-delete-template) | Delete a template. | +| GET | /api/v1/provisioning/templates/:name | [route get template](#route-get-template) | Get a notification template. | +| GET | /api/v1/provisioning/templates | [route get templates](#route-get-templates) | Get all notification templates. | +| PUT | /api/v1/provisioning/templates/:name | [route put template](#route-put-template) | Create or update a notification template. | ## Edit resources in the Grafana UI @@ -1200,7 +1200,7 @@ Status: Bad Request [ValidationError](#validation-error) -### Updates an existing notification template. (_RoutePutTemplate_) +### Create or update a notification template. (_RoutePutTemplate_) ``` PUT /api/v1/provisioning/templates/:name From 1cca6538b7357f36d41f9ca151162ae2dcc9d503 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 14 Mar 2024 13:18:05 +0200 Subject: [PATCH 073/138] [v10.4.x] Chore: Bump update checker interval to 1 day (#84452) Chore: Bump update checker interval to 1 day (#84404) * Bump interval to 1hr * 2 hours is better than 1 * Bump further to 1 day (cherry picked from commit 391d14d091e91301f95d6ce01ba8ca4dd4170b52) Co-authored-by: Andreas Christou --- pkg/services/updatechecker/grafana.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/services/updatechecker/grafana.go b/pkg/services/updatechecker/grafana.go index 5a56d886c7d7..3760fe06b134 100644 --- a/pkg/services/updatechecker/grafana.go +++ b/pkg/services/updatechecker/grafana.go @@ -60,7 +60,7 @@ func (s *GrafanaService) IsDisabled() bool { func (s *GrafanaService) Run(ctx context.Context) error { s.instrumentedCheckForUpdates(ctx) - ticker := time.NewTicker(time.Minute * 10) + ticker := time.NewTicker(time.Hour * 24) run := true for run { From 54d6cb7e96d24b97e405e6d08d41264af4cc6046 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 14 Mar 2024 15:58:55 +0100 Subject: [PATCH 074/138] [v10.4.x] Chore: Adding log also for cases where datasource UID length is invalid (#84472) Chore: Adding log also for cases where datasource UID length is invalid (#84443) * Adding log also for datasource length (cherry picked from commit 8e90e02db2bf9de26766a5c640f8717bfb103fdb) Co-authored-by: Timur Olzhabayev --- pkg/services/datasources/service/store.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/pkg/services/datasources/service/store.go b/pkg/services/datasources/service/store.go index 23ba2ceb66e1..b8afc57dbad4 100644 --- a/pkg/services/datasources/service/store.go +++ b/pkg/services/datasources/service/store.go @@ -253,8 +253,8 @@ func (ss *SqlStore) AddDataSource(ctx context.Context, cmd *datasources.AddDataS return fmt.Errorf("failed to generate UID for datasource %q: %w", cmd.Name, err) } cmd.UID = uid - } else if !util.IsValidShortUID(cmd.UID) { - logDeprecatedInvalidDsUid(ss.logger, cmd.UID, cmd.Name) + } else if err := util.ValidateUID(cmd.UID); err != nil { + logDeprecatedInvalidDsUid(ss.logger, cmd.UID, cmd.Name, err) } ds = &datasources.DataSource{ @@ -388,8 +388,10 @@ func (ss *SqlStore) UpdateDataSource(ctx context.Context, cmd *datasources.Updat } } - if !util.IsValidShortUID(cmd.UID) { - logDeprecatedInvalidDsUid(ss.logger, cmd.UID, cmd.Name) + if cmd.UID != "" { + if err := util.ValidateUID(cmd.UID); err != nil { + logDeprecatedInvalidDsUid(ss.logger, cmd.UID, cmd.Name, err) + } } return err @@ -415,11 +417,11 @@ func generateNewDatasourceUid(sess *db.Session, orgId int64) (string, error) { var generateNewUid func() string = util.GenerateShortUID -func logDeprecatedInvalidDsUid(logger log.Logger, uid, name string) { +func logDeprecatedInvalidDsUid(logger log.Logger, uid string, name string, err error) { logger.Warn( "Invalid datasource uid. The use of invalid uids is deprecated and this operation will fail in a future "+ "version of Grafana. A valid uid is a combination of a-z, A-Z, 0-9 (alphanumeric), - (dash) and _ "+ "(underscore) characters, maximum length 40", - "uid", uid, "name", name, + "uid", uid, "name", name, "error", err, ) } From b946bcad5bad697b5db514f539cf021d14e548df Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 14 Mar 2024 19:33:39 +0200 Subject: [PATCH 075/138] [v10.4.x] Chore: Removing error object from tracking (#84506) Chore: Removing error object from tracking (#84500) Removing error object from tracking (cherry picked from commit 6bc662e53b341504b95564beb74c5361ba8edbee) Co-authored-by: Timur Olzhabayev --- public/app/features/datasources/components/EditDataSource.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/features/datasources/components/EditDataSource.tsx b/public/app/features/datasources/components/EditDataSource.tsx index a0104d828f75..d141d19c253f 100644 --- a/public/app/features/datasources/components/EditDataSource.tsx +++ b/public/app/features/datasources/components/EditDataSource.tsx @@ -129,7 +129,7 @@ export function EditDataSourceView({ trackDsConfigUpdated({ item: 'success' }); appEvents.publish(new DataSourceUpdatedSuccessfully()); } catch (error) { - trackDsConfigUpdated({ item: 'fail', error }); + trackDsConfigUpdated({ item: 'fail' }); return; } From 4b0a5f022f3bf45f3f4e66344955f7519a80ab69 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Fri, 15 Mar 2024 09:34:59 -0400 Subject: [PATCH 076/138] [v10.4.x] Docs: add alt text (#84581) Docs: add alt text (#84532) Added alt text (cherry picked from commit d06e73ac2891279d8802848124f1a5652abc9b9a) Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --- docs/sources/whatsnew/whats-new-in-v10-4.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/whatsnew/whats-new-in-v10-4.md b/docs/sources/whatsnew/whats-new-in-v10-4.md index 9eb850639589..6af876b12a53 100644 --- a/docs/sources/whatsnew/whats-new-in-v10-4.md +++ b/docs/sources/whatsnew/whats-new-in-v10-4.md @@ -261,7 +261,7 @@ The SurrealDB data source launches with just the basics today. You can write que You can find more information and how to configure the plugin [on Github](https://github.com/grafana/surrealdb-datasource). -{{< figure src="/media/images/dashboards/surrealdb-dashboard-example.png" >}} +{{< figure src="/media/images/dashboards/surrealdb-dashboard-example.png" alt="Grafana dashboard using SurrealDB data source" >}} [Documentation](https://grafana.com/grafana/plugins/grafana-surrealdb-datasource/) From 17ab162a1110ba16596d69b5f1c8304970dc3de7 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Fri, 15 Mar 2024 14:50:03 +0100 Subject: [PATCH 077/138] [v10.4.x] InfluxDB: Fix sql query generation by adding quotes around the identifiers (#84587) InfluxDB: Fix sql query generation by adding quotes around the identifiers (#83765) * Quote the identifiers * wrap where filter with quotes * fix query generation (cherry picked from commit dc4c539d4626fa96a475401c1bc69d698775b494) Co-authored-by: ismail simsek --- .../influxdb/fsql/datasource.flightsql.ts | 4 +- .../datasource/influxdb/fsql/sqlUtil.test.ts | 55 ++++++++++++++++++- .../datasource/influxdb/fsql/sqlUtil.ts | 26 ++++++--- 3 files changed, 72 insertions(+), 13 deletions(-) diff --git a/public/app/plugins/datasource/influxdb/fsql/datasource.flightsql.ts b/public/app/plugins/datasource/influxdb/fsql/datasource.flightsql.ts index 476df864d0ad..18c881e2dbb0 100644 --- a/public/app/plugins/datasource/influxdb/fsql/datasource.flightsql.ts +++ b/public/app/plugins/datasource/influxdb/fsql/datasource.flightsql.ts @@ -1,12 +1,12 @@ import { DataSourceInstanceSettings, TimeRange } from '@grafana/data'; import { CompletionItemKind, LanguageDefinition, TableIdentifier } from '@grafana/experimental'; import { getTemplateSrv, TemplateSrv } from '@grafana/runtime'; -import { DB, SqlDatasource, SQLQuery, formatSQL } from '@grafana/sql'; +import { DB, formatSQL, SqlDatasource, SQLQuery } from '@grafana/sql'; import { mapFieldsToTypes } from './fields'; import { buildColumnQuery, buildTableQuery } from './flightsqlMetaQuery'; import { getSqlCompletionProvider } from './sqlCompletionProvider'; -import { quoteLiteral, quoteIdentifierIfNecessary, toRawSql } from './sqlUtil'; +import { quoteIdentifierIfNecessary, quoteLiteral, toRawSql } from './sqlUtil'; import { FlightSQLOptions } from './types'; export class FlightSQLDatasource extends SqlDatasource { diff --git a/public/app/plugins/datasource/influxdb/fsql/sqlUtil.test.ts b/public/app/plugins/datasource/influxdb/fsql/sqlUtil.test.ts index 57fe15c67095..4864004b8ec8 100644 --- a/public/app/plugins/datasource/influxdb/fsql/sqlUtil.test.ts +++ b/public/app/plugins/datasource/influxdb/fsql/sqlUtil.test.ts @@ -1,10 +1,10 @@ -import { SQLQuery, QueryEditorExpressionType } from '@grafana/sql'; +import { QueryEditorExpressionType, SQLQuery } from '@grafana/sql'; import { toRawSql } from './sqlUtil'; describe('toRawSql', () => { it('should render sql properly', () => { - const expected = 'SELECT host FROM iox.value1 WHERE time >= $__timeFrom AND time <= $__timeTo LIMIT 50'; + const expected = 'SELECT "host" FROM "value1" WHERE "time" >= $__timeFrom AND "time" <= $__timeTo LIMIT 50'; const testQuery: SQLQuery = { refId: 'A', sql: { @@ -27,4 +27,55 @@ describe('toRawSql', () => { const result = toRawSql(testQuery); expect(result).toEqual(expected); }); + + it('should wrap the identifiers with quote', () => { + const expected = 'SELECT "host" FROM "TestValue" WHERE "time" >= $__timeFrom AND "time" <= $__timeTo LIMIT 50'; + const testQuery: SQLQuery = { + refId: 'A', + sql: { + limit: 50, + columns: [ + { + parameters: [ + { + name: 'host', + type: QueryEditorExpressionType.FunctionParameter, + }, + ], + type: QueryEditorExpressionType.Function, + }, + ], + }, + dataset: 'iox', + table: 'TestValue', + }; + const result = toRawSql(testQuery); + expect(result).toEqual(expected); + }); + + it('should wrap filters in where', () => { + const expected = `SELECT "host" FROM "TestValue" WHERE "time" >= $__timeFrom AND "time" <= $__timeTo AND ("sensor_id" = '12' AND "sensor_id" = '23') LIMIT 50`; + const testQuery: SQLQuery = { + refId: 'A', + sql: { + limit: 50, + columns: [ + { + parameters: [ + { + name: 'host', + type: QueryEditorExpressionType.FunctionParameter, + }, + ], + type: QueryEditorExpressionType.Function, + }, + ], + whereString: `(sensor_id = '12' AND sensor_id = '23')`, + }, + dataset: 'iox', + table: 'TestValue', + }; + const result = toRawSql(testQuery); + expect(result).toEqual(expected); + }); }); diff --git a/public/app/plugins/datasource/influxdb/fsql/sqlUtil.ts b/public/app/plugins/datasource/influxdb/fsql/sqlUtil.ts index 81ad26737625..41317454a959 100644 --- a/public/app/plugins/datasource/influxdb/fsql/sqlUtil.ts +++ b/public/app/plugins/datasource/influxdb/fsql/sqlUtil.ts @@ -1,6 +1,6 @@ import { isEmpty } from 'lodash'; -import { SQLQuery, createSelectClause, haveColumns } from '@grafana/sql'; +import { createSelectClause, haveColumns, SQLQuery } from '@grafana/sql'; // remove identifier quoting from identifier to use in metadata queries export function unquoteIdentifier(value: string) { @@ -17,7 +17,7 @@ export function quoteLiteral(value: string) { return "'" + value.replace(/'/g, "''") + "'"; } -export function toRawSql({ sql, dataset, table }: SQLQuery): string { +export function toRawSql({ sql, table }: SQLQuery): string { let rawQuery = ''; // Return early with empty string if there is no sql column @@ -25,25 +25,33 @@ export function toRawSql({ sql, dataset, table }: SQLQuery): string { return rawQuery; } - rawQuery += createSelectClause(sql.columns); + // wrapping the column name with quotes + const sc = sql.columns.map((c) => ({ ...c, parameters: c.parameters?.map((p) => ({ ...p, name: `"${p.name}"` })) })); + rawQuery += createSelectClause(sc); - if (dataset && table) { - rawQuery += `FROM ${dataset}.${table} `; + if (table) { + rawQuery += `FROM "${table}" `; } // $__timeFrom and $__timeTo will be interpolated on the backend - rawQuery += `WHERE time >= $__timeFrom AND time <= $__timeTo `; + rawQuery += `WHERE "time" >= $__timeFrom AND "time" <= $__timeTo `; if (sql.whereString) { - rawQuery += `AND ${sql.whereString} `; + // whereString is generated by the react-awesome-query-builder + // we use SQLWhereRow as a common component + // in order to not mess with common component here we just modify the string + const wherePattern = new RegExp('(\\s?)([^\\(]\\S+)(\\s?=)', 'g'); + const subst = `$1"$2"$3`; + const whereString = sql.whereString.replace(wherePattern, subst); + rawQuery += `AND ${whereString} `; } if (sql.groupBy?.[0]?.property.name) { - const groupBy = sql.groupBy.map((g) => g.property.name).filter((g) => !isEmpty(g)); + const groupBy = sql.groupBy.map((g) => `"${g.property.name}"`).filter((g) => !isEmpty(g)); rawQuery += `GROUP BY ${groupBy.join(', ')} `; } if (sql.orderBy?.property.name) { - rawQuery += `ORDER BY ${sql.orderBy.property.name} `; + rawQuery += `ORDER BY "${sql.orderBy.property.name}" `; } if (sql.orderBy?.property.name && sql.orderByDirection) { From 0f1651658b6d2540f5d57ff10225314f0b000e33 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Fri, 15 Mar 2024 14:50:11 +0100 Subject: [PATCH 078/138] [v10.4.x] InfluxDB: Fix escaping template variable when it was used in parentheses (#84585) InfluxDB: Fix escaping template variable when it was used in parentheses (#83400) escape properly regardless of the parentheses (cherry picked from commit 6fab62739d9ca7b48c231fd546a19c8058805a40) Co-authored-by: ismail simsek --- .../plugins/datasource/influxdb/datasource.test.ts | 13 +++++++++++++ .../app/plugins/datasource/influxdb/datasource.ts | 4 ++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/public/app/plugins/datasource/influxdb/datasource.test.ts b/public/app/plugins/datasource/influxdb/datasource.test.ts index a5eb3beabab2..5e20d38370a0 100644 --- a/public/app/plugins/datasource/influxdb/datasource.test.ts +++ b/public/app/plugins/datasource/influxdb/datasource.test.ts @@ -443,6 +443,19 @@ describe('InfluxDataSource Frontend Mode', () => { expect(result).toBe(expectation); }); + it('should return the escaped value if the value wrapped in regex 3', () => { + const value = ['env', 'env2', 'env3']; + const variableMock = queryBuilder() + .withId('tempVar') + .withName('tempVar') + .withMulti(false) + .withIncludeAll(true) + .build(); + const result = ds.interpolateQueryExpr(value, variableMock, 'select from /^($tempVar)$/'); + const expectation = `env|env2|env3`; + expect(result).toBe(expectation); + }); + it('should **not** return the escaped value if the value **is not** wrapped in regex', () => { const value = '/special/path'; const variableMock = queryBuilder().withId('tempVar').withName('tempVar').withMulti(false).build(); diff --git a/public/app/plugins/datasource/influxdb/datasource.ts b/public/app/plugins/datasource/influxdb/datasource.ts index daa4e18ae8b2..b3837a09871a 100644 --- a/public/app/plugins/datasource/influxdb/datasource.ts +++ b/public/app/plugins/datasource/influxdb/datasource.ts @@ -316,8 +316,8 @@ export default class InfluxDatasource extends DataSourceWithBackend Date: Fri, 15 Mar 2024 14:59:00 +0100 Subject: [PATCH 079/138] [v10.4.x] ExtSvcAccounts: FIX prevent service account deletion (#84511) * ExtSvcAccounts: FIX prevent service account deletion (#84502) * ExtSvcAccounts: Fix External Service Accounts Login check Co-authored-by: Karl Persson * Remove service accounts assignments and permissions on delete * Fix first set of tests * Fix second batch of tests * Fix third batch of tests --------- Co-authored-by: Karl Persson (cherry picked from commit 2795f9827a8a6e41e6fb6484e999e654fbaa4ea6) * ExtSvcAccounts: FIX tests that accidently depended on enterprise (#84535) * ExtSvcAccounts: FIX tests that accidently depended on enterprise * fix --------- Co-authored-by: Gabriel MABILLE Co-authored-by: Charandas --- pkg/services/extsvcauth/models.go | 3 +- .../serviceaccounts/database/store.go | 5 +- .../serviceaccounts/database/store_test.go | 18 ++-- .../extsvcaccounts/service_test.go | 4 +- .../serviceaccounts/manager/service.go | 7 +- .../serviceaccounts/manager/service_test.go | 4 +- .../serviceaccounts/manager/stats_test.go | 4 +- pkg/services/serviceaccounts/models.go | 2 + pkg/services/serviceaccounts/proxy/service.go | 2 +- .../serviceaccounts/proxy/service_test.go | 90 +++++++++---------- 10 files changed, 77 insertions(+), 62 deletions(-) diff --git a/pkg/services/extsvcauth/models.go b/pkg/services/extsvcauth/models.go index 717eb42f67eb..e35e103a1365 100644 --- a/pkg/services/extsvcauth/models.go +++ b/pkg/services/extsvcauth/models.go @@ -11,7 +11,8 @@ const ( ServiceAccounts AuthProvider = "ServiceAccounts" // TmpOrgID is the orgID we use while global service accounts are not supported. - TmpOrgID int64 = 1 + TmpOrgIDStr string = "1" + TmpOrgID int64 = 1 ) type AuthProvider string diff --git a/pkg/services/serviceaccounts/database/store.go b/pkg/services/serviceaccounts/database/store.go index ebb66ef48423..b99925c9978a 100644 --- a/pkg/services/serviceaccounts/database/store.go +++ b/pkg/services/serviceaccounts/database/store.go @@ -45,6 +45,9 @@ func ProvideServiceAccountsStore(cfg *setting.Cfg, store db.DB, apiKeyService ap // generateLogin makes a generated string to have a ID for the service account across orgs and it's name // this causes you to create a service account with the same name in different orgs // not the same name in the same org +// -- WARNING: +// -- if you change this function you need to change the ExtSvcLoginPrefix as well +// -- to make sure they are not considered as regular service accounts func generateLogin(prefix string, orgId int64, name string) string { generatedLogin := fmt.Sprintf("%v-%v-%v", prefix, orgId, strings.ToLower(name)) // in case the name has multiple spaces or dashes in the prefix or otherwise, replace them with a single dash @@ -331,7 +334,7 @@ func (s *ServiceAccountsStoreImpl) SearchOrgServiceAccounts(ctx context.Context, whereConditions = append( whereConditions, "login "+s.sqlStore.GetDialect().LikeStr()+" ?") - whereParams = append(whereParams, serviceaccounts.ServiceAccountPrefix+serviceaccounts.ExtSvcPrefix+"%") + whereParams = append(whereParams, serviceaccounts.ExtSvcLoginPrefix+"%") default: s.log.Warn("Invalid filter user for service account filtering", "service account search filtering", query.Filter) } diff --git a/pkg/services/serviceaccounts/database/store_test.go b/pkg/services/serviceaccounts/database/store_test.go index 42e8da777172..038971d33d05 100644 --- a/pkg/services/serviceaccounts/database/store_test.go +++ b/pkg/services/serviceaccounts/database/store_test.go @@ -447,14 +447,14 @@ func TestStore_MigrateAllApiKeys(t *testing.T) { } func TestServiceAccountsStoreImpl_SearchOrgServiceAccounts(t *testing.T) { initUsers := []tests.TestUser{ - {Name: "satest-1", Role: string(org.RoleViewer), Login: "sa-satest-1", IsServiceAccount: true}, + {Name: "satest-1", Role: string(org.RoleViewer), Login: "sa-1-satest-1", IsServiceAccount: true}, {Name: "usertest-2", Role: string(org.RoleEditor), Login: "usertest-2", IsServiceAccount: false}, - {Name: "satest-3", Role: string(org.RoleEditor), Login: "sa-satest-3", IsServiceAccount: true}, - {Name: "satest-4", Role: string(org.RoleAdmin), Login: "sa-satest-4", IsServiceAccount: true}, - {Name: "extsvc-test-5", Role: string(org.RoleNone), Login: "sa-extsvc-test-5", IsServiceAccount: true}, - {Name: "extsvc-test-6", Role: string(org.RoleNone), Login: "sa-extsvc-test-6", IsServiceAccount: true}, - {Name: "extsvc-test-7", Role: string(org.RoleNone), Login: "sa-extsvc-test-7", IsServiceAccount: true}, - {Name: "extsvc-test-8", Role: string(org.RoleNone), Login: "sa-extsvc-test-8", IsServiceAccount: true}, + {Name: "satest-3", Role: string(org.RoleEditor), Login: "sa-1-satest-3", IsServiceAccount: true}, + {Name: "satest-4", Role: string(org.RoleAdmin), Login: "sa-1-satest-4", IsServiceAccount: true}, + {Name: "extsvc-test-5", Role: string(org.RoleNone), Login: "sa-1-extsvc-test-5", IsServiceAccount: true}, + {Name: "extsvc-test-6", Role: string(org.RoleNone), Login: "sa-1-extsvc-test-6", IsServiceAccount: true}, + {Name: "extsvc-test-7", Role: string(org.RoleNone), Login: "sa-1-extsvc-test-7", IsServiceAccount: true}, + {Name: "extsvc-test-8", Role: string(org.RoleNone), Login: "sa-1-extsvc-test-8", IsServiceAccount: true}, } db, store := setupTestDatabase(t) @@ -522,10 +522,10 @@ func TestServiceAccountsStoreImpl_SearchOrgServiceAccounts(t *testing.T) { expectedCount: 4, }, { - desc: "should return service accounts with sa-satest login", + desc: "should return service accounts with sa-1-satest login", query: &serviceaccounts.SearchOrgServiceAccountsQuery{ OrgID: orgID, - Query: "sa-satest", + Query: "sa-1-satest", SignedInUser: userWithPerm, Filter: serviceaccounts.FilterIncludeAll, }, diff --git a/pkg/services/serviceaccounts/extsvcaccounts/service_test.go b/pkg/services/serviceaccounts/extsvcaccounts/service_test.go index 1624c71ed82d..e715dc49a20c 100644 --- a/pkg/services/serviceaccounts/extsvcaccounts/service_test.go +++ b/pkg/services/serviceaccounts/extsvcaccounts/service_test.go @@ -448,13 +448,13 @@ func TestExtSvcAccountsService_GetExternalServiceNames(t *testing.T) { sa1 := sa.ServiceAccountDTO{ Id: 1, Name: sa.ExtSvcPrefix + "sa-svc-1", - Login: sa.ServiceAccountPrefix + sa.ExtSvcPrefix + "sa-svc-1", + Login: sa.ExtSvcLoginPrefix + "sa-svc-1", OrgId: extsvcauth.TmpOrgID, } sa2 := sa.ServiceAccountDTO{ Id: 2, Name: sa.ExtSvcPrefix + "sa-svc-2", - Login: sa.ServiceAccountPrefix + sa.ExtSvcPrefix + "sa-svc-2", + Login: sa.ExtSvcLoginPrefix + "sa-svc-2", OrgId: extsvcauth.TmpOrgID, } tests := []struct { diff --git a/pkg/services/serviceaccounts/manager/service.go b/pkg/services/serviceaccounts/manager/service.go index 141e79e1a948..0f9f7a8fc68c 100644 --- a/pkg/services/serviceaccounts/manager/service.go +++ b/pkg/services/serviceaccounts/manager/service.go @@ -26,6 +26,7 @@ const ( ) type ServiceAccountsService struct { + acService accesscontrol.Service store store log log.Logger backgroundLog log.Logger @@ -54,6 +55,7 @@ func ProvideServiceAccountsService( orgService, ) s := &ServiceAccountsService{ + acService: accesscontrolService, store: serviceAccountsStore, log: log.New("serviceaccounts"), backgroundLog: log.New("serviceaccounts.background"), @@ -174,7 +176,10 @@ func (sa *ServiceAccountsService) DeleteServiceAccount(ctx context.Context, orgI if err := validServiceAccountID(serviceAccountID); err != nil { return err } - return sa.store.DeleteServiceAccount(ctx, orgID, serviceAccountID) + if err := sa.store.DeleteServiceAccount(ctx, orgID, serviceAccountID); err != nil { + return err + } + return sa.acService.DeleteUserPermissions(ctx, orgID, serviceAccountID) } func (sa *ServiceAccountsService) EnableServiceAccount(ctx context.Context, orgID, serviceAccountID int64, enable bool) error { diff --git a/pkg/services/serviceaccounts/manager/service_test.go b/pkg/services/serviceaccounts/manager/service_test.go index bf0633bf1eb3..c7175f480c87 100644 --- a/pkg/services/serviceaccounts/manager/service_test.go +++ b/pkg/services/serviceaccounts/manager/service_test.go @@ -4,6 +4,7 @@ import ( "context" "testing" + "github.com/grafana/grafana/pkg/services/accesscontrol/actest" "github.com/stretchr/testify/require" "github.com/grafana/grafana/pkg/infra/log" @@ -117,7 +118,8 @@ func (f *SecretsCheckerFake) CheckTokens(ctx context.Context) error { func TestProvideServiceAccount_DeleteServiceAccount(t *testing.T) { storeMock := newServiceAccountStoreFake() - svc := ServiceAccountsService{storeMock, log.New("test"), log.New("background.test"), &SecretsCheckerFake{}, false, 0} + acSvc := actest.FakeService{} + svc := ServiceAccountsService{acSvc, storeMock, log.New("test"), log.New("background.test"), &SecretsCheckerFake{}, false, 0} testOrgId := 1 t.Run("should create service account", func(t *testing.T) { diff --git a/pkg/services/serviceaccounts/manager/stats_test.go b/pkg/services/serviceaccounts/manager/stats_test.go index 3f9099a6f462..e85e9adb1291 100644 --- a/pkg/services/serviceaccounts/manager/stats_test.go +++ b/pkg/services/serviceaccounts/manager/stats_test.go @@ -4,6 +4,7 @@ import ( "context" "testing" + "github.com/grafana/grafana/pkg/services/accesscontrol/actest" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -12,8 +13,9 @@ import ( ) func Test_UsageStats(t *testing.T) { + acSvc := actest.FakeService{} storeMock := newServiceAccountStoreFake() - svc := ServiceAccountsService{storeMock, log.New("test"), log.New("background-test"), &SecretsCheckerFake{}, true, 5} + svc := ServiceAccountsService{acSvc, storeMock, log.New("test"), log.New("background-test"), &SecretsCheckerFake{}, true, 5} err := svc.DeleteServiceAccount(context.Background(), 1, 1) require.NoError(t, err) diff --git a/pkg/services/serviceaccounts/models.go b/pkg/services/serviceaccounts/models.go index 71b6aec6ac90..d83d298ea881 100644 --- a/pkg/services/serviceaccounts/models.go +++ b/pkg/services/serviceaccounts/models.go @@ -6,6 +6,7 @@ import ( "github.com/grafana/grafana/pkg/models/roletype" "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/auth/identity" + "github.com/grafana/grafana/pkg/services/extsvcauth" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/util/errutil" ) @@ -18,6 +19,7 @@ var ( const ( ServiceAccountPrefix = "sa-" ExtSvcPrefix = "extsvc-" + ExtSvcLoginPrefix = ServiceAccountPrefix + extsvcauth.TmpOrgIDStr + "-" + ExtSvcPrefix ) const ( diff --git a/pkg/services/serviceaccounts/proxy/service.go b/pkg/services/serviceaccounts/proxy/service.go index beabbd3d29c7..5b2a26f26391 100644 --- a/pkg/services/serviceaccounts/proxy/service.go +++ b/pkg/services/serviceaccounts/proxy/service.go @@ -187,5 +187,5 @@ func isNameValid(name string) bool { } func isExternalServiceAccount(login string) bool { - return strings.HasPrefix(login, serviceaccounts.ServiceAccountPrefix+serviceaccounts.ExtSvcPrefix) + return strings.HasPrefix(login, serviceaccounts.ExtSvcLoginPrefix) } diff --git a/pkg/services/serviceaccounts/proxy/service_test.go b/pkg/services/serviceaccounts/proxy/service_test.go index db0325a2172f..45e1875adef5 100644 --- a/pkg/services/serviceaccounts/proxy/service_test.go +++ b/pkg/services/serviceaccounts/proxy/service_test.go @@ -8,12 +8,12 @@ import ( "github.com/stretchr/testify/require" "github.com/grafana/grafana/pkg/infra/log" - "github.com/grafana/grafana/pkg/services/serviceaccounts" + sa "github.com/grafana/grafana/pkg/services/serviceaccounts" "github.com/grafana/grafana/pkg/services/serviceaccounts/extsvcaccounts" "github.com/grafana/grafana/pkg/services/serviceaccounts/tests" ) -var _ serviceaccounts.Service = (*tests.FakeServiceAccountService)(nil) +var _ sa.Service = (*tests.FakeServiceAccountService)(nil) func TestProvideServiceAccount_crudServiceAccount(t *testing.T) { testOrgId := int64(1) @@ -29,19 +29,19 @@ func TestProvideServiceAccount_crudServiceAccount(t *testing.T) { t.Run("should create service account", func(t *testing.T) { testCases := []struct { description string - form serviceaccounts.CreateServiceAccountForm + form sa.CreateServiceAccountForm expectedError error }{ { description: "should create service account and not return error", - form: serviceaccounts.CreateServiceAccountForm{ + form: sa.CreateServiceAccountForm{ Name: "my-service-account", }, expectedError: nil, }, { description: "should not allow to create a service account with extsvc prefix", - form: serviceaccounts.CreateServiceAccountForm{ + form: sa.CreateServiceAccountForm{ Name: "extsvc-my-service-account", }, expectedError: extsvcaccounts.ErrInvalidName, @@ -61,20 +61,20 @@ func TestProvideServiceAccount_crudServiceAccount(t *testing.T) { testCases := []struct { description string expectedError error - expectedServiceAccount *serviceaccounts.ServiceAccountProfileDTO + expectedServiceAccount *sa.ServiceAccountProfileDTO }{ { description: "should allow to delete a service account", expectedError: nil, - expectedServiceAccount: &serviceaccounts.ServiceAccountProfileDTO{ + expectedServiceAccount: &sa.ServiceAccountProfileDTO{ Login: "my-service-account", }, }, { - description: "should not allow to delete a service account with sa-extsvc prefix", + description: "should not allow to delete a service account with " + sa.ExtSvcLoginPrefix + " prefix", expectedError: extsvcaccounts.ErrCannotBeDeleted, - expectedServiceAccount: &serviceaccounts.ServiceAccountProfileDTO{ - Login: "sa-extsvc-my-service-account", + expectedServiceAccount: &sa.ServiceAccountProfileDTO{ + Login: sa.ExtSvcLoginPrefix + "my-service-account", }, }, } @@ -88,24 +88,24 @@ func TestProvideServiceAccount_crudServiceAccount(t *testing.T) { } }) - t.Run("should delete service account", func(t *testing.T) { + t.Run("should delete service account token", func(t *testing.T) { testCases := []struct { description string expectedError error - expectedServiceAccount *serviceaccounts.ServiceAccountProfileDTO + expectedServiceAccount *sa.ServiceAccountProfileDTO }{ { description: "should allow to delete a service account token", expectedError: nil, - expectedServiceAccount: &serviceaccounts.ServiceAccountProfileDTO{ + expectedServiceAccount: &sa.ServiceAccountProfileDTO{ Login: "my-service-account", }, }, { description: "should not allow to delete a external service account token", expectedError: extsvcaccounts.ErrCannotDeleteToken, - expectedServiceAccount: &serviceaccounts.ServiceAccountProfileDTO{ - Login: "sa-extsvc-my-service-account", + expectedServiceAccount: &sa.ServiceAccountProfileDTO{ + Login: sa.ExtSvcLoginPrefix + "my-service-account", }, }, } @@ -122,20 +122,20 @@ func TestProvideServiceAccount_crudServiceAccount(t *testing.T) { t.Run("should retrieve service account with IsExternal field", func(t *testing.T) { testCases := []struct { description string - expectedServiceAccount *serviceaccounts.ServiceAccountProfileDTO + expectedServiceAccount *sa.ServiceAccountProfileDTO expectedIsExternal bool }{ { description: "should not mark as external", - expectedServiceAccount: &serviceaccounts.ServiceAccountProfileDTO{ + expectedServiceAccount: &sa.ServiceAccountProfileDTO{ Login: "my-service-account", }, expectedIsExternal: false, }, { description: "should mark as external", - expectedServiceAccount: &serviceaccounts.ServiceAccountProfileDTO{ - Login: "sa-extsvc-my-service-account", + expectedServiceAccount: &sa.ServiceAccountProfileDTO{ + Login: sa.ExtSvcLoginPrefix + "my-service-account", }, expectedIsExternal: true, }, @@ -151,17 +151,17 @@ func TestProvideServiceAccount_crudServiceAccount(t *testing.T) { } }) - t.Run("should mark external service accounts correctly", func(t *testing.T) { - serviceMock.ExpectedSearchOrgServiceAccountsResult = &serviceaccounts.SearchOrgServiceAccountsResult{ + t.Run("should flag external service accounts correctly", func(t *testing.T) { + serviceMock.ExpectedSearchOrgServiceAccountsResult = &sa.SearchOrgServiceAccountsResult{ TotalCount: 2, - ServiceAccounts: []*serviceaccounts.ServiceAccountDTO{ + ServiceAccounts: []*sa.ServiceAccountDTO{ {Login: "test"}, - {Login: serviceaccounts.ServiceAccountPrefix + serviceaccounts.ExtSvcPrefix + "test"}, + {Login: sa.ExtSvcLoginPrefix + "test"}, }, Page: 1, PerPage: 2, } - res, err := svc.SearchOrgServiceAccounts(context.Background(), &serviceaccounts.SearchOrgServiceAccountsQuery{OrgID: 1}) + res, err := svc.SearchOrgServiceAccounts(context.Background(), &sa.SearchOrgServiceAccountsQuery{OrgID: 1}) require.Len(t, res.ServiceAccounts, 2) require.NoError(t, err) require.False(t, res.ServiceAccounts[0].IsExternal) @@ -173,47 +173,47 @@ func TestProvideServiceAccount_crudServiceAccount(t *testing.T) { nameWithProtectedPrefix := "extsvc-my-updated-service-account" testCases := []struct { description string - form serviceaccounts.UpdateServiceAccountForm - expectedServiceAccount *serviceaccounts.ServiceAccountProfileDTO + form sa.UpdateServiceAccountForm + expectedServiceAccount *sa.ServiceAccountProfileDTO expectedError error }{ { description: "should update a non-external service account with a valid name", - form: serviceaccounts.UpdateServiceAccountForm{ + form: sa.UpdateServiceAccountForm{ Name: &nameWithoutProtectedPrefix, }, - expectedServiceAccount: &serviceaccounts.ServiceAccountProfileDTO{ + expectedServiceAccount: &sa.ServiceAccountProfileDTO{ Login: "my-service-account", }, expectedError: nil, }, { description: "should not allow to update a non-external service account with extsvc prefix", - form: serviceaccounts.UpdateServiceAccountForm{ + form: sa.UpdateServiceAccountForm{ Name: &nameWithProtectedPrefix, }, - expectedServiceAccount: &serviceaccounts.ServiceAccountProfileDTO{ + expectedServiceAccount: &sa.ServiceAccountProfileDTO{ Login: "my-service-account", }, expectedError: extsvcaccounts.ErrInvalidName, }, { description: "should not allow to update an external service account with a valid name", - form: serviceaccounts.UpdateServiceAccountForm{ + form: sa.UpdateServiceAccountForm{ Name: &nameWithoutProtectedPrefix, }, - expectedServiceAccount: &serviceaccounts.ServiceAccountProfileDTO{ - Login: "sa-extsvc-my-service-account", + expectedServiceAccount: &sa.ServiceAccountProfileDTO{ + Login: sa.ExtSvcLoginPrefix + "my-service-account", }, expectedError: extsvcaccounts.ErrCannotBeUpdated, }, { description: "should not allow to update an external service account with a extsvc prefix", - form: serviceaccounts.UpdateServiceAccountForm{ + form: sa.UpdateServiceAccountForm{ Name: &nameWithProtectedPrefix, }, - expectedServiceAccount: &serviceaccounts.ServiceAccountProfileDTO{ - Login: "sa-extsvc-my-service-account", + expectedServiceAccount: &sa.ServiceAccountProfileDTO{ + Login: sa.ExtSvcLoginPrefix + "my-service-account", }, expectedError: extsvcaccounts.ErrInvalidName, }, @@ -232,27 +232,27 @@ func TestProvideServiceAccount_crudServiceAccount(t *testing.T) { t.Run("should add service account tokens", func(t *testing.T) { testCases := []struct { description string - cmd serviceaccounts.AddServiceAccountTokenCommand - expectedServiceAccount *serviceaccounts.ServiceAccountProfileDTO + cmd sa.AddServiceAccountTokenCommand + expectedServiceAccount *sa.ServiceAccountProfileDTO expectedError error }{ { description: "should allow to create a service account token", - cmd: serviceaccounts.AddServiceAccountTokenCommand{ + cmd: sa.AddServiceAccountTokenCommand{ OrgId: testOrgId, }, - expectedServiceAccount: &serviceaccounts.ServiceAccountProfileDTO{ + expectedServiceAccount: &sa.ServiceAccountProfileDTO{ Login: "my-service-account", }, expectedError: nil, }, { description: "should not allow to create a service account token", - cmd: serviceaccounts.AddServiceAccountTokenCommand{ + cmd: sa.AddServiceAccountTokenCommand{ OrgId: testOrgId, }, - expectedServiceAccount: &serviceaccounts.ServiceAccountProfileDTO{ - Login: "sa-extsvc-my-service-account", + expectedServiceAccount: &sa.ServiceAccountProfileDTO{ + Login: sa.ExtSvcLoginPrefix + "my-service-account", }, expectedError: extsvcaccounts.ErrCannotCreateToken, }, @@ -271,7 +271,7 @@ func TestProvideServiceAccount_crudServiceAccount(t *testing.T) { t.Run("should identify service account logins for being external or not", func(t *testing.T) { assert.False(t, isExternalServiceAccount("my-service-account")) assert.False(t, isExternalServiceAccount("sa-my-service-account")) - assert.False(t, isExternalServiceAccount("extsvc-my-service-account")) - assert.True(t, isExternalServiceAccount("sa-extsvc-my-service-account")) + assert.False(t, isExternalServiceAccount(sa.ExtSvcPrefix+"my-service-account")) // It's not a external service account login + assert.True(t, isExternalServiceAccount(sa.ExtSvcLoginPrefix+"my-service-account")) }) } From e258f2e4e1927fecf3185abf33bc3021a4a53096 Mon Sep 17 00:00:00 2001 From: ismail simsek Date: Fri, 15 Mar 2024 15:11:30 +0100 Subject: [PATCH 080/138] [v10.4.x] InfluxDB: Fix interpolation of multi value template variables by adding parenthesis around them (#84590) InfluxDB: Fix interpolation of multi value template variables by adding parenthesis around them (#83577) Put parenthesis around multi value template variable (cherry picked from commit 757fa06b85f8e1e9d416134e383fc15d7d521fa7) --- public/app/plugins/datasource/influxdb/datasource.test.ts | 6 +++--- public/app/plugins/datasource/influxdb/datasource.ts | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/public/app/plugins/datasource/influxdb/datasource.test.ts b/public/app/plugins/datasource/influxdb/datasource.test.ts index 5e20d38370a0..01f1ab2f7e65 100644 --- a/public/app/plugins/datasource/influxdb/datasource.test.ts +++ b/public/app/plugins/datasource/influxdb/datasource.test.ts @@ -452,7 +452,7 @@ describe('InfluxDataSource Frontend Mode', () => { .withIncludeAll(true) .build(); const result = ds.interpolateQueryExpr(value, variableMock, 'select from /^($tempVar)$/'); - const expectation = `env|env2|env3`; + const expectation = `(env|env2|env3)`; expect(result).toBe(expectation); }); @@ -476,7 +476,7 @@ describe('InfluxDataSource Frontend Mode', () => { const value = [`/special/path`, `/some/other/path`]; const variableMock = queryBuilder().withId('tempVar').withName('tempVar').withMulti().build(); const result = ds.interpolateQueryExpr(value, variableMock, `select that where path = '$tempVar'`); - const expectation = `\\/special\\/path|\\/some\\/other\\/path`; + const expectation = `(\\/special\\/path|\\/some\\/other\\/path)`; expect(result).toBe(expectation); }); @@ -505,7 +505,7 @@ describe('InfluxDataSource Frontend Mode', () => { .build(); const value = [`/special/path`, `/some/other/path`]; const result = ds.interpolateQueryExpr(value, variableMock, `select that where path = /$tempVar/`); - const expectation = `\\/special\\/path|\\/some\\/other\\/path`; + const expectation = `(\\/special\\/path|\\/some\\/other\\/path)`; expect(result).toBe(expectation); }); }); diff --git a/public/app/plugins/datasource/influxdb/datasource.ts b/public/app/plugins/datasource/influxdb/datasource.ts index b3837a09871a..d5be06528aac 100644 --- a/public/app/plugins/datasource/influxdb/datasource.ts +++ b/public/app/plugins/datasource/influxdb/datasource.ts @@ -309,7 +309,8 @@ export default class InfluxDatasource extends DataSourceWithBackend escapeRegex(v)).join('|'); + // then put inside parenthesis. + return `(${value.map((v) => escapeRegex(v)).join('|')})`; } // If the variable is not a multi-value variable @@ -324,7 +325,8 @@ export default class InfluxDatasource extends DataSourceWithBackend escapeRegex(v)).join('|'); + // then put inside parenthesis. + return `(${value.map((v) => escapeRegex(v)).join('|')})`; } return value; From 035e271bbf8e9e7082ce019abb394f6fac74ad66 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Fri, 15 Mar 2024 16:15:29 +0200 Subject: [PATCH 081/138] [v10.4.x] Service accounts: Same Org fix migration to account for duplicate entries (#84591) Service accounts: Same Org fix migration to account for duplicate entries (#84349) * bug: fix migration to account for duplicate entries * refactoring to create test folder for user migrations * fix migration log * added the migration * additional tests * added extSrv tests (cherry picked from commit 6c8895e349d3726826c4e0a3849bce7a030b89cb) Co-authored-by: Eric Leijonmarck --- ...ice_account_multiple_org_login_migrator.go | 68 +++++ .../user/test/service_account_test.go | 247 ++++++++++++++++++ .../migrations/user/test/user_test.go | 55 ++++ pkg/services/sqlstore/migrations/user_mig.go | 6 +- 4 files changed, 372 insertions(+), 4 deletions(-) create mode 100644 pkg/services/sqlstore/migrations/user/service_account_multiple_org_login_migrator.go create mode 100644 pkg/services/sqlstore/migrations/user/test/service_account_test.go create mode 100644 pkg/services/sqlstore/migrations/user/test/user_test.go diff --git a/pkg/services/sqlstore/migrations/user/service_account_multiple_org_login_migrator.go b/pkg/services/sqlstore/migrations/user/service_account_multiple_org_login_migrator.go new file mode 100644 index 000000000000..064985c0f73b --- /dev/null +++ b/pkg/services/sqlstore/migrations/user/service_account_multiple_org_login_migrator.go @@ -0,0 +1,68 @@ +package user + +import ( + "fmt" + + "github.com/grafana/grafana/pkg/services/sqlstore/migrator" + "xorm.io/xorm" +) + +const ( + AllowSameLoginCrossOrgs = "update login field with orgid to allow for multiple service accounts with same name across orgs" +) + +// Service accounts login were not unique per org. this migration is part of making it unique per org +// to be able to create service accounts that are unique per org +func AddServiceAccountsAllowSameLoginCrossOrgs(mg *migrator.Migrator) { + mg.AddMigration(AllowSameLoginCrossOrgs, &ServiceAccountsSameLoginCrossOrgs{}) +} + +var _ migrator.CodeMigration = new(ServiceAccountsSameLoginCrossOrgs) + +type ServiceAccountsSameLoginCrossOrgs struct { + sess *xorm.Session + dialect migrator.Dialect + migrator.MigrationBase +} + +func (p *ServiceAccountsSameLoginCrossOrgs) SQL(dialect migrator.Dialect) string { + return "code migration" +} + +func (p *ServiceAccountsSameLoginCrossOrgs) Exec(sess *xorm.Session, mg *migrator.Migrator) error { + p.sess = sess + p.dialect = mg.Dialect + var err error + switch p.dialect.DriverName() { + case migrator.Postgres: + _, err = p.sess.Exec(`UPDATE "user" + SET login = 'sa-' || org_id::text || '-' || + CASE + WHEN login LIKE 'sa-%' THEN SUBSTRING(login FROM 4) + ELSE login + END + WHERE login IS NOT NULL AND is_service_account = true;`, + ) + case migrator.MySQL: + _, err = p.sess.Exec(`UPDATE user + SET login = CONCAT('sa-', CAST(org_id AS CHAR), '-', + CASE + WHEN login LIKE 'sa-%' THEN SUBSTRING(login, 4) + ELSE login + END) + WHERE login IS NOT NULL AND is_service_account = 1;`, + ) + case migrator.SQLite: + _, err = p.sess.Exec(`Update ` + p.dialect.Quote("user") + ` + SET login = 'sa-' || CAST(org_id AS TEXT) || '-' || + CASE + WHEN SUBSTR(login, 1, 3) = 'sa-' THEN SUBSTR(login, 4) + ELSE login + END + WHERE login IS NOT NULL AND is_service_account = 1;`, + ) + default: + return fmt.Errorf("dialect not supported: %s", p.dialect) + } + return err +} diff --git a/pkg/services/sqlstore/migrations/user/test/service_account_test.go b/pkg/services/sqlstore/migrations/user/test/service_account_test.go new file mode 100644 index 000000000000..eab2f5ac4446 --- /dev/null +++ b/pkg/services/sqlstore/migrations/user/test/service_account_test.go @@ -0,0 +1,247 @@ +package test + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/grafana/grafana/pkg/infra/log" + usermig "github.com/grafana/grafana/pkg/services/sqlstore/migrations/user" + "github.com/grafana/grafana/pkg/services/sqlstore/migrator" + "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/setting" +) + +func TestIntegrationServiceAccountMigration(t *testing.T) { + // Run initial migration to have a working DB + x := setupTestDB(t) + + orgId := 1 + + type migrationTestCase struct { + desc string + serviceAccounts []*user.User + wantServiceAccounts []*user.User + } + testCases := []migrationTestCase{ + { + desc: "basic case", + serviceAccounts: []*user.User{ + { + ID: 1, + UID: "u1", + Name: "sa-basic", + Login: "sa-basic", + Email: "sa-basic", + OrgID: 1, + Created: now, + Updated: now, + IsServiceAccount: true, + }, + { + ID: 2, + UID: "u2", + Name: "sa-basic-admin", + Login: "sa-basic-admin", + Email: "sa-basic-admin", + OrgID: 1, + Created: now, + Updated: now, + IsServiceAccount: true, + }, + }, + wantServiceAccounts: []*user.User{ + { + ID: 1, + Login: fmt.Sprintf("sa-%d-basic", orgId), + }, + { + ID: 2, + Login: fmt.Sprintf("sa-%d-basic-admin", orgId), + }, + }, + }, + { + desc: "should be able to handle multiple sa", + serviceAccounts: []*user.User{ + { + ID: 3, + UID: "u3", + Name: "sa-doan", + Login: "sa-doan", + Email: "sa-doan", + OrgID: 1, + Created: now, + Updated: now, + IsServiceAccount: true, + }, + { + ID: 4, + UID: "u4", + Name: "sa-admin-doan", + Login: "sa-admin-doan", + Email: "sa-admin-doan", + OrgID: 1, + Created: now, + Updated: now, + IsServiceAccount: true, + }, + }, + wantServiceAccounts: []*user.User{ + { + ID: 3, + Login: fmt.Sprintf("sa-%d-doan", orgId), + }, + { + ID: 4, + Login: fmt.Sprintf("sa-%d-admin-doan", orgId), + }, + }, + }, + { + desc: "duplicate logins across different orgs", + serviceAccounts: []*user.User{ + { + ID: 5, + UID: "u5", + Name: "sa-common", + Login: "sa-common@org1.com", + Email: "sa-common@org1.com", + OrgID: 1, + Created: now, + Updated: now, + IsServiceAccount: true, + }, + { + ID: 6, + UID: "u6", + Name: "sa-common", + Login: "sa-common@org2.com", + Email: "sa-common@org2.com", + OrgID: 2, + Created: now, + Updated: now, + IsServiceAccount: true, + }, + }, + wantServiceAccounts: []*user.User{ + { + ID: 5, + Login: "sa-1-common@org1.com", + }, + { + ID: 6, + Login: "sa-2-common@org2.com", + }, + }, + }, + { + desc: "pre-existing sa- prefix", + serviceAccounts: []*user.User{ + { + ID: 7, + UID: "u7", + Name: "sa-preexisting", + Login: "sa-preexisting", + Email: "sa-preexisting@org.com", + OrgID: 1, + Created: now, + Updated: now, + IsServiceAccount: true, + }, + { + ID: 8, + UID: "u8", + Name: "sa-sa-preexisting", + Login: "sa-sa-preexisting", + Email: "sa-sa-preexisting@org.com", + OrgID: 1, + Created: now, + Updated: now, + IsServiceAccount: true, + }, + }, + wantServiceAccounts: []*user.User{ + { + ID: 7, + Login: "sa-1-preexisting", + }, + { + ID: 8, + Login: "sa-1-sa-preexisting", // Ensuring only the first 'sa-' is handled + }, + }, + }, + { + desc: "extSrv accounts also renamed", + serviceAccounts: []*user.User{ + { + ID: 9, + UID: "u9", + Name: "sa-extsvc-slug", + Login: "sa-extsvc-slug", + Email: "sa-extsvc-slug@org.com", + OrgID: 1, + Created: now, + Updated: now, + IsServiceAccount: true, + }, + { + ID: 10, + UID: "u10", + Name: "sa-extsvc-slug2", + Login: "sa-extsvc-slug2", + Email: "sa-extsvc-slug2@org.com", + OrgID: 2, + Created: now, + Updated: now, + IsServiceAccount: true, + }, + }, + wantServiceAccounts: []*user.User{ + { + ID: 9, + Login: "sa-1-extsvc-slug", + }, + { + ID: 10, + Login: "sa-2-extsvc-slug2", + }, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.desc, func(t *testing.T) { + // Remove migration and permissions + _, errDeleteMig := x.Exec(`DELETE FROM migration_log WHERE migration_id = ?`, usermig.AllowSameLoginCrossOrgs) + require.NoError(t, errDeleteMig) + + // insert service accounts + serviceAccoutsCount, err := x.Insert(tc.serviceAccounts) + require.NoError(t, err) + require.Equal(t, int64(len(tc.serviceAccounts)), serviceAccoutsCount) + + // run the migration + usermigrator := migrator.NewMigrator(x, &setting.Cfg{Logger: log.New("usermigration.test")}) + usermig.AddServiceAccountsAllowSameLoginCrossOrgs(usermigrator) + errRunningMig := usermigrator.Start(false, 0) + require.NoError(t, errRunningMig) + + // Check service accounts + resultingServiceAccounts := []user.User{} + err = x.Table("user").Find(&resultingServiceAccounts) + require.NoError(t, err) + + for i := range tc.wantServiceAccounts { + for _, sa := range resultingServiceAccounts { + if sa.ID == tc.wantServiceAccounts[i].ID { + assert.Equal(t, tc.wantServiceAccounts[i].Login, sa.Login) + } + } + } + }) + } +} diff --git a/pkg/services/sqlstore/migrations/user/test/user_test.go b/pkg/services/sqlstore/migrations/user/test/user_test.go new file mode 100644 index 000000000000..ab7b34e1287c --- /dev/null +++ b/pkg/services/sqlstore/migrations/user/test/user_test.go @@ -0,0 +1,55 @@ +package test + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/require" + "gopkg.in/ini.v1" + "xorm.io/xorm" + + "github.com/grafana/grafana/pkg/infra/log" + "github.com/grafana/grafana/pkg/services/sqlstore/migrations" + "github.com/grafana/grafana/pkg/services/sqlstore/migrator" + "github.com/grafana/grafana/pkg/services/sqlstore/sqlutil" + "github.com/grafana/grafana/pkg/setting" +) + +// Setup users +var ( + now = time.Now() +) + +func setupTestDB(t *testing.T) *xorm.Engine { + t.Helper() + dbType := sqlutil.GetTestDBType() + testDB, err := sqlutil.GetTestDB(dbType) + require.NoError(t, err) + + t.Cleanup(testDB.Cleanup) + + x, err := xorm.NewEngine(testDB.DriverName, testDB.ConnStr) + require.NoError(t, err) + + t.Cleanup(func() { + if err := x.Close(); err != nil { + fmt.Printf("failed to close xorm engine: %v", err) + } + }) + + err = migrator.NewDialect(x.DriverName()).CleanDB(x) + require.NoError(t, err) + + mg := migrator.NewMigrator(x, &setting.Cfg{ + Logger: log.New("users.test"), + Raw: ini.Empty(), + }) + migrations := &migrations.OSSMigrations{} + migrations.AddMigration(mg) + + err = mg.Start(false, 0) + require.NoError(t, err) + + return x +} diff --git a/pkg/services/sqlstore/migrations/user_mig.go b/pkg/services/sqlstore/migrations/user_mig.go index bac9f99bf118..77ed12e5876a 100644 --- a/pkg/services/sqlstore/migrations/user_mig.go +++ b/pkg/services/sqlstore/migrations/user_mig.go @@ -5,6 +5,7 @@ import ( "xorm.io/xorm" + "github.com/grafana/grafana/pkg/services/sqlstore/migrations/user" . "github.com/grafana/grafana/pkg/services/sqlstore/migrator" "github.com/grafana/grafana/pkg/util" ) @@ -156,10 +157,7 @@ func addUserMigrations(mg *Migrator) { // Service accounts login were not unique per org. this migration is part of making it unique per org // to be able to create service accounts that are unique per org - mg.AddMigration("Update login field for service accounts", NewRawSQLMigration(""). - SQLite("UPDATE user SET login = 'sa-' || CAST(org_id AS TEXT) || '-' || REPLACE(login, 'sa-', '') WHERE login IS NOT NULL AND is_service_account = 1;"). - Postgres("UPDATE \"user\" SET login = 'sa-' || org_id::text || '-' || REPLACE(login, 'sa-', '') WHERE login IS NOT NULL AND is_service_account = true;"). - Mysql("UPDATE user SET login = CONCAT('sa-', CAST(org_id AS CHAR), '-', REPLACE(login, 'sa-', '')) WHERE login IS NOT NULL AND is_service_account = 1;")) + mg.AddMigration(user.AllowSameLoginCrossOrgs, &user.ServiceAccountsSameLoginCrossOrgs{}) } const migSQLITEisServiceAccountNullable = `ALTER TABLE user ADD COLUMN tmp_service_account BOOLEAN DEFAULT 0; From 2fb6deb115dbc4c2a79f3f7c2d60854495f69481 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Fri, 15 Mar 2024 17:05:03 +0200 Subject: [PATCH 082/138] [v10.4.x] Alerting: Fix optional fields requiring validation rule (#84595) Alerting: Fix optional fields requiring validation rule (#84584) fixes #84296 (cherry picked from commit 85bd116a1071b71d290487112e5532487f256781) Co-authored-by: Gilles De Mey --- .../receivers/form/fields/OptionField.tsx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/public/app/features/alerting/unified/components/receivers/form/fields/OptionField.tsx b/public/app/features/alerting/unified/components/receivers/form/fields/OptionField.tsx index 02384e0c63cf..e5058dca9b94 100644 --- a/public/app/features/alerting/unified/components/receivers/form/fields/OptionField.tsx +++ b/public/app/features/alerting/unified/components/receivers/form/fields/OptionField.tsx @@ -122,7 +122,8 @@ const OptionInput: FC = ({ {...register(name, { required: determineRequired(option, getValues, pathIndex), validate: { - validationRule: (v) => (option.validationRule ? validateOption(v, option.validationRule) : true), + validationRule: (v) => + option.validationRule ? validateOption(v, option.validationRule, option.required) : true, customValidator: (v) => (customValidator ? customValidator(v) : true), }, setValueAs: option.setValueAs, @@ -167,7 +168,8 @@ const OptionInput: FC = ({ rules={{ required: option.required ? 'Option is required' : false, validate: { - validationRule: (v) => (option.validationRule ? validateOption(v, option.validationRule) : true), + validationRule: (v) => + option.validationRule ? validateOption(v, option.validationRule, option.required) : true, customValidator: (v) => (customValidator ? customValidator(v) : true), }, }} @@ -183,7 +185,8 @@ const OptionInput: FC = ({ placeholder={option.placeholder} {...register(name, { required: option.required ? 'Required' : false, - validate: (v) => (option.validationRule !== '' ? validateOption(v, option.validationRule) : true), + validate: (v) => + option.validationRule !== '' ? validateOption(v, option.validationRule, option.required) : true, })} /> ); @@ -223,7 +226,11 @@ const getStyles = (theme: GrafanaTheme2) => ({ `, }); -const validateOption = (value: string, validationRule: string) => { +const validateOption = (value: string, validationRule: string, required: boolean) => { + if (value === '' && !required) { + return true; + } + return RegExp(validationRule).test(value) ? true : 'Invalid format'; }; From de5b771270e1f036d6f7babd76442b33d85ea79b Mon Sep 17 00:00:00 2001 From: Pepe Cano <825430+ppcano@users.noreply.github.com> Date: Fri, 15 Mar 2024 16:24:12 +0100 Subject: [PATCH 083/138] [v10.4.x] Alerting docs: Fix broken links in TF Provisioning page (#84580) --- .../terraform-provisioning/index.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/sources/alerting/set-up/provision-alerting-resources/terraform-provisioning/index.md b/docs/sources/alerting/set-up/provision-alerting-resources/terraform-provisioning/index.md index c215c625ace6..78f7d1e3704c 100644 --- a/docs/sources/alerting/set-up/provision-alerting-resources/terraform-provisioning/index.md +++ b/docs/sources/alerting/set-up/provision-alerting-resources/terraform-provisioning/index.md @@ -393,17 +393,17 @@ For more examples on the concept of this guide: [alerting-rules]: "/docs/grafana/ -> /docs/grafana//alerting/alerting-rules" [alerting-rules]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/alerting-rules" -[contact-points]: "/docs/grafana/ -> /docs/grafana//alerting/configure-notifications/manage-contact-points" -[contact-points]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/configure-notifications/manage-contact-points" +[contact-points]: "/docs/grafana/ -> /docs/grafana//alerting/manage-notifications/manage-contact-points" +[contact-points]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/manage-notifications/manage-contact-points" -[mute-timings]: "/docs/grafana/ -> /docs/grafana//alerting/configure-notifications/mute-timings" -[mute-timings]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/configure-notifications/mute-timings" +[mute-timings]: "/docs/grafana/ -> /docs/grafana//alerting/manage-notifications/mute-timings" +[mute-timings]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/manage-notifications/mute-timings" -[notification-policy]: "/docs/grafana/ -> /docs/grafana//alerting/configure-notifications/create-notification-policy" -[notification-policy]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/configure-notifications/create-notification-policy" +[notification-policy]: "/docs/grafana/ -> /docs/grafana//alerting/alerting-rules/create-notification-policy" +[notification-policy]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/alerting-rules/create-notification-policy" -[notification-template]: "/docs/grafana/ -> /docs/grafana//alerting/configure-notifications/template-notifications" -[notification-template]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/configure-notifications/template-notifications" +[notification-template]: "/docs/grafana/ -> /docs/grafana//alerting/manage-notifications/template-notifications" +[notification-template]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/manage-notifications/template-notifications" [alerting_export]: "/docs/grafana/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/export-alerting-resources" [alerting_export]: "/docs/grafana-cloud/ -> /docs/grafana//alerting/set-up/provision-alerting-resources/export-alerting-resources" From 591cb82b90edd7d3f01c70e61b26464b47bcddc1 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Fri, 15 Mar 2024 18:59:14 +0200 Subject: [PATCH 084/138] [v10.4.x] Alerting/Annotations: Prevent panics from composite store jobs from crashing Grafana (#84596) Alerting/Annotations: Prevent panics from composite store jobs from crashing Grafana (#83459) * Don't directly use pointer to json * Don't crash entire process if a store job panics * Add debug logs when failing to parse/handle Loki entries (cherry picked from commit af528d2f660cc34c8b6e057d81a7c627166686c7) Co-authored-by: William Wernert --- .../annotationsimpl/annotations.go | 2 +- .../annotationsimpl/composite_store.go | 37 ++++++++++++-- .../annotationsimpl/composite_store_test.go | 48 +++++++++++++++++-- .../annotationsimpl/loki/historian_store.go | 10 ++++ .../loki/historian_store_test.go | 18 ++++++- .../annotations/annotationsimpl/store.go | 6 +++ .../annotations/annotationsimpl/xorm_store.go | 4 ++ 7 files changed, 116 insertions(+), 9 deletions(-) diff --git a/pkg/services/annotations/annotationsimpl/annotations.go b/pkg/services/annotations/annotationsimpl/annotations.go index f9640a51e976..3cf88288d270 100644 --- a/pkg/services/annotations/annotationsimpl/annotations.go +++ b/pkg/services/annotations/annotationsimpl/annotations.go @@ -38,7 +38,7 @@ func ProvideService( historianStore := loki.NewLokiHistorianStore(cfg.UnifiedAlerting.StateHistory, features, db, log.New("annotations.loki")) if historianStore != nil { l.Debug("Using composite read store") - read = NewCompositeStore(xormStore, historianStore) + read = NewCompositeStore(log.New("annotations.composite"), xormStore, historianStore) } else { l.Debug("Using xorm read store") read = write diff --git a/pkg/services/annotations/annotationsimpl/composite_store.go b/pkg/services/annotations/annotationsimpl/composite_store.go index 4db6e1c9ece2..3bcf0724b52d 100644 --- a/pkg/services/annotations/annotationsimpl/composite_store.go +++ b/pkg/services/annotations/annotationsimpl/composite_store.go @@ -2,8 +2,11 @@ package annotationsimpl import ( "context" + "fmt" "sort" + "github.com/grafana/grafana/pkg/infra/log" + "github.com/grafana/dskit/concurrency" "github.com/grafana/grafana/pkg/services/annotations" "github.com/grafana/grafana/pkg/services/annotations/accesscontrol" @@ -11,20 +14,29 @@ import ( // CompositeStore is a read store that combines two or more read stores, and queries all stores in parallel. type CompositeStore struct { + logger log.Logger readers []readStore } -func NewCompositeStore(readers ...readStore) *CompositeStore { +func NewCompositeStore(logger log.Logger, readers ...readStore) *CompositeStore { return &CompositeStore{ + logger: logger, readers: readers, } } +// Satisfy the commonStore interface, in practice this is not used. +func (c *CompositeStore) Type() string { + return "composite" +} + // Get returns annotations from all stores, and combines the results. func (c *CompositeStore) Get(ctx context.Context, query *annotations.ItemQuery, accessResources *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error) { itemCh := make(chan []*annotations.ItemDTO, len(c.readers)) - err := concurrency.ForEachJob(ctx, len(c.readers), len(c.readers), func(ctx context.Context, i int) error { + err := concurrency.ForEachJob(ctx, len(c.readers), len(c.readers), func(ctx context.Context, i int) (err error) { + defer handleJobPanic(c.logger, c.readers[i].Type(), &err) + items, err := c.readers[i].Get(ctx, query, accessResources) itemCh <- items return err @@ -47,7 +59,9 @@ func (c *CompositeStore) Get(ctx context.Context, query *annotations.ItemQuery, func (c *CompositeStore) GetTags(ctx context.Context, query *annotations.TagsQuery) (annotations.FindTagsResult, error) { resCh := make(chan annotations.FindTagsResult, len(c.readers)) - err := concurrency.ForEachJob(ctx, len(c.readers), len(c.readers), func(ctx context.Context, i int) error { + err := concurrency.ForEachJob(ctx, len(c.readers), len(c.readers), func(ctx context.Context, i int) (err error) { + defer handleJobPanic(c.logger, c.readers[i].Type(), &err) + res, err := c.readers[i].GetTags(ctx, query) resCh <- res return err @@ -65,3 +79,20 @@ func (c *CompositeStore) GetTags(ctx context.Context, query *annotations.TagsQue return annotations.FindTagsResult{Tags: res}, nil } + +// handleJobPanic is a helper function that recovers from a panic in a concurrent job., +// It will log the error and set the job error if it is not nil. +func handleJobPanic(logger log.Logger, storeType string, jobErr *error) { + if r := recover(); r != nil { + logger.Error("Annotation store panic", "error", r, "store", storeType, "stack", log.Stack(1)) + errMsg := "concurrent job panic" + + if jobErr != nil { + err := fmt.Errorf(errMsg) + if panicErr, ok := r.(error); ok { + err = fmt.Errorf("%s: %w", errMsg, panicErr) + } + *jobErr = err + } + } +} diff --git a/pkg/services/annotations/annotationsimpl/composite_store_test.go b/pkg/services/annotations/annotationsimpl/composite_store_test.go index e7800d5dbdc3..b5aa1d22d8c2 100644 --- a/pkg/services/annotations/annotationsimpl/composite_store_test.go +++ b/pkg/services/annotations/annotationsimpl/composite_store_test.go @@ -7,6 +7,7 @@ import ( "testing" "time" + "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/services/annotations" "github.com/grafana/grafana/pkg/services/annotations/accesscontrol" "github.com/stretchr/testify/require" @@ -18,6 +19,22 @@ var ( ) func TestCompositeStore(t *testing.T) { + t.Run("should handle panic", func(t *testing.T) { + r1 := newFakeReader() + getPanic := func(context.Context, *annotations.ItemQuery, *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error) { + panic("ohno") + } + r2 := newFakeReader(withGetFn(getPanic)) + store := &CompositeStore{ + log.NewNopLogger(), + []readStore{r1, r2}, + } + + _, err := store.Get(context.Background(), nil, nil) + require.Error(t, err) + require.Contains(t, err.Error(), "concurrent job panic") + }) + t.Run("should return first error", func(t *testing.T) { err1 := errors.New("error 1") r1 := newFakeReader(withError(err1)) @@ -25,6 +42,7 @@ func TestCompositeStore(t *testing.T) { r2 := newFakeReader(withError(err2), withWait(10*time.Millisecond)) store := &CompositeStore{ + log.NewNopLogger(), []readStore{r1, r2}, } @@ -64,6 +82,7 @@ func TestCompositeStore(t *testing.T) { r2 := newFakeReader(withItems(items2)) store := &CompositeStore{ + log.NewNopLogger(), []readStore{r1, r2}, } @@ -92,6 +111,7 @@ func TestCompositeStore(t *testing.T) { r2 := newFakeReader(withTags(tags2)) store := &CompositeStore{ + log.NewNopLogger(), []readStore{r1, r2}, } @@ -108,13 +128,23 @@ func TestCompositeStore(t *testing.T) { } type fakeReader struct { - items []*annotations.ItemDTO - tagRes annotations.FindTagsResult - wait time.Duration - err error + items []*annotations.ItemDTO + tagRes annotations.FindTagsResult + getFn func(context.Context, *annotations.ItemQuery, *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error) + getTagFn func(context.Context, *annotations.TagsQuery) (annotations.FindTagsResult, error) + wait time.Duration + err error +} + +func (f *fakeReader) Type() string { + return "fake" } func (f *fakeReader) Get(ctx context.Context, query *annotations.ItemQuery, accessResources *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error) { + if f.getFn != nil { + return f.getFn(ctx, query, accessResources) + } + if f.wait > 0 { time.Sleep(f.wait) } @@ -128,6 +158,10 @@ func (f *fakeReader) Get(ctx context.Context, query *annotations.ItemQuery, acce } func (f *fakeReader) GetTags(ctx context.Context, query *annotations.TagsQuery) (annotations.FindTagsResult, error) { + if f.getTagFn != nil { + return f.getTagFn(ctx, query) + } + if f.wait > 0 { time.Sleep(f.wait) } @@ -164,6 +198,12 @@ func withTags(tags []*annotations.TagsDTO) func(*fakeReader) { } } +func withGetFn(fn func(context.Context, *annotations.ItemQuery, *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error)) func(*fakeReader) { + return func(f *fakeReader) { + f.getFn = fn + } +} + func newFakeReader(opts ...func(*fakeReader)) *fakeReader { f := &fakeReader{} for _, opt := range opts { diff --git a/pkg/services/annotations/annotationsimpl/loki/historian_store.go b/pkg/services/annotations/annotationsimpl/loki/historian_store.go index 451375b5212e..3d12623bd025 100644 --- a/pkg/services/annotations/annotationsimpl/loki/historian_store.go +++ b/pkg/services/annotations/annotationsimpl/loki/historian_store.go @@ -69,6 +69,10 @@ func NewLokiHistorianStore(cfg setting.UnifiedAlertingStateHistorySettings, ft f } } +func (r *LokiHistorianStore) Type() string { + return "loki" +} + func (r *LokiHistorianStore) Get(ctx context.Context, query *annotations.ItemQuery, accessResources *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error) { if query.Type == "annotation" { return make([]*annotations.ItemDTO, 0), nil @@ -124,6 +128,7 @@ func (r *LokiHistorianStore) annotationsFromStream(stream historian.Stream, ac a err := json.Unmarshal([]byte(sample.V), &entry) if err != nil { // bad data, skip + r.log.Debug("failed to unmarshal loki entry", "error", err, "entry", sample.V) continue } @@ -135,6 +140,7 @@ func (r *LokiHistorianStore) annotationsFromStream(stream historian.Stream, ac a transition, err := buildTransition(entry) if err != nil { // bad data, skip + r.log.Debug("failed to build transition", "error", err, "entry", entry) continue } @@ -207,6 +213,10 @@ type number interface { // numericMap converts a simplejson map[string]any to a map[string]N, where N is numeric (int or float). func numericMap[N number](j *simplejson.Json) (map[string]N, error) { + if j == nil { + return nil, fmt.Errorf("unexpected nil value") + } + m, err := j.Map() if err != nil { return nil, err diff --git a/pkg/services/annotations/annotationsimpl/loki/historian_store_test.go b/pkg/services/annotations/annotationsimpl/loki/historian_store_test.go index 1123a7bbddc9..6ed3933de888 100644 --- a/pkg/services/annotations/annotationsimpl/loki/historian_store_test.go +++ b/pkg/services/annotations/annotationsimpl/loki/historian_store_test.go @@ -374,7 +374,23 @@ func TestHasAccess(t *testing.T) { }) } -func TestFloat64Map(t *testing.T) { +func TestNumericMap(t *testing.T) { + t.Run("should return error for nil value", func(t *testing.T) { + var jsonMap *simplejson.Json + _, err := numericMap[float64](jsonMap) + require.Error(t, err) + require.Contains(t, err.Error(), "unexpected nil value") + }) + + t.Run("should return error for nil interface value", func(t *testing.T) { + jsonMap := simplejson.NewFromAny(map[string]any{ + "key1": nil, + }) + _, err := numericMap[float64](jsonMap) + require.Error(t, err) + require.Contains(t, err.Error(), "unexpected value type") + }) + t.Run(`should convert json string:float kv to Golang map[string]float64`, func(t *testing.T) { jsonMap := simplejson.NewFromAny(map[string]any{ "key1": json.Number("1.0"), diff --git a/pkg/services/annotations/annotationsimpl/store.go b/pkg/services/annotations/annotationsimpl/store.go index 1a3d39914161..b1c3643a9c35 100644 --- a/pkg/services/annotations/annotationsimpl/store.go +++ b/pkg/services/annotations/annotationsimpl/store.go @@ -14,12 +14,18 @@ type store interface { writeStore } +type commonStore interface { + Type() string +} + type readStore interface { + commonStore Get(ctx context.Context, query *annotations.ItemQuery, accessResources *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error) GetTags(ctx context.Context, query *annotations.TagsQuery) (annotations.FindTagsResult, error) } type writeStore interface { + commonStore Add(ctx context.Context, items *annotations.Item) error AddMany(ctx context.Context, items []annotations.Item) error Update(ctx context.Context, item *annotations.Item) error diff --git a/pkg/services/annotations/annotationsimpl/xorm_store.go b/pkg/services/annotations/annotationsimpl/xorm_store.go index a9edcebbee24..6ae9ddc3ce1b 100644 --- a/pkg/services/annotations/annotationsimpl/xorm_store.go +++ b/pkg/services/annotations/annotationsimpl/xorm_store.go @@ -54,6 +54,10 @@ func NewXormStore(cfg *setting.Cfg, l log.Logger, db db.DB, tagService tag.Servi } } +func (r *xormRepositoryImpl) Type() string { + return "sql" +} + func (r *xormRepositoryImpl) Add(ctx context.Context, item *annotations.Item) error { tags := tag.ParseTagPairs(item.Tags) item.Tags = tag.JoinTagPairs(tags) From 1e4235c106ed2630bd8ad68ffec30a6e9fe82196 Mon Sep 17 00:00:00 2001 From: Serge Zaitsev Date: Mon, 18 Mar 2024 11:45:30 +0100 Subject: [PATCH 085/138] [v10.4.x] Chore: Fix changelog for v10.4.0 (#84554) Fix changelog for v10.4.0 --- CHANGELOG.md | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40968f165c6f..9c6ef0d987ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,6 @@ ### Features and enhancements -- **Chore:** Improve domain validation for Google OAuth - Backport 83229 to v10.4.x. [#83726](https://github.com/grafana/grafana/issues/83726), [@linoman](https://github.com/linoman) -- **DataQuery:** Track panel plugin id not type. [#83164](https://github.com/grafana/grafana/issues/83164), [@torkelo](https://github.com/torkelo) - **AuthToken:** Remove client token rotation feature toggle. [#82886](https://github.com/grafana/grafana/issues/82886), [@kalleep](https://github.com/kalleep) - **Plugins:** Enable feature toggle angularDeprecationUI by default. [#82880](https://github.com/grafana/grafana/issues/82880), [@xnyo](https://github.com/xnyo) - **Table Component:** Improve text-wrapping behavior of cells. [#82872](https://github.com/grafana/grafana/issues/82872), [@ahuarte47](https://github.com/ahuarte47) @@ -134,15 +132,6 @@ ### Bug fixes -- **GenAI:** Update the component only when the response is fully generated. [#83895](https://github.com/grafana/grafana/issues/83895), [@ivanortegaalba](https://github.com/ivanortegaalba) -- **LDAP:** Fix LDAP users authenticated via auth proxy not being able to use LDAP active sync. [#83751](https://github.com/grafana/grafana/issues/83751), [@Jguer](https://github.com/Jguer) -- **Tempo:** Better fallbacks for metrics query. [#83688](https://github.com/grafana/grafana/issues/83688), [@adrapereira](https://github.com/adrapereira) -- **Tempo:** Add template variable interpolation for filters. [#83667](https://github.com/grafana/grafana/issues/83667), [@joey-grafana](https://github.com/joey-grafana) -- **Elasticsearch:** Fix adhoc filters not applied in frontend mode. [#83597](https://github.com/grafana/grafana/issues/83597), [@svennergr](https://github.com/svennergr) -- **AuthProxy:** Invalidate previous cached item for user when changes are made to any header. [#83287](https://github.com/grafana/grafana/issues/83287), [@klesh](https://github.com/klesh) -- **Alerting:** Fix saving evaluation group. [#83234](https://github.com/grafana/grafana/issues/83234), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron) -- **QueryVariableEditor:** Select a variable ds does not work. [#83181](https://github.com/grafana/grafana/issues/83181), [@ivanortegaalba](https://github.com/ivanortegaalba) -- **Logs Panel:** Add option extra UI functionality for log context. [#83129](https://github.com/grafana/grafana/issues/83129), [@svennergr](https://github.com/svennergr) - **Auth:** Fix email verification bypass when using basic authentication. [#82914](https://github.com/grafana/grafana/issues/82914), [@volcanonoodle](https://github.com/volcanonoodle) - **LibraryPanels/RBAC:** Fix issue where folder scopes weren't being correctly inherited. [#82700](https://github.com/grafana/grafana/issues/82700), [@kaydelaney](https://github.com/kaydelaney) - **Table Panel:** Fix display of ad-hoc filter actions. [#82442](https://github.com/grafana/grafana/issues/82442), [@codeincarnate](https://github.com/codeincarnate) From d8c067486566373205a63ddc5995a402df750a0a Mon Sep 17 00:00:00 2001 From: Kim Nylander <104772500+knylander-grafana@users.noreply.github.com> Date: Mon, 18 Mar 2024 15:15:05 -0400 Subject: [PATCH 086/138] [DOC] V10.4 loki query tempo deprecate (#84326) * Add Loki query deprecation notice to Tempo data source * Update docs/sources/datasources/tempo/query-editor/_index.md Co-authored-by: Larissa Wandzura <126723338+lwandz13@users.noreply.github.com> * Changes from prettier --------- Co-authored-by: Larissa Wandzura <126723338+lwandz13@users.noreply.github.com> --- docs/sources/datasources/tempo/query-editor/_index.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/sources/datasources/tempo/query-editor/_index.md b/docs/sources/datasources/tempo/query-editor/_index.md index dbbadb651f70..c88b8f9b5a79 100644 --- a/docs/sources/datasources/tempo/query-editor/_index.md +++ b/docs/sources/datasources/tempo/query-editor/_index.md @@ -101,6 +101,10 @@ To query a particular trace: ## Query Loki for traces +{{< admonition type="caution" >}} +Starting with Grafana v11.0, the Loki query tab will no longer be available. +{{< /admonition >}} + To find traces to visualize, you can use the [Loki query editor]({{< relref "../../loki#loki-query-editor" >}}). For results, you must configure [derived fields]({{< relref "../../loki#configure-derived-fields" >}}) in the Loki data source that point to this data source. From 80ac64c5409cee2afd0510679c2de33d3994abad Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Tue, 19 Mar 2024 12:22:33 -0400 Subject: [PATCH 087/138] [v10.4.x] docs: initial updates to state timeline documentation (#84758) docs: initial updates to state timeline documentation (#84224) * docs: initial updates to state timeline documentation * docs: apply linting * Apply suggestions from code review Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> * docs: add feedback from PR review * docs: apply linting * Wording and formatting edits * Fixed grammar * Update docs/sources/panels-visualizations/visualizations/state-timeline/index.md Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> * docs: add two examples for state timeline to show null values and two timestamps * docs: add steps to configuring a state timeline * docs: add state timeline video * docs: add link to creating dashboards * Changed link text and added version interpolation syntax --------- Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> (cherry picked from commit 2f539060f8f0d8413fa06c0ddfc26a4f5064d8f7) Co-authored-by: Marie Cruz --- .../visualizations/state-timeline/index.md | 67 ++++++++++++++++++- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/docs/sources/panels-visualizations/visualizations/state-timeline/index.md b/docs/sources/panels-visualizations/visualizations/state-timeline/index.md index b7cf7ff472c2..add92e9968f8 100644 --- a/docs/sources/panels-visualizations/visualizations/state-timeline/index.md +++ b/docs/sources/panels-visualizations/visualizations/state-timeline/index.md @@ -19,9 +19,72 @@ weight: 100 # State timeline -State timelines show discrete state changes over time. Each field or series is rendered as its unique horizontal band. State regions can either be rendered with or without values. This visualization works well with string or boolean states but can also be used with time series. When used with time series, the thresholds are used to turn the numerical values into discrete state regions. +A state timeline visualization displays data in a way that shows state changes over time. In a state timeline, the data is presented as a series of bars or bands called _state regions_. State regions can be rendered with or without values, and the region length indicates the duration or frequency of a state within a given time range. -{{< figure src="/static/img/docs/v8/state_timeline_strings.png" max-width="1025px" caption="state timeline with string states" >}} +For example, if you're monitoring the CPU usage of a server, you can use a state timeline to visualize the different states, such as “LOW,” “NORMAL,” “HIGH,” or “CRITICAL,” over time. Each state is represented by a different color and the lengths represent the duration of time that the server remained in that state: + +{{< figure src="/static/img/docs/state-timeline-panel/state-timeline-panel.png" max-width="1025px" alt="A state timeline panel showing CPU usage" >}} + +The state timeline visualization is useful when you need to monitor and analyze changes in states or statuses of various entities over time. You can use one when you need to: + +- Monitor the status of a server, application, or service to know when your infrastructure is experiencing issues over time. +- Identify operational trends over time. +- Spot any recurring issues with the health of your applications. + +## Configure a state timeline + +Once you have [created a dashboard](https://grafana.com/docs/grafana//dashboards/build-dashboards/create-dashboard/), the following video shows you how to configure a state timeline: + +{{< youtube id="a9wZHM0mdxo" >}} + +## Supported data formats + +The state timeline panel works best if you have data capturing the various states of entities over time, formatted as a table. The data must include: + +- **Timestamps** - Indicate when each state change occurred. This could also be the start time for the state change. You can also add an optional timestamp to indicate the end time for the state change. +- **Entity name/identifier** - Represents the name of the entity you're trying to monitor. +- **State value** - Represents the state value of the entity you're monitoring. These can be string, numerical, or boolean states. + +Each state ends when the next state begins or when there is a `null` value. + +### Examples + +The following tables are examples of the type of data you need for a state timeline visualization and how it should be formatted. + +#### Single time column with null values + +| Timestamps | Server A | Server B | +| ------------------- | -------- | -------- | +| 2024-02-29 8:00:00 | Up | Up | +| 2024-02-29 8:15:00 | null | Up | +| 2024-02-29 8:30:00 | Down | null | +| 2024-02-29 8:45:00 | | Up | +| 2024-02-29 9:00:00 | Up | | +| 2024-02-29 9:15:00 | Up | Down | +| 2024-02-29 9:30:00 | Up | Down | +| 2024-02-29 10:00:00 | Down | Down | +| 2024-02-29 10:30:00 | Warning | Down | + +The data is converted as follows, with the [null and empty values visualized as gaps](https://grafana.com/docs/grafana/latest/panels-visualizations/visualizations/state-timeline/#connect-null-values) in the state timeline: + +{{< figure src="/static/img/docs/state-timeline-panel/state-timeline-with-null-values.png" max-width="1025px" alt="A state timeline panel with null values showing the status of two servers" >}} + +#### Two time columns without null values + +| Start time | End time | Server A | Server B | +| ------------------- | ------------------- | -------- | -------- | +| 2024-02-29 8:00:00 | 2024-02-29 8:15:00 | Up | Up | +| 2024-02-29 8:15:00 | 2024-02-29 8:30:00 | Up | Up | +| 2024-02-29 8:45:00 | 2024-02-29 9:00:00 | Down | Up | +| 2024-02-29 9:00:00 | 2024-02-29 9:15:00 | Down | Up | +| 2024-02-29 9:30:00 | 2024-02-29 10:00:00 | Down | Down | +| 2024-02-29 10:00:00 | 2024-02-29 10:30:00 | Warning | Down | + +The data is converted as follows: + +{{< figure src="/static/img/docs/state-timeline-panel/state-timeline-with-two-timestamps.png" max-width="1025px" alt="A state timeline panel with two time columns showing the status of two servers" >}} + +If your query results aren't in a table format like the preceding examples, especially for time-series data, you can apply specific [transformations](https://stackoverflow.com/questions/68887416/grafana-state-timeline-panel-with-values-states-supplied-by-label) to achieve this. ## State timeline options From c17383d40b82a7fca95542b28c2fd4b419d06d3e Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Tue, 19 Mar 2024 13:50:45 -0400 Subject: [PATCH 088/138] [v10.4.x] Visualizations-TablePanel: added YouTube link to Table Panel (#84771) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Visualizations-TablePanel: added YouTube link to Table Panel (#84533) * Update index.md added YouTube link to Table Panel * Moved video and added placement note * Update index.md adding video description Added a description to the video. Feel free to edit if my syntax or writing needs improvement. * Wording and style edits * Wording fix --------- Co-authored-by: Isabel Matwawana Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> (cherry picked from commit e011c60a759e7e42bd58f705d0fe1478a73603d9) Co-authored-by: Señor Performo - Leandro Melendez <54183040+srperf@users.noreply.github.com> --- .../panels-visualizations/visualizations/table/index.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/sources/panels-visualizations/visualizations/table/index.md b/docs/sources/panels-visualizations/visualizations/table/index.md index 8c0c66cb4801..94821e4eaf35 100644 --- a/docs/sources/panels-visualizations/visualizations/table/index.md +++ b/docs/sources/panels-visualizations/visualizations/table/index.md @@ -31,6 +31,10 @@ Tables are very flexible, supporting multiple modes for time series and for tabl {{< figure src="/static/img/docs/tables/table_visualization.png" max-width="1200px" lightbox="true" caption="Table visualization" >}} +The following video provides a visual walkthrough of the options you can set in a table visualization. If you want to see a configuration in action, check out the video: + +{{< youtube id="PCY7O8EJeJY" >}} + ## Annotation and alert support Annotations and alerts are not currently supported in tables. From d486fa87ab70d991f3ab5600c2b14c243a8dcb61 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 20 Mar 2024 15:03:06 +0100 Subject: [PATCH 089/138] [v10.4.x] Elasticsearch: Fix legend for alerting, expressions and previously frontend queries (#84685) * Elasticsearch: Fix legend for alerting, expressions and previously frontend queries (#84485) * Elasticsearch: Fix legend for alerting, expressions and previously frontend queries * Add comment * Update comment (cherry picked from commit 494d1699805ab603ccd9ef2f6ba7d28caa975088) * Pass correct param to NewClient (this is not needed on main) --------- Co-authored-by: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com> Co-authored-by: Ivana Huckova --- pkg/tsdb/elasticsearch/data_query.go | 23 ++-- pkg/tsdb/elasticsearch/data_query_test.go | 2 +- pkg/tsdb/elasticsearch/elasticsearch.go | 20 +-- pkg/tsdb/elasticsearch/querydata_test.go | 5 +- pkg/tsdb/elasticsearch/response_parser.go | 22 ++-- .../elasticsearch/response_parser_test.go | 116 ++++++++++++++---- 6 files changed, 138 insertions(+), 50 deletions(-) diff --git a/pkg/tsdb/elasticsearch/data_query.go b/pkg/tsdb/elasticsearch/data_query.go index 57f4fc9c1537..6bf91365eb78 100644 --- a/pkg/tsdb/elasticsearch/data_query.go +++ b/pkg/tsdb/elasticsearch/data_query.go @@ -23,20 +23,27 @@ const ( ) type elasticsearchDataQuery struct { - client es.Client - dataQueries []backend.DataQuery - logger log.Logger - ctx context.Context - tracer tracing.Tracer + client es.Client + dataQueries []backend.DataQuery + logger log.Logger + ctx context.Context + tracer tracing.Tracer + keepLabelsInResponse bool } -var newElasticsearchDataQuery = func(ctx context.Context, client es.Client, dataQuery []backend.DataQuery, logger log.Logger, tracer tracing.Tracer) *elasticsearchDataQuery { +var newElasticsearchDataQuery = func(ctx context.Context, client es.Client, req *backend.QueryDataRequest, logger log.Logger, tracer tracing.Tracer) *elasticsearchDataQuery { + _, fromAlert := req.Headers[headerFromAlert] + fromExpression := req.GetHTTPHeader(headerFromExpression) != "" + return &elasticsearchDataQuery{ client: client, - dataQueries: dataQuery, + dataQueries: req.Queries, logger: logger, ctx: ctx, tracer: tracer, + // To maintain backward compatibility, it is necessary to keep labels in responses for alerting and expressions queries. + // Historically, these labels have been used in alerting rules and transformations. + keepLabelsInResponse: fromAlert || fromExpression, } } @@ -77,7 +84,7 @@ func (e *elasticsearchDataQuery) execute() (*backend.QueryDataResponse, error) { return errorsource.AddErrorToResponse(e.dataQueries[0].RefID, response, err), nil } - return parseResponse(e.ctx, res.Responses, queries, e.client.GetConfiguredFields(), e.logger, e.tracer) + return parseResponse(e.ctx, res.Responses, queries, e.client.GetConfiguredFields(), e.keepLabelsInResponse, e.logger, e.tracer) } func (e *elasticsearchDataQuery) processQuery(q *Query, ms *es.MultiSearchRequestBuilder, from, to int64) error { diff --git a/pkg/tsdb/elasticsearch/data_query_test.go b/pkg/tsdb/elasticsearch/data_query_test.go index bded5d6071da..17381d29d910 100644 --- a/pkg/tsdb/elasticsearch/data_query_test.go +++ b/pkg/tsdb/elasticsearch/data_query_test.go @@ -1862,6 +1862,6 @@ func executeElasticsearchDataQuery(c es.Client, body string, from, to time.Time) }, }, } - query := newElasticsearchDataQuery(context.Background(), c, dataRequest.Queries, log.New("test.logger"), tracing.InitializeTracerForTest()) + query := newElasticsearchDataQuery(context.Background(), c, &dataRequest, log.New("test.logger"), tracing.InitializeTracerForTest()) return query.execute() } diff --git a/pkg/tsdb/elasticsearch/elasticsearch.go b/pkg/tsdb/elasticsearch/elasticsearch.go index b15b725cd3ff..bc9138c65769 100644 --- a/pkg/tsdb/elasticsearch/elasticsearch.go +++ b/pkg/tsdb/elasticsearch/elasticsearch.go @@ -24,12 +24,18 @@ import ( "github.com/grafana/grafana/pkg/infra/httpclient" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/tracing" - ngalertmodels "github.com/grafana/grafana/pkg/services/ngalert/models" es "github.com/grafana/grafana/pkg/tsdb/elasticsearch/client" ) var eslog = log.New("tsdb.elasticsearch") +const ( + // headerFromExpression is used by data sources to identify expression queries + headerFromExpression = "X-Grafana-From-Expr" + // headerFromAlert is used by datasources to identify alert queries + headerFromAlert = "FromAlert" +) + type Service struct { httpClientProvider httpclient.Provider im instancemgmt.InstanceManager @@ -48,7 +54,7 @@ func ProvideService(httpClientProvider httpclient.Provider, tracer tracing.Trace func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { dsInfo, err := s.getDSInfo(ctx, req.PluginContext) - _, fromAlert := req.Headers[ngalertmodels.FromAlertHeaderName] + _, fromAlert := req.Headers[headerFromAlert] logger := s.logger.FromContext(ctx).New("fromAlert", fromAlert) if err != nil { @@ -56,20 +62,20 @@ func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest) return &backend.QueryDataResponse{}, err } - return queryData(ctx, req.Queries, dsInfo, logger, s.tracer) + return queryData(ctx, req, dsInfo, logger, s.tracer) } // separate function to allow testing the whole transformation and query flow -func queryData(ctx context.Context, queries []backend.DataQuery, dsInfo *es.DatasourceInfo, logger log.Logger, tracer tracing.Tracer) (*backend.QueryDataResponse, error) { - if len(queries) == 0 { +func queryData(ctx context.Context, req *backend.QueryDataRequest, dsInfo *es.DatasourceInfo, logger log.Logger, tracer tracing.Tracer) (*backend.QueryDataResponse, error) { + if len(req.Queries) == 0 { return &backend.QueryDataResponse{}, fmt.Errorf("query contains no queries") } - client, err := es.NewClient(ctx, dsInfo, queries[0].TimeRange, logger, tracer) + client, err := es.NewClient(ctx, dsInfo, req.Queries[0].TimeRange, logger, tracer) if err != nil { return &backend.QueryDataResponse{}, err } - query := newElasticsearchDataQuery(ctx, client, queries, logger, tracer) + query := newElasticsearchDataQuery(ctx, client, req, logger, tracer) return query.execute() } diff --git a/pkg/tsdb/elasticsearch/querydata_test.go b/pkg/tsdb/elasticsearch/querydata_test.go index 7a559b68fb47..d3e7d1f2af4c 100644 --- a/pkg/tsdb/elasticsearch/querydata_test.go +++ b/pkg/tsdb/elasticsearch/querydata_test.go @@ -114,6 +114,9 @@ type queryDataTestResult struct { func queryDataTestWithResponseCode(queriesBytes []byte, responseStatusCode int, responseBytes []byte) (queryDataTestResult, error) { queries, err := newFlowTestQueries(queriesBytes) + req := backend.QueryDataRequest{ + Queries: queries, + } if err != nil { return queryDataTestResult{}, err } @@ -138,7 +141,7 @@ func queryDataTestWithResponseCode(queriesBytes []byte, responseStatusCode int, return nil }) - result, err := queryData(context.Background(), queries, dsInfo, log.New("test.logger"), tracing.InitializeTracerForTest()) + result, err := queryData(context.Background(), &req, dsInfo, log.New("test.logger"), tracing.InitializeTracerForTest()) if err != nil { return queryDataTestResult{}, err } diff --git a/pkg/tsdb/elasticsearch/response_parser.go b/pkg/tsdb/elasticsearch/response_parser.go index 3bb69e8a1532..822a655fb325 100644 --- a/pkg/tsdb/elasticsearch/response_parser.go +++ b/pkg/tsdb/elasticsearch/response_parser.go @@ -47,7 +47,7 @@ const ( var searchWordsRegex = regexp.MustCompile(regexp.QuoteMeta(es.HighlightPreTagsString) + `(.*?)` + regexp.QuoteMeta(es.HighlightPostTagsString)) -func parseResponse(ctx context.Context, responses []*es.SearchResponse, targets []*Query, configuredFields es.ConfiguredFields, logger log.Logger, tracer tracing.Tracer) (*backend.QueryDataResponse, error) { +func parseResponse(ctx context.Context, responses []*es.SearchResponse, targets []*Query, configuredFields es.ConfiguredFields, keepLabelsInResponse bool, logger log.Logger, tracer tracing.Tracer) (*backend.QueryDataResponse, error) { result := backend.QueryDataResponse{ Responses: backend.Responses{}, } @@ -117,7 +117,7 @@ func parseResponse(ctx context.Context, responses []*es.SearchResponse, targets resSpan.End() return &backend.QueryDataResponse{}, err } - nameFields(queryRes, target) + nameFields(queryRes, target, keepLabelsInResponse) trimDatapoints(queryRes, target) result.Responses[target.RefID] = queryRes @@ -888,7 +888,7 @@ func getSortedLabelValues(labels data.Labels) []string { return values } -func nameFields(queryResult backend.DataResponse, target *Query) { +func nameFields(queryResult backend.DataResponse, target *Query, keepLabelsInResponse bool) { set := make(map[string]struct{}) frames := queryResult.Frames for _, v := range frames { @@ -907,10 +907,18 @@ func nameFields(queryResult backend.DataResponse, target *Query) { // another is "number" valueField := frame.Fields[1] fieldName := getFieldName(*valueField, target, metricTypeCount) - // We need to remove labels so they are not added to legend as duplicates - // ensures backward compatibility with "frontend" version of the plugin - valueField.Labels = nil - frame.Name = fieldName + // If we need to keep the labels in the response, to prevent duplication in names and to keep + // backward compatibility with alerting and expressions we use DisplayNameFromDS + if keepLabelsInResponse { + if valueField.Config == nil { + valueField.Config = &data.FieldConfig{} + } + valueField.Config.DisplayNameFromDS = fieldName + // If we don't need to keep labels (how frontend mode worked), we use frame.Name and remove labels + } else { + valueField.Labels = nil + frame.Name = fieldName + } } } } diff --git a/pkg/tsdb/elasticsearch/response_parser_test.go b/pkg/tsdb/elasticsearch/response_parser_test.go index 6f928655f903..2fc85276f7a0 100644 --- a/pkg/tsdb/elasticsearch/response_parser_test.go +++ b/pkg/tsdb/elasticsearch/response_parser_test.go @@ -330,7 +330,7 @@ func TestProcessLogsResponse(t *testing.T) { ] }` - result, err := parseTestResponse(targets, response) + result, err := parseTestResponse(targets, response, false) require.NoError(t, err) require.Len(t, result.Responses, 1) @@ -417,7 +417,7 @@ func TestProcessLogsResponse(t *testing.T) { ] }` - result, err := parseTestResponse(targets, response) + result, err := parseTestResponse(targets, response, false) require.NoError(t, err) require.Len(t, result.Responses, 1) @@ -525,7 +525,7 @@ func TestProcessRawDataResponse(t *testing.T) { ] }` - result, err := parseTestResponse(targets, response) + result, err := parseTestResponse(targets, response, false) require.NoError(t, err) require.Len(t, result.Responses, 1) @@ -814,7 +814,7 @@ func TestProcessRawDocumentResponse(t *testing.T) { ] }` - result, err := parseTestResponse(targets, response) + result, err := parseTestResponse(targets, response, false) require.NoError(t, err) require.Len(t, result.Responses, 1) @@ -995,7 +995,7 @@ func TestProcessBuckets(t *testing.T) { } ] }` - result, err := parseTestResponse(targets, response) + result, err := parseTestResponse(targets, response, false) require.NoError(t, err) require.Len(t, result.Responses, 1) @@ -1097,7 +1097,7 @@ func TestProcessBuckets(t *testing.T) { } ] }` - result, err := parseTestResponse(targets, response) + result, err := parseTestResponse(targets, response, false) require.NoError(t, err) require.Len(t, result.Responses, 1) @@ -1160,7 +1160,7 @@ func TestProcessBuckets(t *testing.T) { } ] }` - result, err := parseTestResponse(targets, response) + result, err := parseTestResponse(targets, response, false) require.NoError(t, err) require.Len(t, result.Responses, 1) @@ -1233,7 +1233,7 @@ func TestProcessBuckets(t *testing.T) { }] }` - result, err := parseTestResponse(targets, response) + result, err := parseTestResponse(targets, response, false) assert.Nil(t, err) assert.Len(t, result.Responses, 1) frames := result.Responses["A"].Frames @@ -1464,7 +1464,7 @@ func TestProcessBuckets(t *testing.T) { } }] }` - result, err := parseTestResponse(targets, response) + result, err := parseTestResponse(targets, response, false) assert.Nil(t, err) assert.Len(t, result.Responses, 1) @@ -1551,7 +1551,7 @@ func TestProcessBuckets(t *testing.T) { }] }` - result, err := parseTestResponse(targets, response) + result, err := parseTestResponse(targets, response, false) assert.Nil(t, err) assert.Len(t, result.Responses, 1) frames := result.Responses["A"].Frames @@ -1749,7 +1749,7 @@ func TestProcessBuckets(t *testing.T) { } ] }` - result, err := parseTestResponse(targets, response) + result, err := parseTestResponse(targets, response, false) require.NoError(t, err) queryRes := result.Responses["A"] @@ -1775,6 +1775,70 @@ func TestProcessBuckets(t *testing.T) { assert.Equal(t, frame.Name, "server2") }) + t.Run("Single group by query one metric with true keepLabelsInResponse", func(t *testing.T) { + targets := map[string]string{ + "A": `{ + "metrics": [{ "type": "count", "id": "1" }], + "bucketAggs": [ + { "type": "terms", "field": "host", "id": "2" }, + { "type": "date_histogram", "field": "@timestamp", "id": "3" } + ] + }`, + } + response := `{ + "responses": [ + { + "aggregations": { + "2": { + "buckets": [ + { + "3": { + "buckets": [{ "doc_count": 1, "key": 1000 }, { "doc_count": 3, "key": 2000 }] + }, + "doc_count": 4, + "key": "server1" + }, + { + "3": { + "buckets": [{ "doc_count": 2, "key": 1000 }, { "doc_count": 8, "key": 2000 }] + }, + "doc_count": 10, + "key": "server2" + } + ] + } + } + } + ] + }` + result, err := parseTestResponse(targets, response, true) + require.NoError(t, err) + + queryRes := result.Responses["A"] + require.NotNil(t, queryRes) + dataframes := queryRes.Frames + require.NoError(t, err) + require.Len(t, dataframes, 2) + + frame := dataframes[0] + require.Len(t, frame.Fields, 2) + require.Equal(t, frame.Fields[0].Name, data.TimeSeriesTimeFieldName) + require.Equal(t, frame.Fields[0].Len(), 2) + require.Equal(t, frame.Fields[1].Name, data.TimeSeriesValueFieldName) + require.Equal(t, frame.Fields[1].Len(), 2) + require.Equal(t, frame.Fields[1].Labels, data.Labels{"host": "server1"}) + assert.Equal(t, frame.Fields[1].Config.DisplayNameFromDS, "server1") + + frame = dataframes[1] + require.Len(t, frame.Fields, 2) + require.Equal(t, frame.Fields[0].Name, data.TimeSeriesTimeFieldName) + require.Equal(t, frame.Fields[0].Len(), 2) + require.Equal(t, frame.Fields[1].Name, data.TimeSeriesValueFieldName) + require.Equal(t, frame.Fields[1].Len(), 2) + require.Equal(t, frame.Fields[1].Labels, data.Labels{"host": "server2"}) + assert.Equal(t, frame.Fields[1].Config.DisplayNameFromDS, "server2") + }) + t.Run("Single group by query two metrics", func(t *testing.T) { targets := map[string]string{ "A": `{ @@ -1817,7 +1881,7 @@ func TestProcessBuckets(t *testing.T) { } ] }` - result, err := parseTestResponse(targets, response) + result, err := parseTestResponse(targets, response, false) require.NoError(t, err) require.Len(t, result.Responses, 1) @@ -1969,7 +2033,7 @@ func TestProcessBuckets(t *testing.T) { } ] }` - result, err := parseTestResponse(targets, response) + result, err := parseTestResponse(targets, response, false) require.NoError(t, err) require.Len(t, result.Responses, 1) @@ -2142,7 +2206,7 @@ func TestProcessBuckets(t *testing.T) { } ] }` - result, err := parseTestResponse(targets, response) + result, err := parseTestResponse(targets, response, false) require.NoError(t, err) require.Len(t, result.Responses, 1) @@ -2274,7 +2338,7 @@ func TestProcessBuckets(t *testing.T) { } ] }` - result, err := parseTestResponse(targets, response) + result, err := parseTestResponse(targets, response, false) require.NoError(t, err) require.Len(t, result.Responses, 1) @@ -2322,7 +2386,7 @@ func TestProcessBuckets(t *testing.T) { } ] }` - result, err := parseTestResponse(targets, response) + result, err := parseTestResponse(targets, response, false) require.NoError(t, err) require.Len(t, result.Responses, 1) @@ -2384,7 +2448,7 @@ func TestProcessBuckets(t *testing.T) { } ] }` - result, err := parseTestResponse(targets, response) + result, err := parseTestResponse(targets, response, false) require.NoError(t, err) require.Len(t, result.Responses, 1) @@ -2506,7 +2570,7 @@ func TestProcessBuckets(t *testing.T) { } ] }` - result, err := parseTestResponse(targets, response) + result, err := parseTestResponse(targets, response, false) require.NoError(t, err) require.Len(t, result.Responses, 1) @@ -2609,7 +2673,7 @@ func TestProcessBuckets(t *testing.T) { } ] }` - result, err := parseTestResponse(targets, response) + result, err := parseTestResponse(targets, response, false) require.NoError(t, err) require.Len(t, result.Responses, 1) @@ -2659,7 +2723,7 @@ func TestProcessBuckets(t *testing.T) { } ] }` - result, err := parseTestResponse(targets, response) + result, err := parseTestResponse(targets, response, false) require.NoError(t, err) require.Len(t, result.Responses, 1) @@ -2721,7 +2785,7 @@ func TestProcessBuckets(t *testing.T) { } ] }` - result, err := parseTestResponse(targets, response) + result, err := parseTestResponse(targets, response, false) require.NoError(t, err) require.Len(t, result.Responses, 1) @@ -2789,7 +2853,7 @@ func TestProcessBuckets(t *testing.T) { } ] }` - result, err := parseTestResponse(targets, response) + result, err := parseTestResponse(targets, response, false) require.NoError(t, err) require.Len(t, result.Responses, 1) @@ -2853,7 +2917,7 @@ func TestProcessBuckets(t *testing.T) { } ] }` - result, err := parseTestResponse(targets, response) + result, err := parseTestResponse(targets, response, false) require.NoError(t, err) require.Len(t, result.Responses, 1) @@ -2907,7 +2971,7 @@ func TestProcessBuckets(t *testing.T) { } ] }` - result, err := parseTestResponse(targets, response) + result, err := parseTestResponse(targets, response, false) require.NoError(t, err) require.Len(t, result.Responses, 1) @@ -3583,7 +3647,7 @@ func TestTrimEdges(t *testing.T) { requireFrameLength(t, frames[0], 1) } -func parseTestResponse(tsdbQueries map[string]string, responseBody string) (*backend.QueryDataResponse, error) { +func parseTestResponse(tsdbQueries map[string]string, responseBody string, keepLabelsInResponse bool) (*backend.QueryDataResponse, error) { from := time.Date(2018, 5, 15, 17, 50, 0, 0, time.UTC) to := time.Date(2018, 5, 15, 17, 55, 0, 0, time.UTC) configuredFields := es.ConfiguredFields{ @@ -3618,7 +3682,7 @@ func parseTestResponse(tsdbQueries map[string]string, responseBody string) (*bac return nil, err } - return parseResponse(context.Background(), response.Responses, queries, configuredFields, log.New("test.logger"), tracing.InitializeTracerForTest()) + return parseResponse(context.Background(), response.Responses, queries, configuredFields, keepLabelsInResponse, log.New("test.logger"), tracing.InitializeTracerForTest()) } func requireTimeValue(t *testing.T, expected int64, frame *data.Frame, index int) { From d3ce857c0eb86f571ffa993a9cd8493b6f47b630 Mon Sep 17 00:00:00 2001 From: Pepe Cano <825430+ppcano@users.noreply.github.com> Date: Wed, 20 Mar 2024 15:29:54 +0100 Subject: [PATCH 090/138] [v10.4.x] alerting docs: slack integration (#84823) Alerting docs: Fix format issues on `Configure Slack` guide Co-authored-by: tonypowa <45235678+tonypowa@users.noreply.github.com> --- .../integrations/configure-slack.md | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 docs/sources/alerting/alerting-rules/manage-contact-points/integrations/configure-slack.md diff --git a/docs/sources/alerting/alerting-rules/manage-contact-points/integrations/configure-slack.md b/docs/sources/alerting/alerting-rules/manage-contact-points/integrations/configure-slack.md new file mode 100644 index 000000000000..0b19f5992b4d --- /dev/null +++ b/docs/sources/alerting/alerting-rules/manage-contact-points/integrations/configure-slack.md @@ -0,0 +1,93 @@ +--- +canonical: https://grafana.com/docs/grafana/latest/alerting/configure-notifications/manage-contact-points/integrations/configure-slack/ +description: Configure the Slack integration to connect alerts generated by Grafana Alerting +keywords: + - grafana + - alerting + - slack + - integration +labels: + products: + - cloud + - enterprise + - oss +menuTitle: Slack +title: Configure Slack for Alerting +weight: 300 +--- + +## Configure Slack for Alerting + +Use the Grafana Alerting - Slack integration to send Slack notifications when your alerts are firing. + +There are two ways of integrating Slack into Grafana Alerting. + +1. Use a [Slack API token](https://api.slack.com/authentication/token-types) + + Enable your app to access the Slack API. If, for example, you are interested in more granular control over permissions, or your project is expected to regularly scale, resulting in new channels being created, this is the best option. + +1. Use a [Webhook URL](https://api.slack.com/messaging/webhooks) + + Webhooks is the simpler way to post messages into Slack. Slack automatically creates a bot user with all the necessary permissions to post messages to one particular channel of your choice. + +{{< admonition type="note" >}} +Grafana Alerting only allows one Slack channel per contact point. +{{< /admonition >}} + +## Before you begin + +### Slack API Token + +If you are using a Slack API Token, complete the following steps. + +1. Follow steps 1 and 2 of the [Slack API Quickstart](https://api.slack.com/start/quickstart). +1. Add the [chat:write.public](https://api.slack.com/scopes/chat:write.public) scope to give your app the ability to post in all public channels without joining. +1. In OAuth Tokens for Your Workspace, copy the Bot User OAuth Token. +1. Open your Slack workplace. +1. Right click the channel you want to receive notifications in. +1. Click View channel details. +1. Scroll down and copy the Channel ID. + {{< admonition type="note" >}} + While going through these steps, Slack may prompt you to Reinstall your app in order for the changes to take effect. + {{< /admonition >}} + +### Webhook URL + +If you are using a Webhook URL, follow steps 1 and 5 in the [Slack API Quickstart](https://api.slack.com/start/quickstart). + +{{< admonition type="note" >}} +Make sure you copy the Slack app Webhook URL. You will need this when setting up your contact point integration in Grafana Alerting. +{{< /admonition >}} + +## Procedure + +To create your Slack integration in Grafana Alerting, complete the following steps. + +1. Navigate to Alerts&IRM -> Alerting -> Contact points. +1. Click **+ Add contact point**. +1. Enter a contact point name. +1. From the Integration list, select Slack. +1. If you are using a Slack API token: + - In the **Recipient** field, copy in the channel ID. + - In the **Token** field, copy in the Bot User OAuth Token that starts with “xoxb-”. +1. If you are using a Webhook URL, in the **Webhook** field, copy in your Slack app Webhook URL. +1. Click **Test** to check that your integration works. +1. Click **Save contact point**. + +## Next steps + +To add the contact point and integration you created to your default notification policy, complete the following steps. + +1. Navigate to **Alerts&IRM** -> **Alerting** -> **Notification policies**. +1. In the **Default policy**, click the ellipsis icon (…) and then **Edit**, +1. Change the default policy to the contact point you created. +1. Click **Update default policy**. + +**Note:** +If you have more than one contact point, add a new notification policy rather than edit the default one, so you can route specific alerts to Slack. For more information, refer to [Notification policies][nested-policy]. + +{{% docs/reference %}} +[nested-policy]: "/docs/grafana/ -> /docs/grafana//alerting/alerting-rules/create-notification-policy#add-new-nested-policy" + +[nested-policy]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/configure-notifications/create-notification-policy#add-new-nested-policy" +{{% /docs/reference %}} From 04f6c66e91dd0c0132fc0c2792747e50b044cb1f Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 20 Mar 2024 17:06:53 -0400 Subject: [PATCH 091/138] [v10.4.x] Alerting: Marshal incoming json.RawMessage in diff (#84853) Alerting: Marshal incoming json.RawMessage in diff (#84692) This will ensure the encoding is correct when comparing to the existing rule. (cherry picked from commit 6d16cf2699102363c1d0867a58866a57cd198d1f) Co-authored-by: William Wernert --- pkg/services/ngalert/models/alert_rule.go | 6 +++++- pkg/services/ngalert/models/alert_rule_test.go | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/pkg/services/ngalert/models/alert_rule.go b/pkg/services/ngalert/models/alert_rule.go index 320d29386b55..d28ff8ecb705 100644 --- a/pkg/services/ngalert/models/alert_rule.go +++ b/pkg/services/ngalert/models/alert_rule.go @@ -346,7 +346,11 @@ func (alertRule *AlertRule) Diff(rule *AlertRule, ignore ...string) cmputil.Diff // json.RawMessage is a slice of bytes and therefore cmp's default behavior is to compare it by byte, which is not really useful var jsonCmp = cmp.Transformer("", func(in json.RawMessage) string { - return string(in) + b, err := json.Marshal(in) + if err != nil { + return string(in) + } + return string(b) }) ops = append( ops, diff --git a/pkg/services/ngalert/models/alert_rule_test.go b/pkg/services/ngalert/models/alert_rule_test.go index 32836ba4d672..22d2f65a9e67 100644 --- a/pkg/services/ngalert/models/alert_rule_test.go +++ b/pkg/services/ngalert/models/alert_rule_test.go @@ -656,6 +656,21 @@ func TestDiff(t *testing.T) { } }) + t.Run("should correctly detect no change with '<' and '>' in query", func(t *testing.T) { + old := query1 + new := query1 + old.Model = json.RawMessage(`{"field1": "$A \u003c 1"}`) + new.Model = json.RawMessage(`{"field1": "$A < 1"}`) + rule1.Data = []AlertQuery{old} + rule2.Data = []AlertQuery{new} + + diff := rule1.Diff(rule2) + assert.Nil(t, diff) + + // reset rule1 + rule1.Data = []AlertQuery{query1} + }) + t.Run("should detect new changes in array if too many fields changed", func(t *testing.T) { query2 := query1 query2.QueryType = "test" From d94d597d847c05085542c29dfad6b3f469cc77e1 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 21 Mar 2024 09:24:59 +0100 Subject: [PATCH 092/138] [v10.4.x] Docs: Specify `Recorded queries` is available in `Grafana Cloud` (#84878) Docs: Specify `Recorded queries` is available in `Grafana Cloud` (#84716) (cherry picked from commit 60b9a1058a3f235cf70a51e841a6b6c4eb6e16da) Co-authored-by: Pepe Cano <825430+ppcano@users.noreply.github.com> --- docs/sources/administration/recorded-queries/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/administration/recorded-queries/index.md b/docs/sources/administration/recorded-queries/index.md index 6876d4dc9059..d61585f0da58 100644 --- a/docs/sources/administration/recorded-queries/index.md +++ b/docs/sources/administration/recorded-queries/index.md @@ -22,7 +22,7 @@ Recorded queries allow you to see trends over time by taking a snapshot of a dat For our plugins that do not return time series, it might be useful to plot historical data. For example, you might want to query ServiceNow to see a history of request response times but it can only return current point-in-time metrics. {{% admonition type="note" %}} -Available in [Grafana Enterprise]({{< relref "../../introduction/grafana-enterprise/" >}}). +Available in [Grafana Enterprise](https://grafana.com/docs/grafana//introduction/grafana-enterprise/) and [Grafana Cloud](https://grafana.com/docs/grafana-cloud/). {{% /admonition %}} ## How recorded queries work From 00477e356b9fb42f32922fb1856b62e595c17448 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 21 Mar 2024 11:07:36 -0400 Subject: [PATCH 093/138] [v10.4.x] Docs: restructure Configure standard options (#84918) Docs: restructure Configure standard options (#84225) * Removed unnecessary task * Fixed note formatting * Added supported visualizations section * Docs: edit Configure standard options (#84226) * Edited heading * Added table and intro text to Supported visualizations section and updated intro to Standard options section * Replaced grafana link with cloud link * Copy edits * Copy edits * Updated intro * Copy edits and updated images * trigger CI * Deleted local images and linked to uploaded ones * Removed jargon (cherry picked from commit a64977d12abd8030707e5f592c5b8ca1c4b94ef3) Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --- .../configure-standard-options/index.md | 171 +++++++++++------- 1 file changed, 106 insertions(+), 65 deletions(-) diff --git a/docs/sources/panels-visualizations/configure-standard-options/index.md b/docs/sources/panels-visualizations/configure-standard-options/index.md index ea99c1062a92..a72a65672c8c 100644 --- a/docs/sources/panels-visualizations/configure-standard-options/index.md +++ b/docs/sources/panels-visualizations/configure-standard-options/index.md @@ -25,87 +25,94 @@ weight: 60 # Configure standard options -The data model used in Grafana, namely the [data frame](https://grafana.com/developers/plugin-tools/introduction/data-frames), is a columnar-oriented table structure that unifies both time series and table query results. Each column within this structure is called a _field_. A field can represent a single time series or table column. +**Standard options** in the panel editor pane let you change how field data is displayed in your visualizations. Options that you apply don't change the data, they just change how Grafana _displays_ the data. -Field options allow you to change how the data is displayed in your visualizations. Options and overrides that you apply do not change the data, they change how Grafana displays the data. When you change an option, it is applied to all fields, meaning all series or columns. For example, if you change the unit to percentage, then all fields with numeric values are displayed in percentages. +When you set a standard option, the change is applied to all fields or series. For example, if you set the **Unit** option to **Percentage**, all fields with numeric values are displayed as percentages. -For a complete list of field formatting options, refer to [Standard options definitions](#standard-options-definitions). +For more granular control over the display of fields, refer to [Configure overrides][]. -> You can apply standard options to most built-in Grafana panels. Some older panels and community panels that have not updated to the new panel and data model will be missing either all or some of these field options. +## Supported visualizations -1. Open a dashboard. Hover over any part of the panel to display the actions menu on the top right corner. -1. Click the menu and select **Edit**. -1. In the panel display options pane, locate the **Standard options** section. -1. Select the standard options you want to apply. +You can configure standard options for the following visualizations: - For more information about standard options, refer to [Standard options definitions](#standard-options-definitions). +| | | | +| -------------------------- | -------------------------------- | -------------------------------- | +| [Bar chart][bar chart] | [Geomap][geomap] | [Status history][status history] | +| [Bar gauge][bar gauge] | [Histogram][histogram] | [Table][table] | +| [Candlestick][candlestick] | [Pie chart][pie chart] | [Time series][time series] | +| [Canvas][canvas] | [Stat][stat] | [Trend][trend] | +| [Gauge][gauge] | [State timeline][state timeline] | | -1. To preview your change, click outside of the field option box you are editing or press **Enter**. - -## Standard options definitions +## Standard options This section explains all available standard options. -You can apply standard options to most built-in Grafana panels. Some older panels and community panels that have not updated to the new panel and data model will be missing either all or some of these field options. - -Most field options will not affect the visualization until you click outside of the field option box you are editing or press Enter. +To set these options, expand the **Standard options** section in the panel editor pane. Most field options won't affect the visualization until you click outside of the field option box you're editing or press Enter. {{% admonition type="note" %}} -We are constantly working to add and expand options for all visualization, so all options might not be available for all visualizations. +Not all of the options listed apply to all visualizations with standard options. {{% /admonition %}} ### Unit -Lets you choose what unit a field should use. Click in the **Unit** field, then drill down until you find the unit you want. The unit you select is applied to all fields except time. +This option lets you choose which unit a field should use. Click in the **Unit** field, then drill down until you find the unit you want. The unit you select is applied to all fields except time. #### Custom units -You can use the unit dropdown to also specify custom units, custom prefix or suffix and date time formats. +You can also use the **Unit** drop-down to specify custom units, custom prefixes or suffixes, and date time formats. + +To set a custom unit, enter the unit you want to use and then select it in the drop-down. It'll be the last option listed. For example, if you enter a unit called "Hearts", the drop-down will then include the option **Custom unit: Hearts**. + +You can further define a custom unit with specific syntax. For example, to set a custom currency unit called "Gems", enter `currency:Gems` in the field. The drop-down will include the option **Custom unit: currency:Gems**: + +![A custom currency unit called Gems in the Unit drop-down](/media/docs/grafana/panels-visualizations/custom_unit_currency_v11.0.png) + +The following table lists the special syntax options for custom units: -To select a custom unit enter the unit and select the last `Custom: xxx` option in the dropdown. +| Custom unit | Description | +| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `suffix:` | Custom unit that should go after value. | +| `prefix:` | Custom unit that should go before value. | +| `time:` | Custom date time formats type, such as `time:YYYY-MM-DD`. Refer to [formats](https://momentjs.com/docs/#/displaying/) for the format syntax and options. | +| `si:` | Custom SI units, such as `si: mF`. You can specify both a unit and the source data scale. For example, if your source data is represented as milli-something, prefix the unit with the `m` SI scale character. | +| `count:` | Custom count unit. | +| `currency:` | Custom currency unit. | -- `suffix:` for custom unit that should go after value. -- `prefix:` for custom unit that should go before value. -- `time:` For custom date time formats type for example `time:YYYY-MM-DD`. See [formats](https://momentjs.com/docs/#/displaying/) for the format syntax and options. -- `si:` for custom SI units. For example: `si: mF`. This one is a bit more advanced as you can specify both a unit and the - source data scale. So if your source data is represented as milli (thousands of) something prefix the unit with that - SI scale character. -- `count:` for a custom count unit. -- `currency:` for custom a currency unit. +You can also paste a native emoji in the **Unit** drop-down and select it as a custom unit: -You can also paste a native emoji in the unit picker and pick it as a custom unit: +![A thumbs up emoji as a custom unit](/media/docs/grafana/panels-visualizations/custom_unit_thumbsup_v11.0.png) -{{< figure src="/static/img/docs/v66/custom_unit_burger2.png" max-width="600px" caption="Custom unit emoji" >}} +![A time series visualization using custom thumbs up emoji units](/media/docs/grafana/panels-visualizations/thumbsup_panel_v11.0.png) #### String units -Grafana can sometimes be too aggressive in parsing strings and displaying them as numbers. To configure Grafana to show the original string value, create a field override and add a unit property with the `String` unit. +Sometimes Grafana is too aggressive in interpreting strings and displaying them as numbers. To configure Grafana to show the original string value, select **Misc > String** in the **Unit** drop-down. ### Min -Lets you set the minimum value used in percentage threshold calculations. Leave blank to automatically calculate the minimum. +Set the minimum value used in percentage threshold calculations. Leave this field empty to automatically calculate the minimum. ### Max -Lets you set the maximum value used in percentage threshold calculations. Leave blank to automatically calculate the maximum. +Set the maximum value used in percentage threshold calculations. Leave this field empty to automatically calculate the maximum. ### Field min/max -By default the calculated min and max will be based on the minimum and maximum, in all series and fields. Turning field min/max on, will calculate the min or max on each field individually, based on the minimum or maximum value of the field. +By default, the calculated **Min** and **Max** are based on the minimum and maximum of all series and fields. When you enable **Field min/max**, Grafana calculates the min or max of each field individually, based on the minimum or maximum value of the field. ### Decimals -Specify the number of decimals Grafana includes in the rendered value. If you leave this field blank, Grafana automatically truncates the number of decimals based on the value. For example 1.1234 will display as 1.12 and 100.456 will display as 100. +Specify the number of decimals Grafana includes in the rendered value. If you leave this field empty, Grafana automatically truncates the number of decimals based on the value. For example 1.1234 displays as 1.12 and 100.456 displays as 100. -To display all decimals, set the unit to `String`. +To display all decimals, set the unit to **String**. ### Display name -Lets you set the display title of all fields. You can use [variables][] in the field title. +Set the display title of all fields. You can use [variables][] in the field title. -When multiple stats, fields, or series are shown, this field controls the title in each stat. You can use expressions like `${__field.name}` to use only the series name or the field name in title. +When multiple stats, fields, or series are displayed, this field controls the title in each stat. You can use expressions like `${__field.name}` to use only the series name or the field name in the title. -Given a field with a name of Temp, and labels of {"Loc"="PBI", "Sensor"="3"} +The following table shows examples of the different field names generated using various expressions. In this example, there's a field with a name of "Temp" and labels of {"Loc"="PBI", "Sensor"="3"}: | Expression syntax | Example | Renders to | Explanation | | ---------------------------- | ----------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | @@ -115,45 +122,79 @@ Given a field with a name of Temp, and labels of {"Loc"="PBI", "Sensor"="3"} | `${__field.labels.X}` | `${__field.labels.Loc}` | `PBI` | Displays the value of the specified label key. | | `${__field.labels.__values}` | Same as Syntax | `PBI, 3` | Displays the values of the labels separated by a comma (without label keys). | -If the value is an empty string after rendering the expression for a particular field, then the default display method is used. +If the value is an empty string after rendering the expression for a particular field, then the default display method is applied. ### Color scheme -The color options and their effect on the visualization depends on the visualization you are working with. Some visualizations have different color options. +The **Color scheme** options let you set single or multiple colors for your entire visualization. -You can specify a single color, or select a continuous (gradient) color schemes, based on a value. -Continuous color interpolates a color using the percentage of a value relative to min and max. +The color options and their effect on a visualization depend on the visualization you're working with and some visualizations have different color options. -Select one of the following palettes: +Select one of the following schemes: -
- -| Color mode | Description | -| ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Single color** | Specify a single color, useful in an override rule | -| **Shades of a color** | Selects shades of a single color, useful in an override rule | -| **From thresholds** | Informs Grafana to take the color from the matching threshold | -| **Classic palette** | Grafana will assign color by looking up a color in a palette by series index. Useful for Graphs and pie charts and other categorical data visualizations | -| **Classic palette (by series name)** | Grafana will assign color based on the name of the series. Useful when the series names to be visualized depend on the available data. | -| **Green-Yellow-Red (by value)** | Continuous color scheme | -| **Red-Yellow-Green (by value)** | Continuous color scheme | -| **Blue-Yellow-Red (by value)** | Continuous color scheme | -| **Yellow-Red (by value)** | Continuous color scheme | -| **Blue-Purple (by value)** | Continuous color scheme | -| **Yellow-Blue (by value)** | Continuous color scheme | -| **Blues (by value)** | Continuous color scheme (panel background to blue) | -| **Reds (by value)** | Continuous color scheme (panel background color to red) | -| **Greens (by value)** | Continuous color scheme (panel background color to green) | -| **Purples (by value)** | Continuous color scheme (panel background color to purple) | - -{{< figure src="/static/img/docs/v73/color_scheme_dropdown.png" max-width="350px" caption="Color scheme" >}} +| Color scheme | Description | +| ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Single color | Specifies a single color. | +| Shades of a color | Grafana selects shades of a single color. | +| From thresholds (by value) | The color is taken from the matching [threshold][]. For some visualizations, you also need to choose if the color is set by the **Last**, **Min**, or **Max** value of the field or series. | +| Classic palette | Grafana automatically assigns a color for each field or series based on its order. If the order of a field changes in your query, the color also changes. Useful for graphs, pie charts, and other categorical data visualizations. | +| Classic palette (by series name) | Grafana automatically assigns colors based on the name of the series. Useful when the series names to be visualized can change based on the available data. | +| Multiple continuous colors (by value) | Grafana automatically assigns colors based on the percentage of a value relative to the min and the max of the field or series. For some visualizations, you also need to choose if the color is set by the **Last**, **Min**, or **Max** value of the field or series. Select from: **Green-Yellow-Red**, **Red-Yellow-Green**, **Blue-Yellow-Red**, **Yellow-Red**, **Blue-Purple**, and **Yellow-Blue**. | +| Single continuous color (by value) | Grafana automatically assigns shades of one color based on the percentage of a value relative to the min and the max of the field or series. For some visualizations, you also need to choose if the color is set by the **Last**, **Min**, or **Max** value of the field or series. Select from: **Blues**, **Reds**, **Greens**, and **Purples**. | ### No value Enter what Grafana should display if the field value is empty or null. The default value is a hyphen (-). {{% docs/reference %}} +[Configure overrides]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/configure-overrides" +[Configure overrides]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/configure-overrides" + +[bar chart]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/bar-chart" +[bar chart]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/bar-chart" + +[bar gauge]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/bar-gauge" +[bar gauge]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/bar-gauge" + +[candlestick]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/candlestick" +[candlestick]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/candlestick" + +[canvas]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/canvas" +[canvas]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/canvas" + +[gauge]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/gauge" +[gauge]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/gauge" + +[geomap]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/geomap" +[geomap]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/geomap" + +[histogram]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/histogram" +[histogram]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/histogram" + +[pie chart]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/pie-chart" +[pie chart]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/pie-chart" + +[stat]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/stat" +[stat]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/stat" + +[state timeline]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/state-timeline" +[state timeline]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/state-timeline" + +[status history]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/status-history" +[status history]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/status-history" + +[table]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/table" +[table]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/table" + +[time series]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/time-series" +[time series]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/time-series" + +[trend]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/trend" +[trend]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/trend" [variables]: "/docs/grafana/ -> /docs/grafana//dashboards/variables" -[variables]: "/docs/grafana-cloud/ -> /docs/grafana//dashboards/variables" +[variables]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/variables" + +[threshold]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/configure-thresholds" +[threshold]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/configure-thresholds" {{% /docs/reference %}} From e9ea783846595ff427f871cabad24558b02f1e44 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 21 Mar 2024 17:42:47 +0200 Subject: [PATCH 094/138] [v10.4.x] Changelog: Updated changelog for 10.4.1 (#84924) Changelog: Updated changelog for 10.4.1 (#84923) Co-authored-by: grafanabot (cherry picked from commit b848d8709c6779ddf770bf63e2350ceec94869fc) Co-authored-by: grafana-delivery-bot[bot] <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> --- CHANGELOG.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c6ef0d987ed..b16d43497612 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,30 @@ + + +# 10.4.1 (2024-03-20) + +### Features and enhancements + +- **Alerting:** Add "Keep Last State" backend functionality. [#84406](https://github.com/grafana/grafana/issues/84406), [@rwwiv](https://github.com/rwwiv) +- **Postgres:** Allow disabling SNI on SSL-enabled connections. [#84249](https://github.com/grafana/grafana/issues/84249), [@papagian](https://github.com/papagian) +- **DataQuery:** Track panel plugin id not type. [#83164](https://github.com/grafana/grafana/issues/83164), [@torkelo](https://github.com/torkelo) + +### Bug fixes + +- **Elasticsearch:** Fix legend for alerting, expressions and previously frontend queries. [#84685](https://github.com/grafana/grafana/issues/84685), [@ivanahuckova](https://github.com/ivanahuckova) +- **Alerting:** Fix optional fields requiring validation rule. [#84595](https://github.com/grafana/grafana/issues/84595), [@gillesdemey](https://github.com/gillesdemey) +- **ExtSvcAccounts:** FIX prevent service account deletion. [#84511](https://github.com/grafana/grafana/issues/84511), [@gamab](https://github.com/gamab) +- **Loki:** Fix null pointer exception in case request returned an error. [#84401](https://github.com/grafana/grafana/issues/84401), [@svennergr](https://github.com/svennergr) +- **Dashboard:** Fix issue where out-of-view shared query panels caused blank dependent panels. [#84197](https://github.com/grafana/grafana/issues/84197), [@kaydelaney](https://github.com/kaydelaney) +- **Auth:** Only call rotate token if we have a session expiry cookie. [#84181](https://github.com/grafana/grafana/issues/84181), [@kalleep](https://github.com/kalleep) +- **Serviceaccounts:** Add ability to add samename SA for different orgs. [#83953](https://github.com/grafana/grafana/issues/83953), [@eleijonmarck](https://github.com/eleijonmarck) +- **GenAI:** Update the component only when the response is fully generated. [#83895](https://github.com/grafana/grafana/issues/83895), [@ivanortegaalba](https://github.com/ivanortegaalba) +- **Tempo:** Better fallbacks for metrics query. [#83688](https://github.com/grafana/grafana/issues/83688), [@adrapereira](https://github.com/adrapereira) +- **Tempo:** Add template variable interpolation for filters. [#83667](https://github.com/grafana/grafana/issues/83667), [@joey-grafana](https://github.com/joey-grafana) +- **Alerting:** Fix saving evaluation group. [#83234](https://github.com/grafana/grafana/issues/83234), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron) +- **QueryVariableEditor:** Select a variable ds does not work. [#83181](https://github.com/grafana/grafana/issues/83181), [@ivanortegaalba](https://github.com/ivanortegaalba) +- **Logs Panel:** Add option extra UI functionality for log context. [#83129](https://github.com/grafana/grafana/issues/83129), [@svennergr](https://github.com/svennergr) + + # 10.4.0 (2024-03-06) From 1aea2dd15941cf9662aa8aea4e5458f7e0748795 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 21 Mar 2024 18:18:10 +0200 Subject: [PATCH 095/138] Release: Bump version to 10.4.2 (#84926) "Release: Updated versions in package to 10.4.2" Co-authored-by: grafana-delivery-bot[bot] <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> --- lerna.json | 2 +- package.json | 2 +- packages/grafana-data/package.json | 4 +- packages/grafana-e2e-selectors/package.json | 2 +- packages/grafana-e2e/package.json | 6 +- packages/grafana-eslint-rules/package.json | 2 +- packages/grafana-flamegraph/package.json | 6 +- .../grafana-o11y-ds-frontend/package.json | 2 +- packages/grafana-plugin-configs/package.json | 2 +- packages/grafana-prometheus/package.json | 2 +- packages/grafana-runtime/package.json | 10 +- packages/grafana-schema/package.json | 2 +- .../x/AlertGroupsPanelCfg_types.gen.ts | 2 +- .../x/AnnotationsListPanelCfg_types.gen.ts | 2 +- .../panelcfg/x/BarChartPanelCfg_types.gen.ts | 2 +- .../panelcfg/x/BarGaugePanelCfg_types.gen.ts | 2 +- .../x/CandlestickPanelCfg_types.gen.ts | 2 +- .../panelcfg/x/CanvasPanelCfg_types.gen.ts | 2 +- .../x/CloudWatchDataQuery_types.gen.ts | 2 +- .../x/DashboardListPanelCfg_types.gen.ts | 2 +- .../panelcfg/x/DatagridPanelCfg_types.gen.ts | 2 +- .../panelcfg/x/DebugPanelCfg_types.gen.ts | 2 +- .../x/ElasticsearchDataQuery_types.gen.ts | 2 +- .../panelcfg/x/GaugePanelCfg_types.gen.ts | 2 +- .../panelcfg/x/GeomapPanelCfg_types.gen.ts | 2 +- .../panelcfg/x/HeatmapPanelCfg_types.gen.ts | 2 +- .../panelcfg/x/HistogramPanelCfg_types.gen.ts | 2 +- .../logs/panelcfg/x/LogsPanelCfg_types.gen.ts | 2 +- .../dataquery/x/LokiDataQuery_types.gen.ts | 2 +- .../news/panelcfg/x/NewsPanelCfg_types.gen.ts | 2 +- .../panelcfg/x/NodeGraphPanelCfg_types.gen.ts | 2 +- .../panelcfg/x/PieChartPanelCfg_types.gen.ts | 2 +- .../x/PrometheusDataQuery_types.gen.ts | 2 +- .../stat/panelcfg/x/StatPanelCfg_types.gen.ts | 2 +- .../x/StateTimelinePanelCfg_types.gen.ts | 2 +- .../x/StatusHistoryPanelCfg_types.gen.ts | 2 +- .../panelcfg/x/TablePanelCfg_types.gen.ts | 2 +- .../text/panelcfg/x/TextPanelCfg_types.gen.ts | 2 +- .../x/TimeSeriesPanelCfg_types.gen.ts | 2 +- .../panelcfg/x/TrendPanelCfg_types.gen.ts | 2 +- .../panelcfg/x/XYChartPanelCfg_types.gen.ts | 2 +- packages/grafana-sql/package.json | 2 +- packages/grafana-ui/package.json | 8 +- .../internal/input-datasource/package.json | 6 +- .../datasource/azuremonitor/package.json | 14 +-- .../datasource/cloud-monitoring/package.json | 14 +-- .../grafana-pyroscope-datasource/package.json | 12 +-- .../grafana-testdata-datasource/package.json | 14 +-- .../app/plugins/datasource/parca/package.json | 12 +-- .../app/plugins/datasource/tempo/package.json | 4 +- yarn.lock | 98 +++++++++---------- 51 files changed, 142 insertions(+), 142 deletions(-) diff --git a/lerna.json b/lerna.json index 6522ef819e4e..5f924d4e4f53 100644 --- a/lerna.json +++ b/lerna.json @@ -1,4 +1,4 @@ { "npmClient": "yarn", - "version": "10.4.1" + "version": "10.4.2" } diff --git a/package.json b/package.json index 1f76b28d4ca9..d657c302c3d4 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "license": "AGPL-3.0-only", "private": true, "name": "grafana", - "version": "10.4.1", + "version": "10.4.2", "repository": "github:grafana/grafana", "scripts": { "prebuild": "yarn plugin:build", diff --git a/packages/grafana-data/package.json b/packages/grafana-data/package.json index bfe0c4dacf22..b7cfb6500a01 100644 --- a/packages/grafana-data/package.json +++ b/packages/grafana-data/package.json @@ -2,7 +2,7 @@ "author": "Grafana Labs", "license": "Apache-2.0", "name": "@grafana/data", - "version": "10.4.1", + "version": "10.4.2", "description": "Grafana Data Library", "keywords": [ "typescript" @@ -36,7 +36,7 @@ }, "dependencies": { "@braintree/sanitize-url": "7.0.0", - "@grafana/schema": "10.4.1", + "@grafana/schema": "10.4.2", "@types/d3-interpolate": "^3.0.0", "@types/string-hash": "1.1.3", "d3-interpolate": "3.0.1", diff --git a/packages/grafana-e2e-selectors/package.json b/packages/grafana-e2e-selectors/package.json index 8f2728b69bc9..3a17b0af46bc 100644 --- a/packages/grafana-e2e-selectors/package.json +++ b/packages/grafana-e2e-selectors/package.json @@ -2,7 +2,7 @@ "author": "Grafana Labs", "license": "Apache-2.0", "name": "@grafana/e2e-selectors", - "version": "10.4.1", + "version": "10.4.2", "description": "Grafana End-to-End Test Selectors Library", "keywords": [ "cli", diff --git a/packages/grafana-e2e/package.json b/packages/grafana-e2e/package.json index d7174eb4c2a4..352d6ba0b313 100644 --- a/packages/grafana-e2e/package.json +++ b/packages/grafana-e2e/package.json @@ -2,7 +2,7 @@ "author": "Grafana Labs", "license": "Apache-2.0", "name": "@grafana/e2e", - "version": "10.4.1", + "version": "10.4.2", "description": "Grafana End-to-End Test Library", "keywords": [ "cli", @@ -63,8 +63,8 @@ "@babel/core": "7.23.2", "@babel/preset-env": "7.23.2", "@cypress/webpack-preprocessor": "5.17.1", - "@grafana/e2e-selectors": "10.4.1", - "@grafana/schema": "10.4.1", + "@grafana/e2e-selectors": "10.4.2", + "@grafana/schema": "10.4.2", "@grafana/tsconfig": "^1.2.0-rc1", "@mochajs/json-file-reporter": "^1.2.0", "babel-loader": "9.1.3", diff --git a/packages/grafana-eslint-rules/package.json b/packages/grafana-eslint-rules/package.json index ea40fdb8c750..4e159ac42ec7 100644 --- a/packages/grafana-eslint-rules/package.json +++ b/packages/grafana-eslint-rules/package.json @@ -1,7 +1,7 @@ { "name": "@grafana/eslint-plugin", "description": "ESLint rules for use within the Grafana repo. Not suitable (or supported) for external use.", - "version": "10.4.1", + "version": "10.4.2", "main": "./index.cjs", "author": "Grafana Labs", "license": "Apache-2.0", diff --git a/packages/grafana-flamegraph/package.json b/packages/grafana-flamegraph/package.json index 8bf806ccfed3..ab910184197b 100644 --- a/packages/grafana-flamegraph/package.json +++ b/packages/grafana-flamegraph/package.json @@ -2,7 +2,7 @@ "author": "Grafana Labs", "license": "Apache-2.0", "name": "@grafana/flamegraph", - "version": "10.4.1", + "version": "10.4.2", "description": "Grafana flamegraph visualization component", "keywords": [ "grafana", @@ -44,8 +44,8 @@ ], "dependencies": { "@emotion/css": "11.11.2", - "@grafana/data": "10.4.1", - "@grafana/ui": "10.4.1", + "@grafana/data": "10.4.2", + "@grafana/ui": "10.4.2", "@leeoniya/ufuzzy": "1.0.14", "d3": "^7.8.5", "lodash": "4.17.21", diff --git a/packages/grafana-o11y-ds-frontend/package.json b/packages/grafana-o11y-ds-frontend/package.json index c79fccb12a47..7337068f32ce 100644 --- a/packages/grafana-o11y-ds-frontend/package.json +++ b/packages/grafana-o11y-ds-frontend/package.json @@ -3,7 +3,7 @@ "license": "AGPL-3.0-only", "name": "@grafana/o11y-ds-frontend", "private": true, - "version": "10.4.1", + "version": "10.4.2", "description": "Library to manage traces in Grafana.", "sideEffects": false, "repository": { diff --git a/packages/grafana-plugin-configs/package.json b/packages/grafana-plugin-configs/package.json index 29baea44439c..77a5560a7289 100644 --- a/packages/grafana-plugin-configs/package.json +++ b/packages/grafana-plugin-configs/package.json @@ -2,7 +2,7 @@ "name": "@grafana/plugin-configs", "description": "Shared dependencies and files for core plugins", "private": true, - "version": "10.4.1", + "version": "10.4.2", "dependencies": { "tslib": "2.6.2" }, diff --git a/packages/grafana-prometheus/package.json b/packages/grafana-prometheus/package.json index 0524b52fda7f..9d8bad01df5f 100644 --- a/packages/grafana-prometheus/package.json +++ b/packages/grafana-prometheus/package.json @@ -2,7 +2,7 @@ "author": "Grafana Labs", "license": "AGPL-3.0-only", "name": "@grafana/prometheus", - "version": "10.4.1", + "version": "10.4.2", "description": "Grafana Prometheus Library", "keywords": [ "typescript" diff --git a/packages/grafana-runtime/package.json b/packages/grafana-runtime/package.json index edbc156fc948..fad96831c4c9 100644 --- a/packages/grafana-runtime/package.json +++ b/packages/grafana-runtime/package.json @@ -2,7 +2,7 @@ "author": "Grafana Labs", "license": "Apache-2.0", "name": "@grafana/runtime", - "version": "10.4.1", + "version": "10.4.2", "description": "Grafana Runtime Library", "keywords": [ "grafana", @@ -37,11 +37,11 @@ "postpack": "mv package.json.bak package.json" }, "dependencies": { - "@grafana/data": "10.4.1", - "@grafana/e2e-selectors": "10.4.1", + "@grafana/data": "10.4.2", + "@grafana/e2e-selectors": "10.4.2", "@grafana/faro-web-sdk": "^1.3.6", - "@grafana/schema": "10.4.1", - "@grafana/ui": "10.4.1", + "@grafana/schema": "10.4.2", + "@grafana/ui": "10.4.2", "history": "4.10.1", "lodash": "4.17.21", "rxjs": "7.8.1", diff --git a/packages/grafana-schema/package.json b/packages/grafana-schema/package.json index cea6e56247c3..c59176e5a300 100644 --- a/packages/grafana-schema/package.json +++ b/packages/grafana-schema/package.json @@ -2,7 +2,7 @@ "author": "Grafana Labs", "license": "Apache-2.0", "name": "@grafana/schema", - "version": "10.4.1", + "version": "10.4.2", "description": "Grafana Schema Library", "keywords": [ "typescript" diff --git a/packages/grafana-schema/src/raw/composable/alertgroups/panelcfg/x/AlertGroupsPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/alertgroups/panelcfg/x/AlertGroupsPanelCfg_types.gen.ts index c755fbad6681..7b240033e986 100644 --- a/packages/grafana-schema/src/raw/composable/alertgroups/panelcfg/x/AlertGroupsPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/alertgroups/panelcfg/x/AlertGroupsPanelCfg_types.gen.ts @@ -9,7 +9,7 @@ // // Run 'make gen-cue' from repository root to regenerate. -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; export interface Options { /** diff --git a/packages/grafana-schema/src/raw/composable/annotationslist/panelcfg/x/AnnotationsListPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/annotationslist/panelcfg/x/AnnotationsListPanelCfg_types.gen.ts index 06588edf141f..1ffe7d9f0885 100644 --- a/packages/grafana-schema/src/raw/composable/annotationslist/panelcfg/x/AnnotationsListPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/annotationslist/panelcfg/x/AnnotationsListPanelCfg_types.gen.ts @@ -9,7 +9,7 @@ // // Run 'make gen-cue' from repository root to regenerate. -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; export interface Options { limit: number; diff --git a/packages/grafana-schema/src/raw/composable/barchart/panelcfg/x/BarChartPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/barchart/panelcfg/x/BarChartPanelCfg_types.gen.ts index 1d9f5049f24f..a4dbccbfd7c9 100644 --- a/packages/grafana-schema/src/raw/composable/barchart/panelcfg/x/BarChartPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/barchart/panelcfg/x/BarChartPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; export interface Options extends common.OptionsWithLegend, common.OptionsWithTooltip, common.OptionsWithTextFormatting { /** diff --git a/packages/grafana-schema/src/raw/composable/bargauge/panelcfg/x/BarGaugePanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/bargauge/panelcfg/x/BarGaugePanelCfg_types.gen.ts index b4d41f179037..4886e81f5cc5 100644 --- a/packages/grafana-schema/src/raw/composable/bargauge/panelcfg/x/BarGaugePanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/bargauge/panelcfg/x/BarGaugePanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; export interface Options extends common.SingleStatBaseOptions { displayMode: common.BarGaugeDisplayMode; diff --git a/packages/grafana-schema/src/raw/composable/candlestick/panelcfg/x/CandlestickPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/candlestick/panelcfg/x/CandlestickPanelCfg_types.gen.ts index 18346b932501..2b8942569226 100644 --- a/packages/grafana-schema/src/raw/composable/candlestick/panelcfg/x/CandlestickPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/candlestick/panelcfg/x/CandlestickPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; export enum VizDisplayMode { Candles = 'candles', diff --git a/packages/grafana-schema/src/raw/composable/canvas/panelcfg/x/CanvasPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/canvas/panelcfg/x/CanvasPanelCfg_types.gen.ts index 76f2d9b77816..f8d6f1ebc506 100644 --- a/packages/grafana-schema/src/raw/composable/canvas/panelcfg/x/CanvasPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/canvas/panelcfg/x/CanvasPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as ui from '@grafana/schema'; -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; export enum HorizontalConstraint { Center = 'center', diff --git a/packages/grafana-schema/src/raw/composable/cloudwatch/dataquery/x/CloudWatchDataQuery_types.gen.ts b/packages/grafana-schema/src/raw/composable/cloudwatch/dataquery/x/CloudWatchDataQuery_types.gen.ts index 7eec44d663e6..4f01568cacc0 100644 --- a/packages/grafana-schema/src/raw/composable/cloudwatch/dataquery/x/CloudWatchDataQuery_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/cloudwatch/dataquery/x/CloudWatchDataQuery_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; export interface MetricStat { /** diff --git a/packages/grafana-schema/src/raw/composable/dashboardlist/panelcfg/x/DashboardListPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/dashboardlist/panelcfg/x/DashboardListPanelCfg_types.gen.ts index 20b280d3231a..2c8872341a7a 100644 --- a/packages/grafana-schema/src/raw/composable/dashboardlist/panelcfg/x/DashboardListPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/dashboardlist/panelcfg/x/DashboardListPanelCfg_types.gen.ts @@ -9,7 +9,7 @@ // // Run 'make gen-cue' from repository root to regenerate. -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; export interface Options { /** diff --git a/packages/grafana-schema/src/raw/composable/datagrid/panelcfg/x/DatagridPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/datagrid/panelcfg/x/DatagridPanelCfg_types.gen.ts index 98fd2e74fd41..6d9760d55e40 100644 --- a/packages/grafana-schema/src/raw/composable/datagrid/panelcfg/x/DatagridPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/datagrid/panelcfg/x/DatagridPanelCfg_types.gen.ts @@ -9,7 +9,7 @@ // // Run 'make gen-cue' from repository root to regenerate. -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; export interface Options { selectedSeries: number; diff --git a/packages/grafana-schema/src/raw/composable/debug/panelcfg/x/DebugPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/debug/panelcfg/x/DebugPanelCfg_types.gen.ts index af4e5a02cfd8..1d394662156e 100644 --- a/packages/grafana-schema/src/raw/composable/debug/panelcfg/x/DebugPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/debug/panelcfg/x/DebugPanelCfg_types.gen.ts @@ -9,7 +9,7 @@ // // Run 'make gen-cue' from repository root to regenerate. -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; export type UpdateConfig = { render: boolean, diff --git a/packages/grafana-schema/src/raw/composable/elasticsearch/dataquery/x/ElasticsearchDataQuery_types.gen.ts b/packages/grafana-schema/src/raw/composable/elasticsearch/dataquery/x/ElasticsearchDataQuery_types.gen.ts index cdc3bec66894..fa1e3a502711 100644 --- a/packages/grafana-schema/src/raw/composable/elasticsearch/dataquery/x/ElasticsearchDataQuery_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/elasticsearch/dataquery/x/ElasticsearchDataQuery_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; export type BucketAggregation = (DateHistogram | Histogram | Terms | Filters | GeoHashGrid | Nested); diff --git a/packages/grafana-schema/src/raw/composable/gauge/panelcfg/x/GaugePanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/gauge/panelcfg/x/GaugePanelCfg_types.gen.ts index fd321550ac14..7d320a6f0905 100644 --- a/packages/grafana-schema/src/raw/composable/gauge/panelcfg/x/GaugePanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/gauge/panelcfg/x/GaugePanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; export interface Options extends common.SingleStatBaseOptions { minVizHeight: number; diff --git a/packages/grafana-schema/src/raw/composable/geomap/panelcfg/x/GeomapPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/geomap/panelcfg/x/GeomapPanelCfg_types.gen.ts index 880ca9975871..dda759320efa 100644 --- a/packages/grafana-schema/src/raw/composable/geomap/panelcfg/x/GeomapPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/geomap/panelcfg/x/GeomapPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as ui from '@grafana/schema'; -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; export interface Options { basemap: ui.MapLayerOptions; diff --git a/packages/grafana-schema/src/raw/composable/heatmap/panelcfg/x/HeatmapPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/heatmap/panelcfg/x/HeatmapPanelCfg_types.gen.ts index 6f0a56fc42a8..26f320e6a9a7 100644 --- a/packages/grafana-schema/src/raw/composable/heatmap/panelcfg/x/HeatmapPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/heatmap/panelcfg/x/HeatmapPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as ui from '@grafana/schema'; -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; /** * Controls the color mode of the heatmap diff --git a/packages/grafana-schema/src/raw/composable/histogram/panelcfg/x/HistogramPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/histogram/panelcfg/x/HistogramPanelCfg_types.gen.ts index b4ce7790f3de..645855f0be22 100644 --- a/packages/grafana-schema/src/raw/composable/histogram/panelcfg/x/HistogramPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/histogram/panelcfg/x/HistogramPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; export interface Options extends common.OptionsWithLegend, common.OptionsWithTooltip { /** diff --git a/packages/grafana-schema/src/raw/composable/logs/panelcfg/x/LogsPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/logs/panelcfg/x/LogsPanelCfg_types.gen.ts index 697ff2032263..e708571c739e 100644 --- a/packages/grafana-schema/src/raw/composable/logs/panelcfg/x/LogsPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/logs/panelcfg/x/LogsPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; export interface Options { dedupStrategy: common.LogsDedupStrategy; diff --git a/packages/grafana-schema/src/raw/composable/loki/dataquery/x/LokiDataQuery_types.gen.ts b/packages/grafana-schema/src/raw/composable/loki/dataquery/x/LokiDataQuery_types.gen.ts index 00ba037a5e15..0cfb0e2fcb2c 100644 --- a/packages/grafana-schema/src/raw/composable/loki/dataquery/x/LokiDataQuery_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/loki/dataquery/x/LokiDataQuery_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; export enum QueryEditorMode { Builder = 'builder', diff --git a/packages/grafana-schema/src/raw/composable/news/panelcfg/x/NewsPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/news/panelcfg/x/NewsPanelCfg_types.gen.ts index 462ed0ce12cc..bc1770d57f21 100644 --- a/packages/grafana-schema/src/raw/composable/news/panelcfg/x/NewsPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/news/panelcfg/x/NewsPanelCfg_types.gen.ts @@ -9,7 +9,7 @@ // // Run 'make gen-cue' from repository root to regenerate. -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; export interface Options { /** diff --git a/packages/grafana-schema/src/raw/composable/nodegraph/panelcfg/x/NodeGraphPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/nodegraph/panelcfg/x/NodeGraphPanelCfg_types.gen.ts index 9d7229c133a4..36bfdb3ede29 100644 --- a/packages/grafana-schema/src/raw/composable/nodegraph/panelcfg/x/NodeGraphPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/nodegraph/panelcfg/x/NodeGraphPanelCfg_types.gen.ts @@ -9,7 +9,7 @@ // // Run 'make gen-cue' from repository root to regenerate. -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; export interface ArcOption { /** diff --git a/packages/grafana-schema/src/raw/composable/piechart/panelcfg/x/PieChartPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/piechart/panelcfg/x/PieChartPanelCfg_types.gen.ts index 185bd06b8dc8..d6a4629f5496 100644 --- a/packages/grafana-schema/src/raw/composable/piechart/panelcfg/x/PieChartPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/piechart/panelcfg/x/PieChartPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; /** * Select the pie chart display style. diff --git a/packages/grafana-schema/src/raw/composable/prometheus/dataquery/x/PrometheusDataQuery_types.gen.ts b/packages/grafana-schema/src/raw/composable/prometheus/dataquery/x/PrometheusDataQuery_types.gen.ts index c1c0c1234caa..0f449cb27548 100644 --- a/packages/grafana-schema/src/raw/composable/prometheus/dataquery/x/PrometheusDataQuery_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/prometheus/dataquery/x/PrometheusDataQuery_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; export enum QueryEditorMode { Builder = 'builder', diff --git a/packages/grafana-schema/src/raw/composable/stat/panelcfg/x/StatPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/stat/panelcfg/x/StatPanelCfg_types.gen.ts index 3ee22187454c..885ef018c0ed 100644 --- a/packages/grafana-schema/src/raw/composable/stat/panelcfg/x/StatPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/stat/panelcfg/x/StatPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; export interface Options extends common.SingleStatBaseOptions { colorMode: common.BigValueColorMode; diff --git a/packages/grafana-schema/src/raw/composable/statetimeline/panelcfg/x/StateTimelinePanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/statetimeline/panelcfg/x/StateTimelinePanelCfg_types.gen.ts index 2854954366b5..7a09f8d7a6b0 100644 --- a/packages/grafana-schema/src/raw/composable/statetimeline/panelcfg/x/StateTimelinePanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/statetimeline/panelcfg/x/StateTimelinePanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as ui from '@grafana/schema'; -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; export interface Options extends ui.OptionsWithLegend, ui.OptionsWithTooltip, ui.OptionsWithTimezones { /** diff --git a/packages/grafana-schema/src/raw/composable/statushistory/panelcfg/x/StatusHistoryPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/statushistory/panelcfg/x/StatusHistoryPanelCfg_types.gen.ts index 6ce36c518f16..e4fca617d42f 100644 --- a/packages/grafana-schema/src/raw/composable/statushistory/panelcfg/x/StatusHistoryPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/statushistory/panelcfg/x/StatusHistoryPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as ui from '@grafana/schema'; -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; export interface Options extends ui.OptionsWithLegend, ui.OptionsWithTooltip, ui.OptionsWithTimezones { /** diff --git a/packages/grafana-schema/src/raw/composable/table/panelcfg/x/TablePanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/table/panelcfg/x/TablePanelCfg_types.gen.ts index f4ed813bddc5..b617480563a0 100644 --- a/packages/grafana-schema/src/raw/composable/table/panelcfg/x/TablePanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/table/panelcfg/x/TablePanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as ui from '@grafana/schema'; -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; export interface Options { /** diff --git a/packages/grafana-schema/src/raw/composable/text/panelcfg/x/TextPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/text/panelcfg/x/TextPanelCfg_types.gen.ts index e8b90dfb22eb..69b360b690b3 100644 --- a/packages/grafana-schema/src/raw/composable/text/panelcfg/x/TextPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/text/panelcfg/x/TextPanelCfg_types.gen.ts @@ -9,7 +9,7 @@ // // Run 'make gen-cue' from repository root to regenerate. -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; export enum TextMode { Code = 'code', diff --git a/packages/grafana-schema/src/raw/composable/timeseries/panelcfg/x/TimeSeriesPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/timeseries/panelcfg/x/TimeSeriesPanelCfg_types.gen.ts index 282b5e4841f6..4ed9680f321e 100644 --- a/packages/grafana-schema/src/raw/composable/timeseries/panelcfg/x/TimeSeriesPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/timeseries/panelcfg/x/TimeSeriesPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; export interface Options extends common.OptionsWithTimezones { legend: common.VizLegendOptions; diff --git a/packages/grafana-schema/src/raw/composable/trend/panelcfg/x/TrendPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/trend/panelcfg/x/TrendPanelCfg_types.gen.ts index 371487d2abdf..343e9eaa81f9 100644 --- a/packages/grafana-schema/src/raw/composable/trend/panelcfg/x/TrendPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/trend/panelcfg/x/TrendPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; /** * Identical to timeseries... except it does not have timezone settings diff --git a/packages/grafana-schema/src/raw/composable/xychart/panelcfg/x/XYChartPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/xychart/panelcfg/x/XYChartPanelCfg_types.gen.ts index 1ccd26619474..086eac7379e2 100644 --- a/packages/grafana-schema/src/raw/composable/xychart/panelcfg/x/XYChartPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/xychart/panelcfg/x/XYChartPanelCfg_types.gen.ts @@ -11,7 +11,7 @@ import * as common from '@grafana/schema'; -export const pluginVersion = "10.4.1"; +export const pluginVersion = "10.4.2"; /** * Auto is "table" in the UI diff --git a/packages/grafana-sql/package.json b/packages/grafana-sql/package.json index 39fa4d884876..d1b50fe1d7d4 100644 --- a/packages/grafana-sql/package.json +++ b/packages/grafana-sql/package.json @@ -3,7 +3,7 @@ "license": "AGPL-3.0-only", "private": true, "name": "@grafana/sql", - "version": "10.4.1", + "version": "10.4.2", "repository": { "type": "git", "url": "http://github.com/grafana/grafana.git", diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index 40f0e0fca722..39abe48b21d6 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -2,7 +2,7 @@ "author": "Grafana Labs", "license": "Apache-2.0", "name": "@grafana/ui", - "version": "10.4.1", + "version": "10.4.2", "description": "Grafana Components Library", "keywords": [ "grafana", @@ -50,10 +50,10 @@ "@emotion/css": "11.11.2", "@emotion/react": "11.11.3", "@floating-ui/react": "0.26.9", - "@grafana/data": "10.4.1", - "@grafana/e2e-selectors": "10.4.1", + "@grafana/data": "10.4.2", + "@grafana/e2e-selectors": "10.4.2", "@grafana/faro-web-sdk": "^1.3.6", - "@grafana/schema": "10.4.1", + "@grafana/schema": "10.4.2", "@leeoniya/ufuzzy": "1.0.14", "@monaco-editor/react": "4.6.0", "@popperjs/core": "2.11.8", diff --git a/plugins-bundled/internal/input-datasource/package.json b/plugins-bundled/internal/input-datasource/package.json index 123b0d9de3fa..e35fc30437a6 100644 --- a/plugins-bundled/internal/input-datasource/package.json +++ b/plugins-bundled/internal/input-datasource/package.json @@ -1,6 +1,6 @@ { "name": "@grafana-plugins/input-datasource", - "version": "10.4.1", + "version": "10.4.2", "description": "Input Datasource", "private": true, "repository": { @@ -28,8 +28,8 @@ "webpack": "5.76.0" }, "dependencies": { - "@grafana/data": "10.4.1", - "@grafana/ui": "10.4.1", + "@grafana/data": "10.4.2", + "@grafana/ui": "10.4.2", "react": "18.2.0", "tslib": "2.5.0" } diff --git a/public/app/plugins/datasource/azuremonitor/package.json b/public/app/plugins/datasource/azuremonitor/package.json index 6440dcebfcd0..90a3e44fa1dd 100644 --- a/public/app/plugins/datasource/azuremonitor/package.json +++ b/public/app/plugins/datasource/azuremonitor/package.json @@ -2,14 +2,14 @@ "name": "@grafana-plugins/grafana-azure-monitor-datasource", "description": "Grafana data source for Azure Monitor", "private": true, - "version": "10.4.1", + "version": "10.4.2", "dependencies": { "@emotion/css": "11.11.2", - "@grafana/data": "10.4.1", + "@grafana/data": "10.4.2", "@grafana/experimental": "1.7.10", - "@grafana/runtime": "10.4.1", - "@grafana/schema": "10.4.1", - "@grafana/ui": "10.4.1", + "@grafana/runtime": "10.4.2", + "@grafana/schema": "10.4.2", + "@grafana/ui": "10.4.2", "@kusto/monaco-kusto": "^7.4.0", "fast-deep-equal": "^3.1.3", "i18next": "^23.0.0", @@ -23,8 +23,8 @@ "tslib": "2.6.2" }, "devDependencies": { - "@grafana/e2e-selectors": "10.4.1", - "@grafana/plugin-configs": "10.4.1", + "@grafana/e2e-selectors": "10.4.2", + "@grafana/plugin-configs": "10.4.2", "@testing-library/react": "14.2.1", "@testing-library/user-event": "14.5.2", "@types/jest": "29.5.12", diff --git a/public/app/plugins/datasource/cloud-monitoring/package.json b/public/app/plugins/datasource/cloud-monitoring/package.json index c10deab27ee2..03956e80c060 100644 --- a/public/app/plugins/datasource/cloud-monitoring/package.json +++ b/public/app/plugins/datasource/cloud-monitoring/package.json @@ -2,15 +2,15 @@ "name": "@grafana-plugins/stackdriver", "description": "Grafana data source for Google Cloud Monitoring", "private": true, - "version": "10.4.1", + "version": "10.4.2", "dependencies": { "@emotion/css": "11.11.2", - "@grafana/data": "10.4.1", + "@grafana/data": "10.4.2", "@grafana/experimental": "1.7.10", "@grafana/google-sdk": "0.1.2", - "@grafana/runtime": "10.4.1", - "@grafana/schema": "10.4.1", - "@grafana/ui": "10.4.1", + "@grafana/runtime": "10.4.2", + "@grafana/schema": "10.4.2", + "@grafana/ui": "10.4.2", "@kusto/monaco-kusto": "^7.4.0", "debounce-promise": "3.1.2", "fast-deep-equal": "^3.1.3", @@ -25,8 +25,8 @@ "tslib": "2.6.2" }, "devDependencies": { - "@grafana/e2e-selectors": "10.4.1", - "@grafana/plugin-configs": "10.4.1", + "@grafana/e2e-selectors": "10.4.2", + "@grafana/plugin-configs": "10.4.2", "@testing-library/react": "14.2.1", "@testing-library/user-event": "14.5.2", "@types/debounce-promise": "3.1.9", diff --git a/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json b/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json index 552f138cb41e..d9fe9a34142f 100644 --- a/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json +++ b/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json @@ -2,13 +2,13 @@ "name": "@grafana-plugins/grafana-pyroscope-datasource", "description": "Continuous profiling for analysis of CPU and memory usage, down to the line number and throughout time. Saving infrastructure cost, improving performance, and increasing reliability.", "private": true, - "version": "10.4.1", + "version": "10.4.2", "dependencies": { "@emotion/css": "11.11.2", - "@grafana/data": "10.4.1", - "@grafana/runtime": "10.4.1", - "@grafana/schema": "10.4.1", - "@grafana/ui": "10.4.1", + "@grafana/data": "10.4.2", + "@grafana/runtime": "10.4.2", + "@grafana/schema": "10.4.2", + "@grafana/ui": "10.4.2", "fast-deep-equal": "^3.1.3", "lodash": "4.17.21", "monaco-editor": "0.34.0", @@ -20,7 +20,7 @@ "tslib": "2.6.2" }, "devDependencies": { - "@grafana/plugin-configs": "10.4.1", + "@grafana/plugin-configs": "10.4.2", "@testing-library/jest-dom": "6.4.2", "@testing-library/react": "14.2.1", "@testing-library/user-event": "14.5.2", diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/package.json b/public/app/plugins/datasource/grafana-testdata-datasource/package.json index 710d93ff40f9..eca1bd9cb1b4 100644 --- a/public/app/plugins/datasource/grafana-testdata-datasource/package.json +++ b/public/app/plugins/datasource/grafana-testdata-datasource/package.json @@ -2,14 +2,14 @@ "name": "@grafana-plugins/grafana-testdata-datasource", "description": "Generates test data in different forms", "private": true, - "version": "10.4.1", + "version": "10.4.2", "dependencies": { "@emotion/css": "11.11.2", - "@grafana/data": "10.4.1", + "@grafana/data": "10.4.2", "@grafana/experimental": "1.7.10", - "@grafana/runtime": "10.4.1", - "@grafana/schema": "10.4.1", - "@grafana/ui": "10.4.1", + "@grafana/runtime": "10.4.2", + "@grafana/schema": "10.4.2", + "@grafana/ui": "10.4.2", "d3-random": "^3.0.1", "lodash": "4.17.21", "micro-memoize": "^4.1.2", @@ -20,8 +20,8 @@ "uuid": "9.0.1" }, "devDependencies": { - "@grafana/e2e-selectors": "10.4.1", - "@grafana/plugin-configs": "10.4.1", + "@grafana/e2e-selectors": "10.4.2", + "@grafana/plugin-configs": "10.4.2", "@testing-library/react": "14.2.1", "@testing-library/user-event": "14.5.2", "@types/d3-random": "^3.0.2", diff --git a/public/app/plugins/datasource/parca/package.json b/public/app/plugins/datasource/parca/package.json index fa26883d82b0..ecf5f78022f3 100644 --- a/public/app/plugins/datasource/parca/package.json +++ b/public/app/plugins/datasource/parca/package.json @@ -2,13 +2,13 @@ "name": "@grafana-plugins/parca", "description": "Continuous profiling for analysis of CPU and memory usage, down to the line number and throughout time. Saving infrastructure cost, improving performance, and increasing reliability.", "private": true, - "version": "10.4.1", + "version": "10.4.2", "dependencies": { "@emotion/css": "11.11.2", - "@grafana/data": "10.4.1", - "@grafana/runtime": "10.4.1", - "@grafana/schema": "10.4.1", - "@grafana/ui": "10.4.1", + "@grafana/data": "10.4.2", + "@grafana/runtime": "10.4.2", + "@grafana/schema": "10.4.2", + "@grafana/ui": "10.4.2", "lodash": "4.17.21", "monaco-editor": "0.34.0", "react": "18.2.0", @@ -17,7 +17,7 @@ "tslib": "2.6.2" }, "devDependencies": { - "@grafana/plugin-configs": "10.4.1", + "@grafana/plugin-configs": "10.4.2", "@testing-library/react": "14.2.1", "@testing-library/user-event": "14.5.2", "@types/lodash": "4.14.202", diff --git a/public/app/plugins/datasource/tempo/package.json b/public/app/plugins/datasource/tempo/package.json index 2b14d8abdee5..daf45eb679b9 100644 --- a/public/app/plugins/datasource/tempo/package.json +++ b/public/app/plugins/datasource/tempo/package.json @@ -2,7 +2,7 @@ "name": "@grafana-plugins/tempo", "description": "Grafana plugin for the Tempo data source.", "private": true, - "version": "10.4.1", + "version": "10.4.2", "dependencies": { "@emotion/css": "11.11.2", "@grafana/data": "workspace:*", @@ -41,7 +41,7 @@ "uuid": "9.0.1" }, "devDependencies": { - "@grafana/plugin-configs": "10.4.1", + "@grafana/plugin-configs": "10.4.2", "@testing-library/jest-dom": "6.4.2", "@testing-library/react": "14.2.1", "@testing-library/user-event": "14.5.2", diff --git a/yarn.lock b/yarn.lock index 43474fd6285f..0ff1c92425f9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3219,13 +3219,13 @@ __metadata: resolution: "@grafana-plugins/grafana-azure-monitor-datasource@workspace:public/app/plugins/datasource/azuremonitor" dependencies: "@emotion/css": "npm:11.11.2" - "@grafana/data": "npm:10.4.1" - "@grafana/e2e-selectors": "npm:10.4.1" + "@grafana/data": "npm:10.4.2" + "@grafana/e2e-selectors": "npm:10.4.2" "@grafana/experimental": "npm:1.7.10" - "@grafana/plugin-configs": "npm:10.4.1" - "@grafana/runtime": "npm:10.4.1" - "@grafana/schema": "npm:10.4.1" - "@grafana/ui": "npm:10.4.1" + "@grafana/plugin-configs": "npm:10.4.2" + "@grafana/runtime": "npm:10.4.2" + "@grafana/schema": "npm:10.4.2" + "@grafana/ui": "npm:10.4.2" "@kusto/monaco-kusto": "npm:^7.4.0" "@testing-library/react": "npm:14.2.1" "@testing-library/user-event": "npm:14.5.2" @@ -3259,11 +3259,11 @@ __metadata: resolution: "@grafana-plugins/grafana-pyroscope-datasource@workspace:public/app/plugins/datasource/grafana-pyroscope-datasource" dependencies: "@emotion/css": "npm:11.11.2" - "@grafana/data": "npm:10.4.1" - "@grafana/plugin-configs": "npm:10.4.1" - "@grafana/runtime": "npm:10.4.1" - "@grafana/schema": "npm:10.4.1" - "@grafana/ui": "npm:10.4.1" + "@grafana/data": "npm:10.4.2" + "@grafana/plugin-configs": "npm:10.4.2" + "@grafana/runtime": "npm:10.4.2" + "@grafana/schema": "npm:10.4.2" + "@grafana/ui": "npm:10.4.2" "@testing-library/jest-dom": "npm:6.4.2" "@testing-library/react": "npm:14.2.1" "@testing-library/user-event": "npm:14.5.2" @@ -3298,13 +3298,13 @@ __metadata: resolution: "@grafana-plugins/grafana-testdata-datasource@workspace:public/app/plugins/datasource/grafana-testdata-datasource" dependencies: "@emotion/css": "npm:11.11.2" - "@grafana/data": "npm:10.4.1" - "@grafana/e2e-selectors": "npm:10.4.1" + "@grafana/data": "npm:10.4.2" + "@grafana/e2e-selectors": "npm:10.4.2" "@grafana/experimental": "npm:1.7.10" - "@grafana/plugin-configs": "npm:10.4.1" - "@grafana/runtime": "npm:10.4.1" - "@grafana/schema": "npm:10.4.1" - "@grafana/ui": "npm:10.4.1" + "@grafana/plugin-configs": "npm:10.4.2" + "@grafana/runtime": "npm:10.4.2" + "@grafana/schema": "npm:10.4.2" + "@grafana/ui": "npm:10.4.2" "@testing-library/react": "npm:14.2.1" "@testing-library/user-event": "npm:14.5.2" "@types/d3-random": "npm:^3.0.2" @@ -3333,9 +3333,9 @@ __metadata: version: 0.0.0-use.local resolution: "@grafana-plugins/input-datasource@workspace:plugins-bundled/internal/input-datasource" dependencies: - "@grafana/data": "npm:10.4.1" + "@grafana/data": "npm:10.4.2" "@grafana/tsconfig": "npm:^1.2.0-rc1" - "@grafana/ui": "npm:10.4.1" + "@grafana/ui": "npm:10.4.2" "@types/jest": "npm:26.0.15" "@types/react": "npm:18.0.28" copy-webpack-plugin: "npm:11.0.0" @@ -3357,11 +3357,11 @@ __metadata: resolution: "@grafana-plugins/parca@workspace:public/app/plugins/datasource/parca" dependencies: "@emotion/css": "npm:11.11.2" - "@grafana/data": "npm:10.4.1" - "@grafana/plugin-configs": "npm:10.4.1" - "@grafana/runtime": "npm:10.4.1" - "@grafana/schema": "npm:10.4.1" - "@grafana/ui": "npm:10.4.1" + "@grafana/data": "npm:10.4.2" + "@grafana/plugin-configs": "npm:10.4.2" + "@grafana/runtime": "npm:10.4.2" + "@grafana/schema": "npm:10.4.2" + "@grafana/ui": "npm:10.4.2" "@testing-library/react": "npm:14.2.1" "@testing-library/user-event": "npm:14.5.2" "@types/lodash": "npm:4.14.202" @@ -3384,14 +3384,14 @@ __metadata: resolution: "@grafana-plugins/stackdriver@workspace:public/app/plugins/datasource/cloud-monitoring" dependencies: "@emotion/css": "npm:11.11.2" - "@grafana/data": "npm:10.4.1" - "@grafana/e2e-selectors": "npm:10.4.1" + "@grafana/data": "npm:10.4.2" + "@grafana/e2e-selectors": "npm:10.4.2" "@grafana/experimental": "npm:1.7.10" "@grafana/google-sdk": "npm:0.1.2" - "@grafana/plugin-configs": "npm:10.4.1" - "@grafana/runtime": "npm:10.4.1" - "@grafana/schema": "npm:10.4.1" - "@grafana/ui": "npm:10.4.1" + "@grafana/plugin-configs": "npm:10.4.2" + "@grafana/runtime": "npm:10.4.2" + "@grafana/schema": "npm:10.4.2" + "@grafana/ui": "npm:10.4.2" "@kusto/monaco-kusto": "npm:^7.4.0" "@testing-library/react": "npm:14.2.1" "@testing-library/user-event": "npm:14.5.2" @@ -3436,7 +3436,7 @@ __metadata: "@grafana/lezer-traceql": "npm:0.0.15" "@grafana/monaco-logql": "npm:^0.0.7" "@grafana/o11y-ds-frontend": "workspace:*" - "@grafana/plugin-configs": "npm:10.4.1" + "@grafana/plugin-configs": "npm:10.4.2" "@grafana/runtime": "workspace:*" "@grafana/schema": "workspace:*" "@grafana/ui": "workspace:*" @@ -3504,12 +3504,12 @@ __metadata: languageName: node linkType: hard -"@grafana/data@npm:10.4.1, @grafana/data@workspace:*, @grafana/data@workspace:packages/grafana-data": +"@grafana/data@npm:10.4.2, @grafana/data@workspace:*, @grafana/data@workspace:packages/grafana-data": version: 0.0.0-use.local resolution: "@grafana/data@workspace:packages/grafana-data" dependencies: "@braintree/sanitize-url": "npm:7.0.0" - "@grafana/schema": "npm:10.4.1" + "@grafana/schema": "npm:10.4.2" "@grafana/tsconfig": "npm:^1.2.0-rc1" "@rollup/plugin-commonjs": "npm:25.0.7" "@rollup/plugin-json": "npm:6.1.0" @@ -3580,7 +3580,7 @@ __metadata: languageName: node linkType: hard -"@grafana/e2e-selectors@npm:10.4.1, @grafana/e2e-selectors@workspace:*, @grafana/e2e-selectors@workspace:packages/grafana-e2e-selectors": +"@grafana/e2e-selectors@npm:10.4.2, @grafana/e2e-selectors@workspace:*, @grafana/e2e-selectors@workspace:packages/grafana-e2e-selectors": version: 0.0.0-use.local resolution: "@grafana/e2e-selectors@workspace:packages/grafana-e2e-selectors" dependencies: @@ -3606,8 +3606,8 @@ __metadata: "@babel/core": "npm:7.23.2" "@babel/preset-env": "npm:7.23.2" "@cypress/webpack-preprocessor": "npm:5.17.1" - "@grafana/e2e-selectors": "npm:10.4.1" - "@grafana/schema": "npm:10.4.1" + "@grafana/e2e-selectors": "npm:10.4.2" + "@grafana/schema": "npm:10.4.2" "@grafana/tsconfig": "npm:^1.2.0-rc1" "@mochajs/json-file-reporter": "npm:^1.2.0" "@rollup/plugin-node-resolve": "npm:15.2.3" @@ -3751,9 +3751,9 @@ __metadata: "@babel/preset-env": "npm:7.23.9" "@babel/preset-react": "npm:7.23.3" "@emotion/css": "npm:11.11.2" - "@grafana/data": "npm:10.4.1" + "@grafana/data": "npm:10.4.2" "@grafana/tsconfig": "npm:^1.2.0-rc1" - "@grafana/ui": "npm:10.4.1" + "@grafana/ui": "npm:10.4.2" "@leeoniya/ufuzzy": "npm:1.0.14" "@rollup/plugin-node-resolve": "npm:15.2.3" "@testing-library/jest-dom": "npm:^6.1.2" @@ -3860,7 +3860,7 @@ __metadata: languageName: unknown linkType: soft -"@grafana/plugin-configs@npm:10.4.1, @grafana/plugin-configs@workspace:packages/grafana-plugin-configs": +"@grafana/plugin-configs@npm:10.4.2, @grafana/plugin-configs@workspace:packages/grafana-plugin-configs": version: 0.0.0-use.local resolution: "@grafana/plugin-configs@workspace:packages/grafana-plugin-configs" dependencies: @@ -3990,16 +3990,16 @@ __metadata: languageName: unknown linkType: soft -"@grafana/runtime@npm:10.4.1, @grafana/runtime@workspace:*, @grafana/runtime@workspace:packages/grafana-runtime": +"@grafana/runtime@npm:10.4.2, @grafana/runtime@workspace:*, @grafana/runtime@workspace:packages/grafana-runtime": version: 0.0.0-use.local resolution: "@grafana/runtime@workspace:packages/grafana-runtime" dependencies: - "@grafana/data": "npm:10.4.1" - "@grafana/e2e-selectors": "npm:10.4.1" + "@grafana/data": "npm:10.4.2" + "@grafana/e2e-selectors": "npm:10.4.2" "@grafana/faro-web-sdk": "npm:^1.3.6" - "@grafana/schema": "npm:10.4.1" + "@grafana/schema": "npm:10.4.2" "@grafana/tsconfig": "npm:^1.2.0-rc1" - "@grafana/ui": "npm:10.4.1" + "@grafana/ui": "npm:10.4.2" "@rollup/plugin-commonjs": "npm:25.0.7" "@rollup/plugin-node-resolve": "npm:15.2.3" "@testing-library/dom": "npm:9.3.4" @@ -4053,7 +4053,7 @@ __metadata: languageName: node linkType: hard -"@grafana/schema@npm:10.4.1, @grafana/schema@workspace:*, @grafana/schema@workspace:packages/grafana-schema": +"@grafana/schema@npm:10.4.2, @grafana/schema@workspace:*, @grafana/schema@workspace:packages/grafana-schema": version: 0.0.0-use.local resolution: "@grafana/schema@workspace:packages/grafana-schema" dependencies: @@ -4127,7 +4127,7 @@ __metadata: languageName: node linkType: hard -"@grafana/ui@npm:10.4.1, @grafana/ui@workspace:*, @grafana/ui@workspace:packages/grafana-ui": +"@grafana/ui@npm:10.4.2, @grafana/ui@workspace:*, @grafana/ui@workspace:packages/grafana-ui": version: 0.0.0-use.local resolution: "@grafana/ui@workspace:packages/grafana-ui" dependencies: @@ -4135,10 +4135,10 @@ __metadata: "@emotion/css": "npm:11.11.2" "@emotion/react": "npm:11.11.3" "@floating-ui/react": "npm:0.26.9" - "@grafana/data": "npm:10.4.1" - "@grafana/e2e-selectors": "npm:10.4.1" + "@grafana/data": "npm:10.4.2" + "@grafana/e2e-selectors": "npm:10.4.2" "@grafana/faro-web-sdk": "npm:^1.3.6" - "@grafana/schema": "npm:10.4.1" + "@grafana/schema": "npm:10.4.2" "@grafana/tsconfig": "npm:^1.2.0-rc1" "@leeoniya/ufuzzy": "npm:1.0.14" "@monaco-editor/react": "npm:4.6.0" From 95604c13553613103033ceedcf9793e5bb4a967a Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 21 Mar 2024 14:57:31 -0400 Subject: [PATCH 096/138] [v10.4.x] Alerting: Add docs for "Keep Last State" feature (#84943) Alerting: Add docs for "Keep Last State" feature (#84676) Add initial docs for "Keep Last State" feature (cherry picked from commit c5b04b5674e77e6fce087ee5b76c3771452c30cc) Co-authored-by: William Wernert --- .../alert-rules/state-and-health.md | 16 +++++++++++----- .../manage-notifications/view-state-health.md | 18 ++++++++++++------ 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/docs/sources/alerting/fundamentals/alert-rules/state-and-health.md b/docs/sources/alerting/fundamentals/alert-rules/state-and-health.md index 87989b633546..aebbce8ecc2c 100644 --- a/docs/sources/alerting/fundamentals/alert-rules/state-and-health.md +++ b/docs/sources/alerting/fundamentals/alert-rules/state-and-health.md @@ -6,6 +6,7 @@ description: Learn about the state and health of alert rules to understand sever keywords: - grafana - alerting + - keep last state - guide - state labels: @@ -49,15 +50,20 @@ An alert instance can be in either of the following states: | **NoData** | No data has been received for the configured time window. | | **Error** | The error that occurred when attempting to evaluate an alert rule. | +## Keep last state + +An alert rule can be configured to keep the last state when a `NoData` and/or `Error` state is encountered. This will both prevent alerts from firing, and from resolving and re-firing. Just like normal evaluation, the alert rule will transition from `Pending` to `Firing` after the pending period has elapsed. + ## Alert rule health An alert rule can have one the following health statuses: -| State | Description | -| ---------- | ---------------------------------------------------------------------------------- | -| **Ok** | No error when evaluating an alert rule. | -| **Error** | An error occurred when evaluating an alert rule. | -| **NoData** | The absence of data in at least one time series returned during a rule evaluation. | +| State | Description | +| ---------------------- | -------------------------------------------------------------------------------------------------------- | +| **Ok** | No error when evaluating an alerting rule. | +| **Error** | An error occurred when evaluating an alerting rule. | +| **NoData** | The absence of data in at least one time series returned during a rule evaluation. | +| **{status}, KeepLast** | The rule would have received another status but was configured to keep the last state of the alert rule. | ## Special alerts for `NoData` and `Error` diff --git a/docs/sources/alerting/manage-notifications/view-state-health.md b/docs/sources/alerting/manage-notifications/view-state-health.md index 0ebed5afd118..0b4a5fb71902 100644 --- a/docs/sources/alerting/manage-notifications/view-state-health.md +++ b/docs/sources/alerting/manage-notifications/view-state-health.md @@ -8,6 +8,7 @@ description: View the state and health of alert rules keywords: - grafana - alert rules + - keep last state - guide - state - health @@ -58,15 +59,20 @@ An alert instance can be in either of the following states: | **NoData** | No data has been received for the configured time window. | | **Error** | The error that occurred when attempting to evaluate an alerting rule. | +## Keep last state + +An alert rule can be configured to keep the last state when a `NoData` and/or `Error` state is encountered. This will both prevent alerts from firing, and from resolving and re-firing. Just like normal evaluation, the alert rule will transition from `Pending` to `Firing` after the pending period has elapsed. + ## Alert rule health An alert rule can have one the following health statuses: -| State | Description | -| ---------- | ---------------------------------------------------------------------------------- | -| **Ok** | No error when evaluating an alerting rule. | -| **Error** | An error occurred when evaluating an alerting rule. | -| **NoData** | The absence of data in at least one time series returned during a rule evaluation. | +| State | Description | +| ---------------------- | -------------------------------------------------------------------------------------------------------- | +| **Ok** | No error when evaluating an alerting rule. | +| **Error** | An error occurred when evaluating an alerting rule. | +| **NoData** | The absence of data in at least one time series returned during a rule evaluation. | +| **{status}, KeepLast** | The rule would have received another status but was configured to keep the last state of the alert rule. | ## Special alerts for `NoData` and `Error` @@ -78,7 +84,7 @@ When evaluation of an alerting rule produces state `NoData` or `Error`, Grafana | **datasource_uid** | The UID of the data source that caused the state. | {{% admonition type="note" %}} -You will need to set the No Data and Error Handling to `No Data` or `Error` in the alert rule as per this doc: https://grafana.com/docs/grafana/latest/alerting/alerting-rules/create-grafana-managed-rule/#configure-no-data-and-error-handling in order to generate the additional labels. +You will need to set the No Data and Error Handling to `No Data` or `Error` in the alert rule as per this doc: in order to generate the additional labels. {{% /admonition %}} You can handle these alerts the same way as regular alerts by adding a silence, route to a contact point, and so on. From 554cca4604d18f2a34ca723145f5caa4907544be Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 21 Mar 2024 15:19:38 -0400 Subject: [PATCH 097/138] [v10.4.x] Docs: add Configure tooltips page (#84945) * Docs: add Configure tooltips page (#84089) * Added Configure tooltips page * Added intro, description options and image * Updated weight and removed passive voice * Replaced list with table and updated non-configurable tooltips section * Updated info about other tooltips * Wording edits * Apply suggestions from code review * Fixed table * Added hover value in color scheme info with image (cherry picked from commit e192c0aa055e107b87fccc5a47321c86b1a74a13) * Added public preview note * Formatted feature toggle --------- Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> Co-authored-by: Isabel Matwawana --- .../configure-tooltips/index.md | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 docs/sources/panels-visualizations/configure-tooltips/index.md diff --git a/docs/sources/panels-visualizations/configure-tooltips/index.md b/docs/sources/panels-visualizations/configure-tooltips/index.md new file mode 100644 index 000000000000..4adfb32f37c9 --- /dev/null +++ b/docs/sources/panels-visualizations/configure-tooltips/index.md @@ -0,0 +1,116 @@ +--- +aliases: +keywords: + - grafana + - tooltips + - documentation +labels: + products: + - cloud + - enterprise + - oss +menuTitle: Configure tooltips +title: Configure tooltips +description: Configure tooltips for your visualizations +weight: 75 +--- + +# Configure tooltips + +{{< docs/public-preview product="The new tooltip experience" featureFlag="`newVizTooltips`" >}} + +When you hover your cursor over a visualization, Grafana can display tooltips that contain more information about a data point, like the exact time of a result. You can customize tooltips to control how many series they include and the order of those values. You can also copy the content from tooltips to use elsewhere. Learn more about configuring tooltips in [Tooltip options](#tooltip-options). + +## Supported visualizations + +You can configure tooltips for the following visualizations: + +| | | +| -------------------------- | -------------------------------- | +| [Bar chart][bar chart] | [State timeline][state timeline] | +| [Candlestick][candlestick] | [Status history][status history] | +| [Heatmap][heatmap] | [Time series][time series] | +| [Pie chart][pie chart] | [Trend][trend] | + + + +Some visualizations, for example [candlestick][] and [flame graph][], have tooltips, but they aren't configurable. These visualizations don't have a **Tooltip** section in the panel editor pane. [Geomaps][geomaps] provide you the option to have tooltips triggered upon click or hover under the **Map controls** options in the panel editor pane. + + + +## Tooltip options + +You can find the following options under the **Tooltip** section in the panel edit pane. + +{{% admonition type="note" %}} +Not all of the options listed apply to all visualizations with tooltips. +{{% /admonition %}} + +### Tooltip mode + +Choose how tooltips behave with the following options: + +- **Single** - The tooltip only the single series that you're hovering over in the visualization. +- **All** - The tooltip shows all series in the visualization. Grafana highlights the series that you are hovering over in bold in the series list in the tooltip. +- **Hidden** - Tooltips aren't displayed when you interact with the visualization. + +You can use a [field override][] to hide individual series from the tooltip. + +### Values sort order + +When you set the **Tooltip mode** to **All**, the **Values sort order** option is displayed. This option controls the order in which values are listed in a tooltip. Choose from the following: + +- **None** - Grafana automatically sorts the values displayed in a tooltip. +- **Ascending** - Values in the tooltip are listed from smallest to largest. +- **Descending** - Values in the tooltip are listed from largest to smallest. + +### Hover proximity + +Set the hover proximity (in pixels) to control how close the cursor must be to a data point to trigger the tooltip to display. + +![Adding a hover proximity limit for tooltips](/media/docs/grafana/gif-grafana-10-4-hover-proximity.gif) + +### Show histogram (Y axis) + +For the heatmap visualization only, when you set the **Tooltip mode** to **Single**, the **Show histogram (Y axis)** option is displayed. This option controls whether or not the tooltip includes a histogram representing the y-axis. + +### Show color scale + +For the heatmap visualization only, when you set the **Tooltip mode** to **Single**, the **Show color scale** option is displayed. This option controls whether or not the tooltip includes the color scale that's also represented in the legend. When the color scale is included in the tooltip, it shows the hovered value on the scale: + +![Heatmap with a tooltip displayed showing the hovered value reflected in the color scale](/media/docs/grafana/panels-visualizations/screenshot-heatmap-tooltip-color-scale-v11.0.png) + +{{% docs/reference %}} +[bar chart]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/bar-chart" +[bar chart]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/bar-chart" + +[candlestick]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/candlestick" +[candlestick]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/candlestick" + +[flame graph]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/flame-graph" +[flame graph]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/flame-graph" + +[geomaps]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/geomap#tooltip" +[geomaps]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/geomap#tooltip" + +[heatmap]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/heatmap" +[heatmap]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/heatmap" + +[pie chart]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/pie-chart" +[pie chart]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/pie-chart" + +[state timeline]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/state-timeline" +[state timeline]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/state-timeline" + +[status history]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/status-history" +[status history]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/status-history" + +[time series]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/time-series" +[time series]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/time-series" + +[trend]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/trend" +[trend]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/trend" + +[field override]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/configure-overrides" +[field override]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/configure-overrides" +{{% /docs/reference %}} From 75f5cee757cc7d3700b7c0130ce167ad4c10874c Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Fri, 22 Mar 2024 19:25:42 +0200 Subject: [PATCH 098/138] [v10.4.x] CloudMonitoring: Only run query if filters are complete (#85016) CloudMonitoring: Only run query if filters are complete (#85004) * Only run query if filters are complete - Update tests * Fix tests (cherry picked from commit 4855751d0dee06cbf23696cc6104f55a6c03bd03) Co-authored-by: Andreas Christou --- .../components/MetricQueryEditor.test.tsx | 31 +++++++++++++++++++ .../components/MetricQueryEditor.tsx | 13 +++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/public/app/plugins/datasource/cloud-monitoring/components/MetricQueryEditor.test.tsx b/public/app/plugins/datasource/cloud-monitoring/components/MetricQueryEditor.test.tsx index ad2f975ba209..b3975ad9438e 100644 --- a/public/app/plugins/datasource/cloud-monitoring/components/MetricQueryEditor.test.tsx +++ b/public/app/plugins/datasource/cloud-monitoring/components/MetricQueryEditor.test.tsx @@ -1,5 +1,7 @@ import { render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import React from 'react'; +import { openMenu } from 'react-select-event'; import { getDefaultTimeRange } from '@grafana/data'; @@ -80,4 +82,33 @@ describe('MetricQueryEditor', () => { render(); await waitFor(() => expect(screen.getByLabelText('Alias by').closest('input')!.value).toEqual('AliasTest')); }); + + it('runs a timeSeriesList query if there are no filters', async () => { + const onRunQuery = jest.fn(); + const onChange = jest.fn(); + const query = createMockQuery(); + + render(); + + const groupBy = screen.getByLabelText('Group by'); + openMenu(groupBy); + const option = 'metadata.system_labels.cloud_account'; + await userEvent.click(screen.getByText(option)); + + expect(onRunQuery).toHaveBeenCalledTimes(1); + expect(onChange).toHaveBeenCalledTimes(1); + }); + + it('does not run a timeSeriesList query when filter is added', async () => { + const onRunQuery = jest.fn(); + const onChange = jest.fn(); + const query = createMockQuery(); + + render(); + + const addFilter = screen.getByLabelText('Add'); + await userEvent.click(addFilter); + expect(onRunQuery).toHaveBeenCalledTimes(0); + expect(onChange).toHaveBeenCalledTimes(1); + }); }); diff --git a/public/app/plugins/datasource/cloud-monitoring/components/MetricQueryEditor.tsx b/public/app/plugins/datasource/cloud-monitoring/components/MetricQueryEditor.tsx index 432b5429e91b..846ee57fb085 100644 --- a/public/app/plugins/datasource/cloud-monitoring/components/MetricQueryEditor.tsx +++ b/public/app/plugins/datasource/cloud-monitoring/components/MetricQueryEditor.tsx @@ -50,8 +50,19 @@ function Editor({ }: React.PropsWithChildren) { const onChangeTimeSeriesList = useCallback( (timeSeriesList: TimeSeriesList) => { + let filtersComplete = true; + if (timeSeriesList?.filters && timeSeriesList.filters.length > 0) { + for (const filter of timeSeriesList.filters) { + if (filter === '') { + filtersComplete = false; + break; + } + } + } onQueryChange({ ...query, timeSeriesList }); - onRunQuery(); + if (filtersComplete) { + onRunQuery(); + } }, [onQueryChange, onRunQuery, query] ); From f04c5d39f53ad13a62bc6928fe5a5d269d9bfa87 Mon Sep 17 00:00:00 2001 From: Larissa Wandzura <126723338+lwandz13@users.noreply.github.com> Date: Fri, 22 Mar 2024 14:20:53 -0500 Subject: [PATCH 099/138] [v10.4.x] Docs: Fixed a typo in the Azure config page (#84862) Docs: Fixed a typo in the Azure config page (#84475) fixed typo, cleaned up some language (cherry picked from commit f727e2187362bb707fc23853f199446de759e6d6) --- .../configure-authentication/azuread/index.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/sources/setup-grafana/configure-security/configure-authentication/azuread/index.md b/docs/sources/setup-grafana/configure-security/configure-authentication/azuread/index.md index 1197769d0b5c..8d0b79451e74 100644 --- a/docs/sources/setup-grafana/configure-security/configure-authentication/azuread/index.md +++ b/docs/sources/setup-grafana/configure-security/configure-authentication/azuread/index.md @@ -21,6 +21,10 @@ weight: 800 The Azure AD authentication allows you to use an Azure Active Directory tenant as an identity provider for Grafana. You can use Azure AD application roles to assign users and groups to Grafana roles from the Azure Portal. +{{% admonition type="note" %}} +If Users use the same email address in Azure AD that they use with other authentication providers (such as Grafana.com), you need to do additional configuration to ensure that the users are matched correctly. Please refer to [Using the same email address to login with different identity providers]({{< relref "../../configure-authentication#using-the-same-email-address-to-login-with-different-identity-providers" >}}) for more information. +{{% /admonition %}} + ## Create the Azure AD application To enable the Azure AD OAuth2, register your application with Azure AD. @@ -171,7 +175,7 @@ Ensure that you have followed the steps in [Create the Azure AD application](#cr Available in Public Preview in Grafana 10.4 behind the `ssoSettingsApi` feature toggle. {{% /admonition %}} -As a Grafana Admin, you can configure your Azure AD OAuth2 client from within Grafana using the GitLab UI. To do this, navigate to **Administration > Authentication > Azure AD** page and fill in the form. If you have a current configuration in the Grafana configuration file, the form will be pre-populated with those values. Otherwise the form will contain default values. +As a Grafana Admin, you can configure your Azure AD OAuth2 client from within Grafana using the Grafana UI. To do this, navigate to the **Administration > Authentication > Azure AD** page and fill in the form. If you have a current configuration in the Grafana configuration file, the form will be pre-populated with those values. Otherwise the form will contain default values. After you have filled in the form, click **Save** to save the configuration. If the save was successful, Grafana will apply the new configurations. From a678a464be0aa0c353a09fbae09e7a91db02adf6 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Mon, 25 Mar 2024 05:33:32 -0700 Subject: [PATCH 100/138] [v10.4.x] alerting: get started tutorial (#85072) alerting: get started tutorial (#84669) * first commit * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: Gilles De Mey * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: Gilles De Mey * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: Gilles De Mey * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: Gilles De Mey * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: Gilles De Mey * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: Gilles De Mey * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: Gilles De Mey * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: Gilles De Mey * second commit * updated headings * Update alerting-get-started.md * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * third commit * Update alerting-get-started.md * Update alerting-get-started.md * Update alerting-get-started.md * edited contact point - summary * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/tutorials/alerting-get-started/alerting-get-started.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * elaboration, formatting * minor changes * pretty --------- Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> Co-authored-by: Gilles De Mey (cherry picked from commit 4be5eaa14f9c6f3d5a37eddccd29f2ba75313877) Co-authored-by: tonypowa <45235678+tonypowa@users.noreply.github.com> --- .../alerting-get-started.md | 206 ++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 docs/sources/tutorials/alerting-get-started/alerting-get-started.md diff --git a/docs/sources/tutorials/alerting-get-started/alerting-get-started.md b/docs/sources/tutorials/alerting-get-started/alerting-get-started.md new file mode 100644 index 000000000000..2b30932f90a6 --- /dev/null +++ b/docs/sources/tutorials/alerting-get-started/alerting-get-started.md @@ -0,0 +1,206 @@ +# Introduction + +In this guide, we'll walk you through the process of setting up your first alert in just a few minutes. You'll witness your alert in action with real-time data, as well as sending alert notifications. + +In this tutorial you will: + +- Set up an Alert +- Send an alert notification to a public webhook. + +# Before you begin + +Ensure you have the following applications installed. + +- [Docker Compose](https://docs.docker.com/get-docker/) (included in Docker for Desktop for macOS and Windows) +- [Git](https://git-scm.com/) + +## Set up a sample application + +The sample application generates real data and exposes metrics, which are stored in Prometheus. In Grafana Alerting, you can then build an alert rule based on the data generated. + +Download the files to your local machine. + +1. Clone the [tutorial environment repository](www.github.com/grafana/tutorial-environment). + + ``` + git clone https://github.com/grafana/tutorial-environment.git + ``` + +1. Change to the directory where you cloned the repository: + + ``` + cd tutorial-environment + ``` + +1. Make sure Docker is running: + + ``` + docker --version + ``` + + This command will display the installed Docker version if the installation was successful. + +1. Start the sample application: + + ``` + docker compose up -d + ``` + + The first time you run `docker compose up -d`, Docker downloads all the necessary resources for the tutorial. This might take a few minutes, depending on your internet connection. + + {{< admonition type="note" >}} + If you already have Grafana, Loki, or Prometheus running on your system, you might see errors, because the Docker image is trying to use ports that your local installations are already using. . If this is the case, stop the services, then run the command again. + {{< /admonition >}} + +1. Ensure all services are up-and-running: + + ``` + docker compose ps + ``` + + In the State column, it should say Up for all services. + +The Grafana News app should be live on [localhost:8081](http://localhost:8081/). + +## Generate data + +To enhance the hands-on aspect of this tutorial, you can actively participate in the Grafana News application to simulate web traffic and interactions. This enables you to observe data within Grafana and set up alerts accordingly. + +### Grafana News + +Grafana News is an application created to demonstrate the observation of data using the Grafana stack. It achieves this by generating web traffic through activities such as posting links and voting for your preferred ones. + +To add a link: + +1. Enter a **Title** +1. Enter a **URL** +1. Click **Submit** to add the link. + The link will appear listed under the Grafana News heading. +1. To vote for a link, click the triangle icon next to the name of the link. + +## Log in to Grafana + +Besides being an open-source observability tool, Grafana has its own built-in alerting service. This means that you can receive notifications whenever there is an event of interest in your data, and even see these events graphed in your visualizations. + +In your browser, navigate to [localhost:3000](http://localhost:3000). +You should get logged in automatically + +## Create a contact point for Grafana Managed Alerts + +In this step, we'll set up a new contact point. This contact point will use the _webhooks_ channel. In order to make this work, we also need an endpoint for our webhook channel to receive the alert. We will use [requestbin.com](https://requestbin.com) to quickly set up that test endpoint. This way we can make sure that our alert is actually sending a notification somewhere. + +1. Browse to [requestbin.com](https://requestbin.com). +1. Under the **Create Request Bin** button, click the link to create a **public bin** instead. +1. From Request Bin, copy the endpoint URL. + +Your Request Bin is now waiting for the first request. + +Next, let's configure a Contact Point in Grafana's Alerting UI to send notifications to our Request Bin. + +1. Return to Grafana. In Grafana's sidebar, hover over the **Alerting** (bell) icon and then click **Contact points**. +1. Click **+ Add contact point**. +1. In **Name**, write **RequestBin**. +1. In **Integration**, choose **Webhook**. +1. In **URL**, paste the endpoint to your request bin. + +1. Click **Test**, and then click **Send test notification** to send a test alert to your request bin. +1. Navigate back to the Request Bin you created earlier. On the left side, there's now a `POST /` entry. Click it to see what information Grafana sent. +1. Return to Grafana and click **Save contact point**. + +We have now created a dummy webhook endpoint and created a new Alerting Contact Point in Grafana. Now we can create an alert rule and link it to this new channel. + +## Create an alert + +Next, we'll establish an alert within Grafana Alerting to notify us whenever our sample app experiences a specific volume of requests. + +In Grafana, **navigate to Alerting** > **Alert rules**. Click on **New alert rule**. + +## Enter alert rule name + +1. Make it short and descriptive as this will appear in your alert notification. For instance, **server-requests-duration** + +## Define query and alert condition + +In this section, we define queries, expressions (used to manipulate the data), and the condition that must be met for the alert to be triggered. + +1. Select the **Prometheus** data source from the drop-down menu. + + {{< admonition type="note" >}} + To visualize this data in Grafana, we need time-series metrics that we can collect and store. We can do that with [Prometheus](https://grafana.com/docs/grafana/latest/getting-started/get-started-grafana-prometheus/), which pulls metrics from our sample app. + {{< /admonition >}} + +1. In the Query editor, switch to **Code** mode by clicking the button at the right. +1. Enter the query + + ``` + sum(rate(tns_request_duration_seconds_count[1m])) by(method) + ``` + + This [PromQL](https://prometheus.io/docs/prometheus/latest/querying/basics/) query calculates the sum of the per-second average rates of increase of the `tns_request_duration_seconds_count` metric over the last 1 minute, grouped by the HTTP method used in the requests. This can be useful for analyzing the request duration trends for different HTTP methods. + +1. Keep expressions “B” and “C” as they are. These expressions (**Reduce** and **Threshold**, respectively) come by default when creating a new rule. + The Reduce expression “B”, selects the last value of our query “A”, while the Threshold expression “C” will check if the last value from expression “B” is above a specific value. In addition, the Threshold expression is the alert condition by default. Enter `0.2` as threshold value. You can read more about queries and conditions [here](https://grafana.com/docs/grafana/latest/alerting/fundamentals/alert-rules/queries-conditions/#expression-queries). + +1. Click Preview to run the queries. + +You should see the request duration for different HTTP methods. + +{{}} +If it returns “No data,” or an error, you are welcome to post questions in our [Grafana Community forum](https://community.grafana.com/). +{{}} + +## Set evaluation behavior + +An evaluation group defines an evaluation interval - how often a rule is checked. Alert rules within the same evaluation group are evaluated sequentially + +1. In **Folder**, click **+ New folder** and enter a name. For example: _grafana-news_. This folder will contain our alerts. +1. In the **Evaluation group**, repeat the above step to create a new evaluation group. We will name it _1m-evaluation_. +1. Choose an **Evaluation interval** (how often the alert will be evaluated). + For example, every `1m` (1 minute). +1. Set the **pending period** (the “for” period). + This is the time that a condition has to be met until the alert enters into **Firing** state and a notification is sent. For example, `0s` (zero seconds) so the alert rule fires the moment the condition is met. + +## Configure labels and notifications + +Add labels to ease searching or route notifications to a policy. + +### Labels + +1. Add `app` as the label key, and `grafana-news` as the value + +### Notifications + +Select who should receive a notification when an alert rule fires. + +1. Under **Contact point**, select **RequestBin** from the drop-down menu. + +## Add Annotations + +To provide more context on the alert, you can link a dashboard and panel to our Alert. For that, click **Link Dashboard and panel** button. + +Linking an alert rule to a panel adds an annotation to the panel when the status of your alert rulechanges. If you don’t have a panel already, and since this is optional, you can skip this step for now and link it after you have finished configuring the alert rule. + +Click **Save rule and exit** at the top right corner. + +## Trigger an alert + +We have now configured an alert rule and a contact point. Now let’s see if we can trigger an alert by generating some traffic on our sample application. + +1. Browse to [localhost:8081](http://localhost:8081/). +1. Add a new title and URL. +1. Repeatedly click the vote button or refresh the page to generate a traffic spike. + +Once the query `sum(rate(tns_request_duration_seconds_count[1m])) by(method)` returns a value greater than `0.2`, Grafana will trigger our alert. Browse to the Request Bin we created earlier and find the sent Grafana alert notification with details and metadata. + +## Summary + +In this tutorial, you have learned how to set up an alert, send alert notifications to a public webhook, and generate some sample data to observe your alert in action. By following these steps, you've gained a foundational understanding of how to leverage Grafana's alerting capabilities to monitor and respond to events of interest in your data. Happy monitoring! + +# Learn more + +Check out the links below to continue your learning journey with Grafana's LGTM stack. + +- [Prometheus](/docs/grafana//features/datasources/prometheus/) +- [Alerting Overview](/docs/grafana//alerting/) +- [Alert rules](/docs/grafana//alerting/create-alerts/) +- [Contact Points](/docs/grafana//alerting/notifications/) From 6c09bfa2a0cbc70fc61e272f5c294e665c22bcc3 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Mon, 25 Mar 2024 12:25:04 -0400 Subject: [PATCH 101/138] [v10.4.x] docs: update text panel documentation (#85098) docs: update text panel documentation (#84884) * docs: update text panel * Apply suggestions from code review Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --------- Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> (cherry picked from commit 44ae127a6e8fa3db2c11f288fc36777e81f1cb03) Co-authored-by: Marie Cruz --- .../panels-visualizations/visualizations/text/index.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/sources/panels-visualizations/visualizations/text/index.md b/docs/sources/panels-visualizations/visualizations/text/index.md index eb003b96df1b..51276ae365a7 100644 --- a/docs/sources/panels-visualizations/visualizations/text/index.md +++ b/docs/sources/panels-visualizations/visualizations/text/index.md @@ -23,6 +23,16 @@ weight: 100 Text visualizations enable you to directly include text or HTML in your dashboards. This can be used to add contextual information and descriptions or embed complex HTML. +For example, if you want to display important links to your dashboard, you can use a text visualization to add these links: + +{{< figure src="/static/img/docs/text-panel/text-panel.png" max-width="1025px" alt="A text panel showing important links" >}} + +Use a text visualization when you need to: + +- Add important links or useful annotations. +- Provide instructions or guidance on how to interpret different panels, configure settings, or take specific actions based on the displayed data. +- Announce any scheduled maintenance or downtime that might impact your dashboards. + ## Mode **Mode** determines how embedded content appears. From 01395e3291d1431474b39f966d528adf4c0fc590 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Mon, 25 Mar 2024 12:28:08 -0400 Subject: [PATCH 102/138] [v10.4.x] docs: updates to stat panel documentation (#85101) docs: updates to stat panel documentation (#84814) * docs: updates to stat panel documentation * Apply suggestions from code review Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> * Made formatting and wording edit --------- Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> Co-authored-by: Isabel Matwawana (cherry picked from commit 34195ba854b167b3a4b2ad9e218124ade9efac56) Co-authored-by: Marie Cruz --- .../visualizations/stat/index.md | 68 ++++++++++++++++--- 1 file changed, 59 insertions(+), 9 deletions(-) diff --git a/docs/sources/panels-visualizations/visualizations/stat/index.md b/docs/sources/panels-visualizations/visualizations/stat/index.md index ca51b1c77457..2466fb366c7a 100644 --- a/docs/sources/panels-visualizations/visualizations/stat/index.md +++ b/docs/sources/panels-visualizations/visualizations/stat/index.md @@ -21,24 +21,74 @@ weight: 100 # Stat -Stats show one large stat value with an optional graph sparkline. You can control the background or value color using thresholds or overrides. - -{{< figure src="/static/img/docs/v66/stat_panel_dark3.png" max-width="1025px" caption="Stat visualization" >}} - {{% admonition type="note" %}} This visualization replaces the Singlestat visualization, which was deprecated in Grafana 7.0 and removed in Grafana 8.0. {{% /admonition %}} +A stat visualization displays your data in single values of interest—such as the latest or current value of a series—with an optional graph sparkline. A graph sparkline, which is only available in stat visualizations, is a small time-series graph shown in the background of each value in the visualization. + +For example, if you're monitoring the utilization of various services, you can use a stat visualization to show their latest usage: + +{{< figure src="/static/img/docs/v66/stat_panel_dark3.png" max-width="1025px" alt="A stat panel showing latest usage of various services" >}} + +Use a stat visualization when you need to: + +- Monitor key metrics at a glance, such as the latest health of your application, number of high priority bugs in your application, or total number of sales. +- Display aggregated data, such as the average response time of your services. +- Highlight values above your normal thresholds to quickly identify if any metrics are outside your expected range. + +## Configure a stat visualization + +Once you've [created a dashboard](https://grafana.com/docs/grafana//dashboards/build-dashboards/create-dashboard/), the following video shows you how to configure a stat visualization: + +{{< youtube id="yNRnLyVntUw" start="1048" >}} + +Alternatively, refer to this blog post on [how to easily retrieve values from a range in Grafana using a stat visualization](https://grafana.com/blog/2023/10/18/how-to-easily-retrieve-values-from-a-range-in-grafana-using-a-stat-panel/). + +## Supported data formats + +The stat visualization supports a variety of formats for displaying data. Supported formats include: + +- **Single values** - The most common format and can be numerical, strings, or boolean values. +- **Time-series data** - [Calculation types][] can be applied to your time-series data to display single values over a specified time range. + +### Examples + +The following tables are examples of the type of data you need for a stat visualization and how it should be formatted. + +#### Single numerical values + +| Number of high priority bugs | +| ---------------------------- | +| 80 | +| 52 | +| 59 | +| 40 | + +The data is visualized as follows, with the last value displayed, along with a sparkline and [percentage change](#show-percent-change): + +{{< figure src="/static/img/docs/stat-panel/stat_panel_single.png" max-width="1025px" alt="A stat panel showing the latest number of high priority bugs" >}} + +#### Time-series data + +| Time | Cellar | Living room | Porch | Bedroom | Guest room | Kitchen | +| ------------------- | ------ | ----------- | ----- | ------- | ---------- | ------- | +| 2024-03-20 06:34:40 | 12.3 | 18.3 | 18.8 | 15.9 | 9.29 | 9.61 | +| 2024-03-20 06:41:40 | 16.8 | 17.1 | 21.5 | 14.1 | 10.5 | 17.5 | +| 2024-03-20 06:48:40 | 16.7 | 18.0 | 21.0 | 9.51 | 13.6 | 20.1 | +| 2024-03-20 06:55:40 | 14.3 | 18.7 | 16.5 | 9.11 | 14.8 | 12.5 | +| 2024-03-20 07:02:40 | 12.8 | 15.2 | 21.1 | 15.6 | 7.98 | 13.0 | + +The data is visualized as follows, with the mean value displayed for each room, along with the room name, sparkline, and unit of measurement: + +{{< figure src="/static/img/docs/stat-panel/stat_panel_multiple.png" max-width="1025px" alt="A stat panel showing some statistics for each room in square meters" >}} + By default, a stat displays one of the following: - Just the value for a single series or field. - Both the value and name for multiple series or fields. -You can use the **Text mode** to control how the text is displayed. - -Example screenshot: - -{{< figure src="/static/img/docs/v71/stat-panel-text-modes.png" max-width="1025px" caption="Stat visualization" >}} +You can use the [**Text mode**](#text-mode) to control how the text is displayed. ## Automatic layout adjustment From 6a8944a76e146e2f3d31cfac1475cc7d249d9d2d Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Mon, 25 Mar 2024 12:34:48 -0400 Subject: [PATCH 103/138] [v10.4.x] docs: update status history panel (#85105) docs: update status history panel (#84939) * docs: updates to status history panel documentation * docs: updates to status history panel documentation * Apply suggestions from code review Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> * fix: linting issues --------- Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> (cherry picked from commit 15dca455147ac7aae55884da3481c880f3645e06) Co-authored-by: Marie Cruz --- .../visualizations/state-timeline/index.md | 2 - .../visualizations/status-history/index.md | 72 +++++++++++++++---- 2 files changed, 60 insertions(+), 14 deletions(-) diff --git a/docs/sources/panels-visualizations/visualizations/state-timeline/index.md b/docs/sources/panels-visualizations/visualizations/state-timeline/index.md index add92e9968f8..92e916b6ef35 100644 --- a/docs/sources/panels-visualizations/visualizations/state-timeline/index.md +++ b/docs/sources/panels-visualizations/visualizations/state-timeline/index.md @@ -33,8 +33,6 @@ The state timeline visualization is useful when you need to monitor and analyze ## Configure a state timeline -Once you have [created a dashboard](https://grafana.com/docs/grafana//dashboards/build-dashboards/create-dashboard/), the following video shows you how to configure a state timeline: - {{< youtube id="a9wZHM0mdxo" >}} ## Supported data formats diff --git a/docs/sources/panels-visualizations/visualizations/status-history/index.md b/docs/sources/panels-visualizations/visualizations/status-history/index.md index b3e9c5e6837d..a985512a681c 100644 --- a/docs/sources/panels-visualizations/visualizations/status-history/index.md +++ b/docs/sources/panels-visualizations/visualizations/status-history/index.md @@ -19,15 +19,70 @@ weight: 100 # Status history -Status histories show periodic states over time. Each field or series is rendered as a horizontal row. Boxes are rendered and centered around each value. +A status history visualization displays data in a way that shows periodic states over time. In a status history, each field or series is rendered as a horizontal row, with multiple boxes showing the different statuses. This provides you with a centralized view for the status of a component or service. -{{< figure src="/static/img/docs/status-history-panel/status-history-example-v8-0.png" max-width="1025px" caption="Status history example" >}} +For example, if you're monitoring the health status of different services, you can use a status history to visualize the different statuses, such as “OK,” “WARN,” or “BAD,” over time. Each status is represented by a different color: -## Supported data +{{< figure src="/static/img/docs/status-history-panel/status-history-example-v8-0.png" max-width="1025px" alt="A status history panel showing the health status of different services" >}} -A status history works with string, boolean and numerical fields or time series. A time field is required. You can use value mappings to color strings or assign text values to numerical ranges. +{{% admonition type="note" %}} +A status history is similar to a [state timeline](https://grafana.com/docs/grafana//panels-visualizations/visualizations/state-timeline/), but has different [configuration options](#status-history-options). Unlike state timelines, status histories don't merge consecutive values. +{{% /admonition %}} -## Display options +Use a status history when you need to: + +- Monitor the status of a server, application, or service to know when your infrastructure is experiencing issues over time. +- Identify operational trends over time. +- Spot any recurring issues with the health of your applications. + +## Configure a status history + +Once you've [created a dashboard](https://grafana.com/docs/grafana//dashboards/build-dashboards/create-dashboard/), you can use the following state timeline video as a reference for how to configure a status history: + +{{< youtube id="a9wZHM0mdxo" >}} + +## Supported data formats + +The status history visualization works best if you have data capturing the various status of entities over time, formatted as a table. The data must include: + +- **Timestamps** - Indicate when each status change occurred. This could also be the start time for the status change. You can also add an optional timestamp to indicate the end time for the status change. +- **Entity name/identifier** - Represents the name of the entity you're trying to monitor. +- **Status value** - Represents the state value of the entity you're monitoring. These can be string, numerical, or boolean states. + +### Examples + +The following tables are examples of the type of data you need for a status history visualization and how it should be formatted. + +#### Single time column with null values + +| Timestamps | Backend_01 | Backend_02 | +| ------------------ | ---------- | ---------- | +| 2024-02-29 8:00:00 | OK | WARN | +| 2024-02-29 8:15:00 | WARN | | +| 2024-02-29 8:18:00 | | WARN | +| 2024-02-29 8:30:00 | BAD | | +| 2024-02-29 8:36:00 | | OK | +| 2024-02-29 8:45:00 | OK | | + +The data is converted as follows, with the null and empty values visualized as gaps in the status history: + +{{< figure src="/static/img/docs/status-history-panel/status_history_with_null.png" max-width="1025px" alt="A status history panel with null values showing the status of two servers" >}} + +#### Two time columns without null values + +| Start time | End time | Backend_01 | Backend_02 | +| ------------------ | ------------------ | ---------- | ---------- | +| 2024-02-29 8:00:00 | 2024-02-29 8:15:00 | OK | OK | +| 2024-02-29 8:15:00 | 2024-02-29 8:30:00 | OK | OK | +| 2024-02-29 8:30:00 | 2024-02-29 8:45:00 | OK | OK | +| 2024-02-29 8:45:00 | 2024-02-29 9:00:00 | BAD | WARN | +| 2024-02-29 9:00:00 | 2024-02-29 9:15:00 | OK | WARN | + +The data is converted as follows: + +{{< figure src="/static/img/docs/status-history-panel/status_history.png" max-width="1025px" alt="A status history panel with two time columns showing the status of two servers" >}} + +## Status history options Use these options to refine the visualization. @@ -53,13 +108,6 @@ To assign colors to boolean or string values, use the [Value mappings][]. {{< figure src="/static/img/docs/v8/value_mappings_side_editor.png" max-width="300px" caption="Value mappings side editor" >}} -## Time series data with thresholds - -The visualization can be used with time series data as well. In this case, the thresholds are used to color the boxes. You can also -use gradient color schemes to color values. - -{{< figure src="/static/img/docs/v8/state_timeline_time_series.png" max-width="1025px" caption="state timeline with time series" >}} - ## Legend options When the legend option is enabled it can show either the value mappings or the threshold brackets. To show the value mappings in the legend, it's important that the `Color scheme` as referenced in [Color scheme][] is set to `Single color` or `Classic palette`. To see the threshold brackets in the legend set the `Color scheme` to `From thresholds`. From e1fc1e9a13b757e2fa99eeef9f9c89a06bf742c7 Mon Sep 17 00:00:00 2001 From: Will Browne Date: Mon, 25 Mar 2024 20:27:55 +0100 Subject: [PATCH 104/138] [v10.4.x] Chore: Update grafana-plugin-sdk (#85087) * Chore: Update grafana-plugin-sdk (#84289) (cherry picked from commit 265200799d9f142622a99f3561e1864f84216ecd) * Re-generate openapi --------- Co-authored-by: Andres Martinez Gotor Co-authored-by: Giuseppe Guerra --- go.mod | 54 +++++------ go.sum | 91 +++++++++++-------- pkg/services/datasources/datasources.go | 2 +- .../fakes/fake_datasource_service.go | 2 +- .../datasources/service/datasource.go | 10 +- .../datasources/service/datasource_test.go | 28 ++++-- pkg/services/ngalert/sender/notifier_ext.go | 12 ++- pkg/services/ngalert/sender/sender.go | 6 +- pkg/tsdb/azuremonitor/httpclient.go | 2 +- pkg/tsdb/azuremonitor/httpclient_test.go | 12 +-- pkg/tsdb/prometheus/client/transport_test.go | 3 +- pkg/tsdb/tempo/grpc.go | 8 +- public/api-merged.json | 8 +- public/openapi3.json | 8 +- 14 files changed, 139 insertions(+), 107 deletions(-) diff --git a/go.mod b/go.mod index afbd6c73678e..f6da3e46fcf1 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ replace github.com/prometheus/prometheus => github.com/prometheus/prometheus v0. replace github.com/getkin/kin-openapi => github.com/getkin/kin-openapi v0.120.0 require ( - cloud.google.com/go/storage v1.30.1 // @grafana/backend-platform + cloud.google.com/go/storage v1.36.0 // @grafana/backend-platform cuelang.org/go v0.6.0-0.dev // @grafana/grafana-as-code github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // @grafana/partner-datasources github.com/Azure/go-autorest/autorest v0.11.29 // @grafana/backend-platform @@ -63,7 +63,7 @@ require ( github.com/grafana/cuetsy v0.1.11 // @grafana/grafana-as-code github.com/grafana/grafana-aws-sdk v0.23.1 // @grafana/aws-datasources github.com/grafana/grafana-azure-sdk-go v1.12.0 // @grafana/partner-datasources - github.com/grafana/grafana-plugin-sdk-go v0.211.0 // @grafana/plugins-platform-backend + github.com/grafana/grafana-plugin-sdk-go v0.215.0 // @grafana/plugins-platform-backend github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // @grafana/backend-platform github.com/hashicorp/go-hclog v1.6.2 // @grafana/plugins-platform-backend github.com/hashicorp/go-plugin v1.6.0 // @grafana/plugins-platform-backend @@ -101,20 +101,20 @@ require ( github.com/yalue/merged_fs v1.2.2 // @grafana/grafana-as-code github.com/yudai/gojsondiff v1.0.0 // @grafana/backend-platform go.opentelemetry.io/collector/pdata v1.0.1 // @grafana/backend-platform - go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.46.1 // @grafana/grafana-operator-experience-squad + go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.49.0 // @grafana/grafana-operator-experience-squad go.opentelemetry.io/otel/exporters/jaeger v1.10.0 // @grafana/backend-platform - go.opentelemetry.io/otel/sdk v1.22.0 // @grafana/backend-platform - go.opentelemetry.io/otel/trace v1.22.0 // @grafana/backend-platform - golang.org/x/crypto v0.18.0 // @grafana/backend-platform + go.opentelemetry.io/otel/sdk v1.24.0 // @grafana/backend-platform + go.opentelemetry.io/otel/trace v1.24.0 // @grafana/backend-platform + golang.org/x/crypto v0.19.0 // @grafana/backend-platform golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb // @grafana/alerting-squad-backend - golang.org/x/net v0.20.0 // @grafana/oss-big-tent @grafana/partner-datasources + golang.org/x/net v0.21.0 // @grafana/oss-big-tent @grafana/partner-datasources golang.org/x/oauth2 v0.16.0 // @grafana/grafana-authnz-team golang.org/x/sync v0.6.0 // @grafana/alerting-squad-backend golang.org/x/time v0.5.0 // @grafana/backend-platform golang.org/x/tools v0.17.0 // @grafana/grafana-as-code gonum.org/v1/gonum v0.12.0 // @grafana/observability-metrics - google.golang.org/api v0.153.0 // @grafana/backend-platform - google.golang.org/grpc v1.60.1 // @grafana/plugins-platform-backend + google.golang.org/api v0.155.0 // @grafana/backend-platform + google.golang.org/grpc v1.62.1 // @grafana/plugins-platform-backend google.golang.org/protobuf v1.32.0 // @grafana/plugins-platform-backend gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/ini.v1 v1.67.0 // @grafana/alerting-squad-backend @@ -162,7 +162,7 @@ require ( github.com/go-openapi/validate v0.23.0 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // @grafana/backend-platform github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect - github.com/golang/glog v1.1.2 // indirect + github.com/golang/glog v1.2.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // @grafana/backend-platform github.com/google/btree v1.1.2 // indirect @@ -214,11 +214,11 @@ require ( go.opencensus.io v0.24.0 // indirect go.uber.org/atomic v1.11.0 // @grafana/alerting-squad-backend go.uber.org/goleak v1.3.0 // indirect - golang.org/x/sys v0.16.0 // indirect + golang.org/x/sys v0.17.0 // indirect golang.org/x/text v0.14.0 // @grafana/backend-platform golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20231212172506-995d672761c0 // indirect; @grafana/backend-platform + google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect; @grafana/backend-platform ) require ( @@ -243,10 +243,10 @@ require ( github.com/jmoiron/sqlx v1.3.5 // @grafana/backend-platform github.com/matryer/is v1.4.0 // @grafana/grafana-as-code github.com/urfave/cli v1.22.14 // @grafana/backend-platform - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 // @grafana/plugins-platform-backend + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // @grafana/plugins-platform-backend go.opentelemetry.io/contrib/propagators/jaeger v1.22.0 // @grafana/backend-platform - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // @grafana/backend-platform - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 // @grafana/backend-platform + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // @grafana/backend-platform + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 // @grafana/backend-platform gocloud.dev v0.25.0 // @grafana/grafana-app-platform-squad ) @@ -256,7 +256,7 @@ require ( github.com/Masterminds/semver/v3 v3.1.1 // @grafana/grafana-release-guild github.com/alicebob/miniredis/v2 v2.30.1 // @grafana/alerting-squad-backend github.com/dave/dst v0.27.2 // @grafana/grafana-as-code - github.com/go-jose/go-jose/v3 v3.0.1 // @grafana/grafana-authnz-team + github.com/go-jose/go-jose/v3 v3.0.3 // @grafana/grafana-authnz-team github.com/grafana/dataplane/examples v0.0.1 // @grafana/observability-metrics github.com/grafana/dataplane/sdata v0.0.7 // @grafana/observability-metrics github.com/grafana/kindsys v0.0.0-20230508162304-452481b63482 // @grafana/grafana-as-code @@ -266,7 +266,7 @@ require ( github.com/ory/fosite v0.44.1-0.20230317114349-45a6785cc54f // @grafana/grafana-authnz-team github.com/redis/go-redis/v9 v9.0.2 // @grafana/alerting-squad-backend github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // @grafana/grafana-as-code - go.opentelemetry.io/contrib/samplers/jaegerremote v0.16.0 // @grafana/backend-platform + go.opentelemetry.io/contrib/samplers/jaegerremote v0.18.0 // @grafana/backend-platform golang.org/x/mod v0.14.0 // @grafana/backend-platform gopkg.in/square/go-jose.v2 v2.6.0 // @grafana/grafana-authnz-team k8s.io/utils v0.0.0-20230726121419-3b25d923346b // @grafana/partner-datasources @@ -274,7 +274,7 @@ require ( require ( github.com/spf13/cobra v1.8.0 // @grafana/grafana-app-platform-squad - go.opentelemetry.io/otel v1.22.0 // @grafana/backend-platform + go.opentelemetry.io/otel v1.24.0 // @grafana/backend-platform k8s.io/api v0.29.0 // @grafana/grafana-app-platform-squad k8s.io/apimachinery v0.29.0 // @grafana/grafana-app-platform-squad k8s.io/apiserver v0.29.0 // @grafana/grafana-app-platform-squad @@ -282,7 +282,7 @@ require ( k8s.io/component-base v0.29.0 // @grafana/grafana-app-platform-squad k8s.io/klog/v2 v2.110.1 // @grafana/grafana-app-platform-squad k8s.io/kube-aggregator v0.29.0 // @grafana/grafana-app-platform-squad - k8s.io/kube-openapi v0.0.0-20231214164306-ab13479f8bf8 // @grafana/grafana-app-platform-squad + k8s.io/kube-openapi v0.0.0-20240220201932-37d671a357a5 // @grafana/grafana-app-platform-squad ) require github.com/grafana/gofpdf v0.0.0-20231002120153-857cc45be447 // @grafana/sharing-squad @@ -294,7 +294,7 @@ require github.com/grafana/pyroscope-go/godeltaprof v0.1.6 // @grafana/observabi require github.com/apache/arrow/go/v15 v15.0.0 // @grafana/observability-metrics require ( - cloud.google.com/go v0.111.0 // indirect + cloud.google.com/go v0.112.0 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect github.com/Azure/azure-pipeline-go v0.2.3 // indirect github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect @@ -398,14 +398,14 @@ require ( go.etcd.io/etcd/api/v3 v3.5.10 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.10 // indirect go.etcd.io/etcd/client/v3 v3.5.10 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect - go.opentelemetry.io/otel/metric v1.22.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect - golang.org/x/term v0.16.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 // indirect + golang.org/x/term v0.17.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect @@ -454,7 +454,7 @@ require ( github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 // indirect github.com/go-logr/logr v1.4.1 // @grafana/grafana-app-platform-squad github.com/go-logr/stdr v1.2.2 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect github.com/hmarr/codeowners v1.1.2 // @grafana/grafana-as-code github.com/imdario/mergo v0.3.16 // indirect github.com/klauspost/compress v1.17.4 // indirect @@ -467,7 +467,7 @@ require ( github.com/valyala/fasttemplate v1.2.2 // indirect github.com/wk8/go-ordered-map v1.0.0 // @grafana/backend-platform github.com/xlab/treeprint v1.2.0 // @grafana/observability-traces-and-profiling - go.opentelemetry.io/proto/otlp v1.0.0 // indirect + go.opentelemetry.io/proto/otlp v1.1.0 // indirect ) require ( diff --git a/go.sum b/go.sum index cc8f43450665..81c8d674e237 100644 --- a/go.sum +++ b/go.sum @@ -52,8 +52,8 @@ cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5x cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk= cloud.google.com/go v0.110.9/go.mod h1:rpxevX/0Lqvlbc88b7Sc1SPNdyK1riNBTUU6JXhYNpM= cloud.google.com/go v0.110.10/go.mod h1:v1OoFqYxiBkUrruItNM3eT4lLByNjxmJSV/xDKJNnic= -cloud.google.com/go v0.111.0 h1:YHLKNupSD1KqjDbQ3+LVdQ81h/UJbJyZG203cEfnQgM= -cloud.google.com/go v0.111.0/go.mod h1:0mibmpKP1TyOOFYQY5izo0LnT+ecvOQ0Sg3OdmMiNRU= +cloud.google.com/go v0.112.0 h1:tpFCD7hpHFlQ8yPwT3x+QeXqc2T6+n6T+hmABHfDUSM= +cloud.google.com/go v0.112.0/go.mod h1:3jEEVwZ/MHU4djK5t5RHuKOA/GbLddgTdVubX1qnPD4= cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= @@ -1037,8 +1037,9 @@ cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeL cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= -cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM= cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= +cloud.google.com/go/storage v1.36.0 h1:P0mOkAcaJxhCTvAkMhxMfrTKiNcub4YmmPBtlhAyTr8= +cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= @@ -1568,8 +1569,9 @@ github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230428030218-4003588d1b74/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= +github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E= github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw= @@ -1746,16 +1748,18 @@ github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go. github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q= -github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1MyGqJ2DIk5HpM= github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= +github.com/envoyproxy/go-control-plane v0.12.0 h1:4X+VP1GHd1Mhj6IB5mMeGbLCleqxjletLK6K0rbxyZI= +github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= github.com/envoyproxy/protoc-gen-validate v1.0.1/go.mod h1:0vj8bNkYbSTNS2PIyH87KZaeN4x9zpL9Qt8fQC7d+vs= -github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= +github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= +github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= @@ -1825,8 +1829,8 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= -github.com/go-jose/go-jose/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA= -github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= +github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= +github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= @@ -2311,8 +2315,9 @@ github.com/golang/gddo v0.0.0-20190904175337-72a348e765d2/go.mod h1:xEhNfoBDX1hz github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= -github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= +github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68= +github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -2530,8 +2535,8 @@ github.com/grafana/grafana-google-sdk-go v0.1.0/go.mod h1:Vo2TKWfDVmNTELBUM+3lkr github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79 h1:r+mU5bGMzcXCRVAuOrTn54S80qbfVkvTdUJZfSfTNbs= github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79/go.mod h1:wc6Hbh3K2TgCUSfBC/BOzabItujtHMESZeFk5ZhdxhQ= github.com/grafana/grafana-plugin-sdk-go v0.114.0/go.mod h1:D7x3ah+1d4phNXpbnOaxa/osSaZlwh9/ZUnGGzegRbk= -github.com/grafana/grafana-plugin-sdk-go v0.211.0 h1:hYtieOoYvsv/BcFbtspml4OzfuYrv1d14nESdf13qxQ= -github.com/grafana/grafana-plugin-sdk-go v0.211.0/go.mod h1:qsI4ktDf0lig74u8SLPJf9zRdVxWV/W4Wi+Ox6gifgs= +github.com/grafana/grafana-plugin-sdk-go v0.215.0 h1:02gwVsqYi1I+U48/MQR61eOMxiXE7KNKC8QsiMJ//qA= +github.com/grafana/grafana-plugin-sdk-go v0.215.0/go.mod h1:nBsh3jRItKQUXDF2BQkiQCPxqrsSQeb+7hiFyJTO1RE= github.com/grafana/kindsys v0.0.0-20230508162304-452481b63482 h1:1YNoeIhii4UIIQpCPU+EXidnqf449d0C3ZntAEt4KSo= github.com/grafana/kindsys v0.0.0-20230508162304-452481b63482/go.mod h1:GNcfpy5+SY6RVbNGQW264gC0r336Dm+0zgQ5vt6+M8Y= github.com/grafana/prometheus-alertmanager v0.25.1-0.20240208102907-e82436ce63e6 h1:CBm0rwLCPDyarg9/bHJ50rBLYmyMDoyCWpgRMITZhdA= @@ -2567,8 +2572,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFb github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 h1:6UKoz5ujsI55KNpsJH3UwCq3T8kKbZwNZBNPuTTje8U= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1/go.mod h1:YvJ2f6MplWDhfxiUC3KpyTy76kYUZA4W3pTv/wdKQ9Y= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hanwen/go-fuse v1.0.0/go.mod h1:unqXarDXqzAk0rt98O2tVndEPIpUgLD9+rwFisZH3Ok= github.com/hanwen/go-fuse/v2 v2.1.0/go.mod h1:oRyA5eK+pvJyv5otpO/DgccS8y/RvYMaO00GgRLGryc= @@ -3737,40 +3742,43 @@ go.opentelemetry.io/collector/pdata v1.0.1 h1:dGX2h7maA6zHbl5D3AsMnF1c3Nn+3EUftb go.opentelemetry.io/collector/pdata v1.0.1/go.mod h1:jutXeu0QOXYY8wcZ/hege+YAnSBP3+jpTqYU1+JTI5Y= go.opentelemetry.io/collector/semconv v0.90.1/go.mod h1:j/8THcqVxFna1FpvA2zYIsUperEtOaRaqoLYIN4doWw= go.opentelemetry.io/contrib v0.18.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 h1:UNQQKPfTDe1J81ViolILjTKPr9WetKW6uei2hFgJmFs= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0/go.mod h1:r9vWsPS/3AQItv3OSlEJ/E4mbrhUbbw18meOjArPtKQ= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.18.0/go.mod h1:iK1G0FgHurSJ/aYLg5LpnPI0pqdanM73S3dhyDp0Lk4= -go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.46.1 h1:gbhw/u49SS3gkPWiYweQNJGm/uJN5GkI/FrosxSHT7A= -go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.46.1/go.mod h1:GnOaBaFQ2we3b9AGWJpsBa7v1S5RlQzlC3O7dRMxZhM= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.49.0 h1:RtcvQ4iw3w9NBB5yRwgA4sSa82rfId7n4atVpvKx3bY= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.49.0/go.mod h1:f/PbKbRd4cdUICWell6DmzvVJ7QrmBgFrRHjXmAXbK4= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= go.opentelemetry.io/contrib/propagators/jaeger v1.22.0 h1:bAHX+zN/inu+Rbqk51REmC8oXLl+Dw6pp9ldQf/onaY= go.opentelemetry.io/contrib/propagators/jaeger v1.22.0/go.mod h1:bH9GkgkN21mscXcQP6lQJYI8XnEPDxlTN/ZOBuHDjqE= -go.opentelemetry.io/contrib/samplers/jaegerremote v0.16.0 h1:bBCrzJPJI3BsFjIYQEQ6J142Woqs/WHsImQfjV1XEnI= -go.opentelemetry.io/contrib/samplers/jaegerremote v0.16.0/go.mod h1:StxwPndBVNZD2sZez0RQ0SP/129XGCd4aEmVGaw1/QM= +go.opentelemetry.io/contrib/samplers/jaegerremote v0.18.0 h1:Q9PrD94WoMolBx44ef5UWWvufpVSME0MiSymXZfedso= +go.opentelemetry.io/contrib/samplers/jaegerremote v0.18.0/go.mod h1:tjp49JHNvreAAoWjdCHIVD7NXMjuJ3Dp/9iNOuPPlC8= go.opentelemetry.io/otel v1.22.0 h1:xS7Ku+7yTFvDfDraDIJVpw7XPyuHlB9MCiqqX5mcJ6Y= go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= go.opentelemetry.io/otel/exporters/jaeger v1.10.0 h1:7W3aVVjEYayu/GOqOVF4mbTvnCuxF1wWu3eRxFGQXvw= go.opentelemetry.io/otel/exporters/jaeger v1.10.0/go.mod h1:n9IGyx0fgyXXZ/i0foLHNxtET9CzXHzZeKCucvRBFgA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqheXEFWAZ7O8A7m+J0aPTmpJN3YQ7qetUAdkkkKpk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 h1:Mw5xcxMwlqoJd97vwPxA8isEaIoxsta9/Q51+TTJLGE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0/go.mod h1:CQNu9bj7o7mC6U7+CA/schKEYakYXWr79ucDHTMGhCM= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I= go.opentelemetry.io/otel/metric v1.22.0 h1:lypMQnGyJYeuYPhOM/bgjbFM6WE44W1/T45er4d8Hhg= go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= go.opentelemetry.io/otel/oteltest v0.18.0/go.mod h1:NyierCU3/G8DLTva7KRzGii2fdxdR89zXKH1bNWY7Bo= go.opentelemetry.io/otel/sdk v1.17.0/go.mod h1:U87sE0f5vQB7hwUoW98pW5Rz4ZDuCFBZFNUBlSgmDFQ= go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= -go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= -go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= +go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= +go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= go.opentelemetry.io/otel/trace v1.22.0 h1:Hg6pPujv0XG9QaVbGOBVHunyuLcCC3jN7WEhPx83XD0= go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI= +go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY= go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY= go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -3884,8 +3892,9 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -4070,8 +4079,9 @@ golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181003184128-c57b0facaced/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -4308,8 +4318,9 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -4329,8 +4340,9 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= -golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -4599,8 +4611,9 @@ google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvy google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750= google.golang.org/api v0.139.0/go.mod h1:CVagp6Eekz9CjGZ718Z+sloknzkDJE7Vc1Ckj9+viBk= google.golang.org/api v0.149.0/go.mod h1:Mwn1B7JTXrzXtnvmzQE2BD6bYZQ8DShKZDZbeN9I7qI= -google.golang.org/api v0.153.0 h1:N1AwGhielyKFaUqH07/ZSIQR3uNPcV7NVw0vj+j4iR4= google.golang.org/api v0.153.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY= +google.golang.org/api v0.155.0 h1:vBmGhCYs0djJttDNynWo44zosHlPvHmA0XiN2zP2DtA= +google.golang.org/api v0.155.0/go.mod h1:GI5qK5f40kCpHfPn6+YzGAByIKWv8ujFnmoWm7Igduk= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -4790,8 +4803,8 @@ google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+ google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405/go.mod h1:3WDQMjmJk36UQhjQ89emUzb1mdaHcPeeAh4SCBKznB4= google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= google.golang.org/genproto v0.0.0-20231120223509-83a465c0220f/go.mod h1:nWSwAFPb+qfNJXsoeO3Io7zf4tMSfN8EA8RlDA04GhY= -google.golang.org/genproto v0.0.0-20231212172506-995d672761c0 h1:YJ5pD9rF8o9Qtta0Cmy9rdBwkSjrTCT6XTiUQVOtIos= -google.golang.org/genproto v0.0.0-20231212172506-995d672761c0/go.mod h1:l/k7rMz0vFTBPy+tFSGvXEd3z+BcoG1k7EHbqm+YBsY= +google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ= +google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= @@ -4810,8 +4823,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go. google.golang.org/genproto/googleapis/api v0.0.0-20231030173426-d783a09b4405/go.mod h1:oT32Z4o8Zv2xPQTg0pbVaPr0MPOH6f14RgXt7zfIpwg= google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= google.golang.org/genproto/googleapis/api v0.0.0-20231127180814-3a041ad873d4/go.mod h1:k2dtGpRrbsSyKcNPKKI5sstZkrNCZwpU/ns96JoHbGg= -google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0 h1:s1w3X6gQxwrLEpxnLd/qXTVLgQE2yXwaOaoa6IlY/+o= -google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0/go.mod h1:CAny0tYF+0/9rmDB9fahA9YLzX3+AEVl1qXbv5hhj6c= +google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 h1:Lj5rbfG876hIAYFjqiJnPHfhXbv+nzTWfm04Fg/XSVU= +google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230807174057-1744710a1577/go.mod h1:NjCQG/D8JandXxM57PZbAJL1DCNL6EypA0vPPwfsc7c= google.golang.org/genproto/googleapis/bytestream v0.0.0-20231030173426-d783a09b4405/go.mod h1:GRUCuLdzVqZte8+Dl/D4N25yLzcGqqWaYkeVOwulFqw= @@ -4834,8 +4847,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go. google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405/go.mod h1:67X1fPuzjcrkymZzZV1vvkFeTn2Rvc6lYF9MYFGCcwE= google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA= google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 h1:/jFB8jK5R3Sq3i/lmeZO0cATSzFfZaJq1J2Euan3XKU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0/go.mod h1:FUoWkonphQm3RhTS+kOEhF8h0iDpm4tdXolVCeZ9KKA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 h1:AjyfHzEPEFp/NpvfN5g+KDla3EMojjhRVZc1i7cj+oM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -4894,8 +4907,8 @@ google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= -google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= -google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= +google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= +google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= google.golang.org/grpc/cmd/protoc-gen-go-grpc v0.0.0-20200910201057-6591123024b3/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/grpc/examples v0.0.0-20210304020650-930c79186c99/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= @@ -5030,8 +5043,8 @@ k8s.io/kms v0.29.0/go.mod h1:mB0f9HLxRXeXUfHfn1A7rpwOlzXI1gIWu86z6buNoYA= k8s.io/kube-aggregator v0.29.0 h1:N4fmtePxOZ+bwiK1RhVEztOU+gkoVkvterHgpwAuiTw= k8s.io/kube-aggregator v0.29.0/go.mod h1:bjatII63ORkFg5yUFP2qm2OC49R0wwxZhRVIyJ4Z4X0= k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= -k8s.io/kube-openapi v0.0.0-20231214164306-ab13479f8bf8 h1:yHNkNuLjht7iq95pO9QmbjOWCguvn8mDe3lT78nqPkw= -k8s.io/kube-openapi v0.0.0-20231214164306-ab13479f8bf8/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= +k8s.io/kube-openapi v0.0.0-20240220201932-37d671a357a5 h1:QSpdNrZ9uRlV0VkqLvVO0Rqg8ioKi3oSw7O5P7pJV8M= +k8s.io/kube-openapi v0.0.0-20240220201932-37d671a357a5/go.mod h1:Pa1PvrP7ACSkuX6I7KYomY6cmMA0Tx86waBhDUgoKPw= k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= k8s.io/utils v0.0.0-20230711102312-30195339c3c7/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= diff --git a/pkg/services/datasources/datasources.go b/pkg/services/datasources/datasources.go index accc20758873..cc4573fb21c4 100644 --- a/pkg/services/datasources/datasources.go +++ b/pkg/services/datasources/datasources.go @@ -58,7 +58,7 @@ type DataSourceService interface { // CustomHeaders returns a map of custom headers the user might have // configured for this Datasource. Not every datasource can has the option // to configure those. - CustomHeaders(ctx context.Context, ds *DataSource) (map[string]string, error) + CustomHeaders(ctx context.Context, ds *DataSource) (http.Header, error) } // CacheService interface for retrieving a cached datasource. diff --git a/pkg/services/datasources/fakes/fake_datasource_service.go b/pkg/services/datasources/fakes/fake_datasource_service.go index 69959cc6d573..3f9fcf4d5602 100644 --- a/pkg/services/datasources/fakes/fake_datasource_service.go +++ b/pkg/services/datasources/fakes/fake_datasource_service.go @@ -134,6 +134,6 @@ func (s *FakeDataSourceService) DecryptedPassword(ctx context.Context, ds *datas return "", nil } -func (s *FakeDataSourceService) CustomHeaders(ctx context.Context, ds *datasources.DataSource) (map[string]string, error) { +func (s *FakeDataSourceService) CustomHeaders(ctx context.Context, ds *datasources.DataSource) (http.Header, error) { return nil, nil } diff --git a/pkg/services/datasources/service/datasource.go b/pkg/services/datasources/service/datasource.go index a73e71b88700..593da43dedea 100644 --- a/pkg/services/datasources/service/datasource.go +++ b/pkg/services/datasources/service/datasource.go @@ -484,7 +484,7 @@ func (s *Service) httpClientOptions(ctx context.Context, ds *datasources.DataSou opts := &sdkhttpclient.Options{ Timeouts: timeouts, - Headers: s.getCustomHeaders(ds.JsonData, decryptedValues), + Header: s.getCustomHeaders(ds.JsonData, decryptedValues), Labels: map[string]string{ "datasource_type": ds.Type, "datasource_name": ds.Name, @@ -654,8 +654,8 @@ func (s *Service) getTimeout(ds *datasources.DataSource) time.Duration { // getCustomHeaders returns a map with all the to be set headers // The map key represents the HeaderName and the value represents this header's value -func (s *Service) getCustomHeaders(jsonData *simplejson.Json, decryptedValues map[string]string) map[string]string { - headers := make(map[string]string) +func (s *Service) getCustomHeaders(jsonData *simplejson.Json, decryptedValues map[string]string) http.Header { + headers := make(http.Header) if jsonData == nil { return headers } @@ -680,7 +680,7 @@ func (s *Service) getCustomHeaders(jsonData *simplejson.Json, decryptedValues ma } if val, ok := decryptedValues[headerValueSuffix]; ok { - headers[key] = val + headers.Add(key, val) } } @@ -769,7 +769,7 @@ func readQuotaConfig(cfg *setting.Cfg) (*quota.Map, error) { } // CustomerHeaders returns the custom headers specified in the datasource. The context is used for the decryption operation that might use the store, so consider setting an acceptable timeout for your use case. -func (s *Service) CustomHeaders(ctx context.Context, ds *datasources.DataSource) (map[string]string, error) { +func (s *Service) CustomHeaders(ctx context.Context, ds *datasources.DataSource) (http.Header, error) { values, err := s.SecretsService.DecryptJsonData(ctx, ds.SecureJsonData) if err != nil { return nil, fmt.Errorf("failed to get custom headers: %w", err) diff --git a/pkg/services/datasources/service/datasource_test.go b/pkg/services/datasources/service/datasource_test.go index c9818f4bcb46..fab5b2b47d77 100644 --- a/pkg/services/datasources/service/datasource_test.go +++ b/pkg/services/datasources/service/datasource_test.go @@ -833,7 +833,7 @@ func TestService_GetHttpTransport(t *testing.T) { require.NoError(t, err) headers := dsService.getCustomHeaders(sjson, map[string]string{"httpHeaderValue1": "Bearer xf5yhfkpsnmgo"}) - require.Equal(t, "Bearer xf5yhfkpsnmgo", headers["Authorization"]) + require.Equal(t, "Bearer xf5yhfkpsnmgo", headers.Get("Authorization")) // 1. Start HTTP test server which checks the request headers backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -902,7 +902,7 @@ func TestService_GetHttpTransport(t *testing.T) { require.NoError(t, err) headers := dsService.getCustomHeaders(sjson, map[string]string{"httpHeaderValue1": "example.com"}) - require.Equal(t, "example.com", headers["Host"]) + require.Equal(t, "example.com", headers.Get("Host")) // 1. Start HTTP test server which checks the request headers backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -1192,7 +1192,7 @@ func TestDataSource_CustomHeaders(t *testing.T) { name string jsonData *simplejson.Json secureJsonData map[string][]byte - expectedHeaders map[string]string + expectedHeaders http.Header expectedErrorMsg string }{ { @@ -1203,8 +1203,8 @@ func TestDataSource_CustomHeaders(t *testing.T) { secureJsonData: map[string][]byte{ "httpHeaderValue1": encryptedValue, }, - expectedHeaders: map[string]string{ - "X-Test-Header1": testValue, + expectedHeaders: http.Header{ + "X-Test-Header1": []string{testValue}, }, }, { @@ -1213,7 +1213,7 @@ func TestDataSource_CustomHeaders(t *testing.T) { "httpHeaderName1": "X-Test-Header1", }), secureJsonData: map[string][]byte{}, - expectedHeaders: map[string]string{}, + expectedHeaders: http.Header{}, }, { name: "non customer header value", @@ -1221,7 +1221,21 @@ func TestDataSource_CustomHeaders(t *testing.T) { "someotherheader": "X-Test-Header1", }), secureJsonData: map[string][]byte{}, - expectedHeaders: map[string]string{}, + expectedHeaders: http.Header{}, + }, + { + name: "add multiple header value", + jsonData: simplejson.NewFromAny(map[string]any{ + "httpHeaderName1": "X-Test-Header1", + "httpHeaderName2": "X-Test-Header1", + }), + secureJsonData: map[string][]byte{ + "httpHeaderValue1": encryptedValue, + "httpHeaderValue2": encryptedValue, + }, + expectedHeaders: http.Header{ + "X-Test-Header1": []string{testValue, testValue}, + }, }, } diff --git a/pkg/services/ngalert/sender/notifier_ext.go b/pkg/services/ngalert/sender/notifier_ext.go index 27effd18913d..544ed4ae0724 100644 --- a/pkg/services/ngalert/sender/notifier_ext.go +++ b/pkg/services/ngalert/sender/notifier_ext.go @@ -24,7 +24,7 @@ import ( // ApplyConfig updates the status state as the new config requires. // Extension: add new parameter headers. -func (n *Manager) ApplyConfig(conf *config.Config, headers map[string]map[string]string) error { +func (n *Manager) ApplyConfig(conf *config.Config, headers map[string]http.Header) error { n.mtx.Lock() defer n.mtx.Unlock() @@ -57,7 +57,7 @@ type alertmanagerSet struct { client *http.Client // Extension: headers that should be used for the http requests to the alertmanagers. - headers map[string]string + headers http.Header metrics *alertMetrics @@ -144,7 +144,7 @@ func (n *Manager) sendAll(alerts ...*Alert) bool { defer cancel() // Extension: added headers parameter. - go func(client *http.Client, url string, headers map[string]string) { + go func(client *http.Client, url string, headers http.Header) { if err := n.sendOne(ctx, client, url, payload, headers); err != nil { level.Error(n.logger).Log("alertmanager", url, "count", len(alerts), "msg", "Error sending alert", "err", err) n.metrics.errors.WithLabelValues(url).Inc() @@ -167,7 +167,7 @@ func (n *Manager) sendAll(alerts ...*Alert) bool { } // Extension: added headers parameter. -func (n *Manager) sendOne(ctx context.Context, c *http.Client, url string, b []byte, headers map[string]string) error { +func (n *Manager) sendOne(ctx context.Context, c *http.Client, url string, b []byte, headers http.Header) error { req, err := http.NewRequest("POST", url, bytes.NewReader(b)) if err != nil { return err @@ -176,7 +176,9 @@ func (n *Manager) sendOne(ctx context.Context, c *http.Client, url string, b []b req.Header.Set("Content-Type", contentTypeJSON) // Extension: set headers. for k, v := range headers { - req.Header.Set(k, v) + for _, vv := range v { + req.Header.Set(k, vv) + } } resp, err := n.opts.Do(ctx, c, req) if err != nil { diff --git a/pkg/services/ngalert/sender/sender.go b/pkg/services/ngalert/sender/sender.go index 18f16d194c16..60d609243813 100644 --- a/pkg/services/ngalert/sender/sender.go +++ b/pkg/services/ngalert/sender/sender.go @@ -43,7 +43,7 @@ type ExternalAlertmanager struct { type ExternalAMcfg struct { URL string - Headers map[string]string + Headers http.Header } type Option func(*ExternalAlertmanager) @@ -177,9 +177,9 @@ func (s *ExternalAlertmanager) DroppedAlertmanagers() []*url.URL { return s.manager.DroppedAlertmanagers() } -func buildNotifierConfig(alertmanagers []ExternalAMcfg) (*config.Config, map[string]map[string]string, error) { +func buildNotifierConfig(alertmanagers []ExternalAMcfg) (*config.Config, map[string]http.Header, error) { amConfigs := make([]*config.AlertmanagerConfig, 0, len(alertmanagers)) - headers := map[string]map[string]string{} + headers := map[string]http.Header{} for i, am := range alertmanagers { u, err := url.Parse(am.URL) if err != nil { diff --git a/pkg/tsdb/azuremonitor/httpclient.go b/pkg/tsdb/azuremonitor/httpclient.go index 77ae5779579b..74cb28269812 100644 --- a/pkg/tsdb/azuremonitor/httpclient.go +++ b/pkg/tsdb/azuremonitor/httpclient.go @@ -28,7 +28,7 @@ func newHTTPClient(ctx context.Context, route types.AzRoute, model types.Datasou } for header, value := range route.Headers { - clientOpts.Headers[header] = value + clientOpts.Header.Add(header, value) } // Use Azure credentials if the route has OAuth scopes configured diff --git a/pkg/tsdb/azuremonitor/httpclient_test.go b/pkg/tsdb/azuremonitor/httpclient_test.go index d6fe1d4840cf..4bd221144885 100644 --- a/pkg/tsdb/azuremonitor/httpclient_test.go +++ b/pkg/tsdb/azuremonitor/httpclient_test.go @@ -72,18 +72,18 @@ func TestHttpClient_AzureCredentials(t *testing.T) { }, } - res := map[string]string{ - "GrafanaHeader": "GrafanaValue", - "AzureHeader": "AzureValue", + res := http.Header{ + "Grafanaheader": {"GrafanaValue"}, + "Azureheader": {"AzureValue"}, } _, err := newHTTPClient(context.Background(), route, model, settings, azureSettings, provider) require.NoError(t, err) assert.NotNil(t, provider.opts) - if provider.opts.Headers != nil { - assert.Len(t, provider.opts.Headers, 2) - assert.Equal(t, res, provider.opts.Headers) + if provider.opts.Header != nil { + assert.Len(t, provider.opts.Header, 2) + assert.Equal(t, res, provider.opts.Header) } }) } diff --git a/pkg/tsdb/prometheus/client/transport_test.go b/pkg/tsdb/prometheus/client/transport_test.go index de7b165c6f64..b8f025f8a98f 100644 --- a/pkg/tsdb/prometheus/client/transport_test.go +++ b/pkg/tsdb/prometheus/client/transport_test.go @@ -2,6 +2,7 @@ package client import ( "context" + "net/http" "testing" "github.com/grafana/grafana-azure-sdk-go/azsettings" @@ -21,7 +22,7 @@ func TestCreateTransportOptions(t *testing.T) { } opts, err := CreateTransportOptions(context.Background(), settings, backend.NewLoggerWith("logger", "test")) require.NoError(t, err) - require.Equal(t, map[string]string{"foo": "bar"}, opts.Headers) + require.Equal(t, http.Header{"Foo": []string{"bar"}}, opts.Header) require.Equal(t, 2, len(opts.Middlewares)) }) diff --git a/pkg/tsdb/tempo/grpc.go b/pkg/tsdb/tempo/grpc.go index 061713f989e1..12ff01554711 100644 --- a/pkg/tsdb/tempo/grpc.go +++ b/pkg/tsdb/tempo/grpc.go @@ -81,9 +81,11 @@ func getDialOpts(settings backend.DataSourceInstanceSettings, opts httpclient.Op // to the CustomHeadersMiddleware in the HTTP client provider. func CustomHeadersStreamInterceptor(httpOpts httpclient.Options) grpc.StreamClientInterceptor { return func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) { - if len(httpOpts.Headers) != 0 { - for key, value := range httpOpts.Headers { - ctx = metadata.AppendToOutgoingContext(ctx, key, value) + if len(httpOpts.Header) != 0 { + for key, value := range httpOpts.Header { + for _, v := range value { + ctx = metadata.AppendToOutgoingContext(ctx, key, v) + } } } diff --git a/public/api-merged.json b/public/api-merged.json index 725bd8a0d9a8..6126a8e3b3f0 100644 --- a/public/api-merged.json +++ b/public/api-merged.json @@ -15152,7 +15152,7 @@ } }, "FrameType": { - "description": "A FrameType string, when present in a frame's metadata, asserts that the\nframe's structure conforms to the FrameType's specification.\nThis property is currently optional, so FrameType may be FrameTypeUnknown even if the properties of\nthe Frame correspond to a defined FrameType.", + "description": "A FrameType string, when present in a frame's metadata, asserts that the\nframe's structure conforms to the FrameType's specification.\nThis property is currently optional, so FrameType may be FrameTypeUnknown even if the properties of\nthe Frame correspond to a defined FrameType.\n+enum", "type": "string" }, "FrameTypeVersion": { @@ -16035,8 +16035,8 @@ } }, "JSONWebKey": { + "description": "JSONWebKey represents a public or private key in JWK format. It can be\nmarshaled into JSON and unmarshaled from JSON.", "type": "object", - "title": "JSONWebKey represents a public or private key in JWK format.", "properties": { "Algorithm": { "description": "Key algorithm, parsed from `alg` header.", @@ -16069,7 +16069,7 @@ "$ref": "#/definitions/URL" }, "Key": { - "description": "Cryptographic key, can be a symmetric or asymmetric key." + "description": "Key is the Go in-memory representation of this key. It must have one\nof these types:\ned25519.PublicKey\ned25519.PrivateKey\necdsa.PublicKey\necdsa.PrivateKey\nrsa.PublicKey\nrsa.PrivateKey\n[]byte (a symmetric key)\n\nWhen marshaling this JSONWebKey into JSON, the \"kty\" header parameter\nwill be automatically set based on the type of this field." }, "KeyID": { "description": "Key identifier, parsed from `kid` header.", @@ -18312,7 +18312,7 @@ "type": "object", "title": "QueryDataResponse contains the results from a QueryDataRequest.", "properties": { - "Responses": { + "results": { "$ref": "#/definitions/Responses" } } diff --git a/public/openapi3.json b/public/openapi3.json index bfa8084a60b3..7a161c02406b 100644 --- a/public/openapi3.json +++ b/public/openapi3.json @@ -5700,7 +5700,7 @@ "type": "object" }, "FrameType": { - "description": "A FrameType string, when present in a frame's metadata, asserts that the\nframe's structure conforms to the FrameType's specification.\nThis property is currently optional, so FrameType may be FrameTypeUnknown even if the properties of\nthe Frame correspond to a defined FrameType.", + "description": "A FrameType string, when present in a frame's metadata, asserts that the\nframe's structure conforms to the FrameType's specification.\nThis property is currently optional, so FrameType may be FrameTypeUnknown even if the properties of\nthe Frame correspond to a defined FrameType.\n+enum", "type": "string" }, "FrameTypeVersion": { @@ -6583,6 +6583,7 @@ "type": "object" }, "JSONWebKey": { + "description": "JSONWebKey represents a public or private key in JWK format. It can be\nmarshaled into JSON and unmarshaled from JSON.", "properties": { "Algorithm": { "description": "Key algorithm, parsed from `alg` header.", @@ -6615,7 +6616,7 @@ "$ref": "#/components/schemas/URL" }, "Key": { - "description": "Cryptographic key, can be a symmetric or asymmetric key." + "description": "Key is the Go in-memory representation of this key. It must have one\nof these types:\ned25519.PublicKey\ned25519.PrivateKey\necdsa.PublicKey\necdsa.PrivateKey\nrsa.PublicKey\nrsa.PrivateKey\n[]byte (a symmetric key)\n\nWhen marshaling this JSONWebKey into JSON, the \"kty\" header parameter\nwill be automatically set based on the type of this field." }, "KeyID": { "description": "Key identifier, parsed from `kid` header.", @@ -6626,7 +6627,6 @@ "type": "string" } }, - "title": "JSONWebKey represents a public or private key in JWK format.", "type": "object" }, "Json": { @@ -8858,7 +8858,7 @@ "QueryDataResponse": { "description": "It is the return type of a QueryData call.", "properties": { - "Responses": { + "results": { "$ref": "#/components/schemas/Responses" } }, From 3328ac82064b683052460fec14b244392bd3b08c Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Mon, 25 Mar 2024 22:39:30 +0200 Subject: [PATCH 105/138] [v10.4.x] Prometheus: Prevent duplicate registration of custom header middleware (#85120) Prometheus: Prevent duplicate registration of custom header middleware (#84860) * remove dupe middleware * fix test (cherry picked from commit c8c372c3279fa10a89e9270a8d26602d33aa1fea) Co-authored-by: Will Browne --- pkg/tsdb/prometheus/client/transport.go | 1 - pkg/tsdb/prometheus/client/transport_test.go | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/pkg/tsdb/prometheus/client/transport.go b/pkg/tsdb/prometheus/client/transport.go index a333e04fafbc..8998b49bd7ae 100644 --- a/pkg/tsdb/prometheus/client/transport.go +++ b/pkg/tsdb/prometheus/client/transport.go @@ -59,7 +59,6 @@ func middlewares(logger log.Logger, httpMethod string) []sdkhttpclient.Middlewar middlewares := []sdkhttpclient.Middleware{ // TODO: probably isn't needed anymore and should by done by http infra code middleware.CustomQueryParameters(logger), - sdkhttpclient.CustomHeadersMiddleware(), } // Needed to control GET vs POST method of the requests diff --git a/pkg/tsdb/prometheus/client/transport_test.go b/pkg/tsdb/prometheus/client/transport_test.go index b8f025f8a98f..56367435c9fa 100644 --- a/pkg/tsdb/prometheus/client/transport_test.go +++ b/pkg/tsdb/prometheus/client/transport_test.go @@ -23,7 +23,7 @@ func TestCreateTransportOptions(t *testing.T) { opts, err := CreateTransportOptions(context.Background(), settings, backend.NewLoggerWith("logger", "test")) require.NoError(t, err) require.Equal(t, http.Header{"Foo": []string{"bar"}}, opts.Header) - require.Equal(t, 2, len(opts.Middlewares)) + require.Equal(t, 1, len(opts.Middlewares)) }) t.Run("add azure credentials if configured", func(t *testing.T) { @@ -44,6 +44,6 @@ func TestCreateTransportOptions(t *testing.T) { ctx := backend.WithGrafanaConfig(context.Background(), cfg) opts, err := CreateTransportOptions(ctx, settings, backend.NewLoggerWith("logger", "test")) require.NoError(t, err) - require.Equal(t, 3, len(opts.Middlewares)) + require.Equal(t, 2, len(opts.Middlewares)) }) } From 41d516639d2257e6523f66d2f48ae7083e1567f6 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Tue, 26 Mar 2024 13:07:59 +0200 Subject: [PATCH 106/138] [v10.4.x] Access control: Improve annotation delete performance (#85150) Access control: Improve annotation delete performance (#85068) * Access control: Improve annotation delete performance * simplify query string * Refactor * remove unnecessary join (cherry picked from commit 02606be3ed165c0b007bf1ce66c4c7a7e01fde89) Co-authored-by: Alexander Zobnin --- .../accesscontrol/accesscontrol.go | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/pkg/services/annotations/accesscontrol/accesscontrol.go b/pkg/services/annotations/accesscontrol/accesscontrol.go index 9102e62b9fa4..d0d22703414c 100644 --- a/pkg/services/annotations/accesscontrol/accesscontrol.go +++ b/pkg/services/annotations/accesscontrol/accesscontrol.go @@ -59,6 +59,14 @@ func (authz *AuthService) Authorize(ctx context.Context, orgID int64, query *ann var visibleDashboards map[string]int64 var err error if canAccessDashAnnotations { + if query.AnnotationID != 0 { + annotationDashboardID, err := authz.getAnnotationDashboard(ctx, query, orgID) + if err != nil { + return nil, ErrAccessControlInternal.Errorf("failed to fetch annotations: %w", err) + } + query.DashboardID = annotationDashboardID + } + visibleDashboards, err = authz.dashboardsWithVisibleAnnotations(ctx, query, orgID) if err != nil { return nil, ErrAccessControlInternal.Errorf("failed to fetch dashboards: %w", err) @@ -72,6 +80,32 @@ func (authz *AuthService) Authorize(ctx context.Context, orgID int64, query *ann }, nil } +func (authz *AuthService) getAnnotationDashboard(ctx context.Context, query *annotations.ItemQuery, orgID int64) (int64, error) { + var items []annotations.Item + params := make([]any, 0) + err := authz.db.WithDbSession(ctx, func(sess *db.Session) error { + sql := ` + SELECT + a.id, + a.org_id, + a.dashboard_id + FROM annotation as a + WHERE a.org_id = ? AND a.id = ? + ` + params = append(params, orgID, query.AnnotationID) + + return sess.SQL(sql, params...).Find(&items) + }) + if err != nil { + return 0, err + } + if len(items) == 0 { + return 0, ErrAccessControlInternal.Errorf("annotation not found") + } + + return items[0].DashboardID, nil +} + func (authz *AuthService) dashboardsWithVisibleAnnotations(ctx context.Context, query *annotations.ItemQuery, orgID int64) (map[string]int64, error) { recursiveQueriesSupported, err := authz.db.RecursiveQueriesAreSupported() if err != nil { From b5607298737bb5b31ad2faf86cf922e4a989ced9 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Tue, 26 Mar 2024 13:45:20 +0200 Subject: [PATCH 107/138] [v10.4.x] SQLEngine: Use `debug` method instead of custom implementation (#85154) SQLEngine: Use `debug` method instead of custom implementation (#85118) Use debug method instead of custom implementation (cherry picked from commit 19159a89a24941073991898b3fcc516ee979d86b) Co-authored-by: Andreas Christou --- pkg/tsdb/sqleng/sql_engine.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/pkg/tsdb/sqleng/sql_engine.go b/pkg/tsdb/sqleng/sql_engine.go index 543ceec0375c..3dceed95cba0 100644 --- a/pkg/tsdb/sqleng/sql_engine.go +++ b/pkg/tsdb/sqleng/sql_engine.go @@ -8,12 +8,12 @@ import ( "fmt" "net" "regexp" + "runtime/debug" "strconv" "strings" "sync" "time" - "github.com/go-stack/stack" "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/data" "github.com/grafana/grafana-plugin-sdk-go/data/sqlutil" @@ -198,12 +198,6 @@ func (e *DataSourceHandler) QueryData(ctx context.Context, req *backend.QueryDat return result, nil } -func stackTrace(skip int) string { - call := stack.Caller(skip) - s := stack.Trace().TrimBelow(call).TrimRuntime() - return s.String() -} - func (e *DataSourceHandler) executeQuery(query backend.DataQuery, wg *sync.WaitGroup, queryContext context.Context, ch chan DBDataResponse, queryJson QueryJson) { defer wg.Done() @@ -216,7 +210,7 @@ func (e *DataSourceHandler) executeQuery(query backend.DataQuery, wg *sync.WaitG defer func() { if r := recover(); r != nil { - logger.Error("ExecuteQuery panic", "error", r, "stack", stackTrace(1)) + logger.Error("ExecuteQuery panic", "error", r, "stack", string(debug.Stack())) if theErr, ok := r.(error); ok { queryResult.dataResponse.Error = theErr } else if theErrString, ok := r.(string); ok { From d26a1454c8f4af2f4f8bed9939d54f6986751e9c Mon Sep 17 00:00:00 2001 From: Will Browne Date: Tue, 26 Mar 2024 12:52:13 +0100 Subject: [PATCH 108/138] [v10.4.x] Plugins: Pass PDC file contents in requests (#85144) * Plugins: Pass PDC file contents in requests (#84783) * Plugins: Pass PDC file contents in requests * go mod tidy * undo go.mod changes * fix linter * fix tests * undo unnecessary changes * update dep * join with comma * update naming * bump SDK (cherry picked from commit b765c21d4c88c96d8a68d55d03fbbd33307bd4cf) * set env + req config * fix linter --- go.mod | 12 +- go.sum | 20 ++- pkg/plugins/envvars/envvars.go | 23 ++- pkg/plugins/envvars/envvars_test.go | 6 +- .../datasources/service/datasource.go | 2 +- pkg/setting/setting_secure_socks_proxy.go | 74 +++++++-- .../setting_secure_socks_proxy_test.go | 152 +++++++++++++----- 7 files changed, 210 insertions(+), 79 deletions(-) diff --git a/go.mod b/go.mod index f6da3e46fcf1..932950ff0264 100644 --- a/go.mod +++ b/go.mod @@ -63,7 +63,7 @@ require ( github.com/grafana/cuetsy v0.1.11 // @grafana/grafana-as-code github.com/grafana/grafana-aws-sdk v0.23.1 // @grafana/aws-datasources github.com/grafana/grafana-azure-sdk-go v1.12.0 // @grafana/partner-datasources - github.com/grafana/grafana-plugin-sdk-go v0.215.0 // @grafana/plugins-platform-backend + github.com/grafana/grafana-plugin-sdk-go v0.217.0 // @grafana/plugins-platform-backend github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // @grafana/backend-platform github.com/hashicorp/go-hclog v1.6.2 // @grafana/plugins-platform-backend github.com/hashicorp/go-plugin v1.6.0 // @grafana/plugins-platform-backend @@ -105,9 +105,9 @@ require ( go.opentelemetry.io/otel/exporters/jaeger v1.10.0 // @grafana/backend-platform go.opentelemetry.io/otel/sdk v1.24.0 // @grafana/backend-platform go.opentelemetry.io/otel/trace v1.24.0 // @grafana/backend-platform - golang.org/x/crypto v0.19.0 // @grafana/backend-platform + golang.org/x/crypto v0.21.0 // @grafana/backend-platform golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb // @grafana/alerting-squad-backend - golang.org/x/net v0.21.0 // @grafana/oss-big-tent @grafana/partner-datasources + golang.org/x/net v0.22.0 // @grafana/oss-big-tent @grafana/partner-datasources golang.org/x/oauth2 v0.16.0 // @grafana/grafana-authnz-team golang.org/x/sync v0.6.0 // @grafana/alerting-squad-backend golang.org/x/time v0.5.0 // @grafana/backend-platform @@ -115,7 +115,7 @@ require ( gonum.org/v1/gonum v0.12.0 // @grafana/observability-metrics google.golang.org/api v0.155.0 // @grafana/backend-platform google.golang.org/grpc v1.62.1 // @grafana/plugins-platform-backend - google.golang.org/protobuf v1.32.0 // @grafana/plugins-platform-backend + google.golang.org/protobuf v1.33.0 // @grafana/plugins-platform-backend gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/ini.v1 v1.67.0 // @grafana/alerting-squad-backend gopkg.in/mail.v2 v2.3.1 // @grafana/backend-platform @@ -214,7 +214,7 @@ require ( go.opencensus.io v0.24.0 // indirect go.uber.org/atomic v1.11.0 // @grafana/alerting-squad-backend go.uber.org/goleak v1.3.0 // indirect - golang.org/x/sys v0.17.0 // indirect + golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // @grafana/backend-platform golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/appengine v1.6.8 // indirect @@ -403,7 +403,7 @@ require ( go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect - golang.org/x/term v0.17.0 // indirect + golang.org/x/term v0.18.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect diff --git a/go.sum b/go.sum index 81c8d674e237..99600516ac9c 100644 --- a/go.sum +++ b/go.sum @@ -2535,8 +2535,8 @@ github.com/grafana/grafana-google-sdk-go v0.1.0/go.mod h1:Vo2TKWfDVmNTELBUM+3lkr github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79 h1:r+mU5bGMzcXCRVAuOrTn54S80qbfVkvTdUJZfSfTNbs= github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79/go.mod h1:wc6Hbh3K2TgCUSfBC/BOzabItujtHMESZeFk5ZhdxhQ= github.com/grafana/grafana-plugin-sdk-go v0.114.0/go.mod h1:D7x3ah+1d4phNXpbnOaxa/osSaZlwh9/ZUnGGzegRbk= -github.com/grafana/grafana-plugin-sdk-go v0.215.0 h1:02gwVsqYi1I+U48/MQR61eOMxiXE7KNKC8QsiMJ//qA= -github.com/grafana/grafana-plugin-sdk-go v0.215.0/go.mod h1:nBsh3jRItKQUXDF2BQkiQCPxqrsSQeb+7hiFyJTO1RE= +github.com/grafana/grafana-plugin-sdk-go v0.217.0 h1:oQjq5KRrVrhweXHxFtEMgjv1KW7hujGiRPIYrsPZ9PE= +github.com/grafana/grafana-plugin-sdk-go v0.217.0/go.mod h1:FdvSvOliqpVLnytM7e89zCFyYPDE6VOn9SIjVQRvVxM= github.com/grafana/kindsys v0.0.0-20230508162304-452481b63482 h1:1YNoeIhii4UIIQpCPU+EXidnqf449d0C3ZntAEt4KSo= github.com/grafana/kindsys v0.0.0-20230508162304-452481b63482/go.mod h1:GNcfpy5+SY6RVbNGQW264gC0r336Dm+0zgQ5vt6+M8Y= github.com/grafana/prometheus-alertmanager v0.25.1-0.20240208102907-e82436ce63e6 h1:CBm0rwLCPDyarg9/bHJ50rBLYmyMDoyCWpgRMITZhdA= @@ -3893,8 +3893,9 @@ golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -4080,8 +4081,8 @@ golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181003184128-c57b0facaced/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -4319,8 +4320,9 @@ golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -4341,8 +4343,9 @@ golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -4930,8 +4933,9 @@ google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/DataDog/dd-trace-go.v1 v1.27.0/go.mod h1:Sp1lku8WJMvNV0kjDI4Ni/T7J/U3BO5ct5kEaoVU8+I= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= diff --git a/pkg/plugins/envvars/envvars.go b/pkg/plugins/envvars/envvars.go index 62c769290f8a..9b343281b471 100644 --- a/pkg/plugins/envvars/envvars.go +++ b/pkg/plugins/envvars/envvars.go @@ -152,7 +152,7 @@ func (s *Service) GetConfigMap(ctx context.Context, pluginID string, _ *auth.Ext m[proxy.PluginSecureSocksProxyEnabled] = "true" m[proxy.PluginSecureSocksProxyClientCert] = s.cfg.ProxySettings.ClientCert m[proxy.PluginSecureSocksProxyClientKey] = s.cfg.ProxySettings.ClientKey - m[proxy.PluginSecureSocksProxyRootCACert] = s.cfg.ProxySettings.RootCA + m[proxy.PluginSecureSocksProxyRootCAs] = strings.Join(s.cfg.ProxySettings.RootCAs, " ") m[proxy.PluginSecureSocksProxyProxyAddress] = s.cfg.ProxySettings.ProxyAddress m[proxy.PluginSecureSocksProxyServerName] = s.cfg.ProxySettings.ServerName m[proxy.PluginSecureSocksProxyAllowInsecure] = strconv.FormatBool(s.cfg.ProxySettings.AllowInsecure) @@ -287,13 +287,20 @@ func (s *Service) awsEnvVars() []string { func (s *Service) secureSocksProxyEnvVars() []string { if s.cfg.ProxySettings.Enabled { return []string{ - proxy.PluginSecureSocksProxyClientCert + "=" + s.cfg.ProxySettings.ClientCert, - proxy.PluginSecureSocksProxyClientKey + "=" + s.cfg.ProxySettings.ClientKey, - proxy.PluginSecureSocksProxyRootCACert + "=" + s.cfg.ProxySettings.RootCA, - proxy.PluginSecureSocksProxyProxyAddress + "=" + s.cfg.ProxySettings.ProxyAddress, - proxy.PluginSecureSocksProxyServerName + "=" + s.cfg.ProxySettings.ServerName, - proxy.PluginSecureSocksProxyEnabled + "=" + strconv.FormatBool(s.cfg.ProxySettings.Enabled), - proxy.PluginSecureSocksProxyAllowInsecure + "=" + strconv.FormatBool(s.cfg.ProxySettings.AllowInsecure), + // nolint:staticcheck + proxy.PluginSecureSocksProxyClientCertFilePathEnvVarName + "=" + s.cfg.ProxySettings.ClientCertFilePath, + // nolint:staticcheck + proxy.PluginSecureSocksProxyClientKeyFilePathEnvVarName + "=" + s.cfg.ProxySettings.ClientKeyFilePath, + // nolint:staticcheck + proxy.PluginSecureSocksProxyRootCACertFilePathsEnvVarName + "=" + strings.Join(s.cfg.ProxySettings.RootCAFilePaths, " "), + // nolint:staticcheck + proxy.PluginSecureSocksProxyAddressEnvVarName + "=" + s.cfg.ProxySettings.ProxyAddress, + // nolint:staticcheck + proxy.PluginSecureSocksProxyServerNameEnvVarName + "=" + s.cfg.ProxySettings.ServerName, + // nolint:staticcheck + proxy.PluginSecureSocksProxyEnabledEnvVarName + "=" + strconv.FormatBool(s.cfg.ProxySettings.Enabled), + // nolint:staticcheck + proxy.PluginSecureSocksProxyAllowInsecureEnvVarName + "=" + strconv.FormatBool(s.cfg.ProxySettings.AllowInsecure), } } return nil diff --git a/pkg/plugins/envvars/envvars_test.go b/pkg/plugins/envvars/envvars_test.go index f782ddefba89..9e626fe532ff 100644 --- a/pkg/plugins/envvars/envvars_test.go +++ b/pkg/plugins/envvars/envvars_test.go @@ -686,7 +686,7 @@ func TestService_GetConfigMap(t *testing.T) { ShowUI: true, ClientCert: "c3rt", ClientKey: "k3y", - RootCA: "ca", + RootCAs: []string{"ca"}, ProxyAddress: "https://proxy.grafana.com", ServerName: "secureProxy", AllowInsecure: true, @@ -712,7 +712,7 @@ func TestService_GetConfigMap(t *testing.T) { ShowUI: true, ClientCert: "c3rt", ClientKey: "k3y", - RootCA: "ca", + RootCAs: []string{"ca"}, ProxyAddress: "https://proxy.grafana.com", ServerName: "secureProxy", }, @@ -730,7 +730,7 @@ func TestService_GetConfigMap(t *testing.T) { ShowUI: true, ClientCert: "c3rt", ClientKey: "k3y", - RootCA: "ca", + RootCAs: []string{"ca"}, ProxyAddress: "https://proxy.grafana.com", ServerName: "secureProxy", }, diff --git a/pkg/services/datasources/service/datasource.go b/pkg/services/datasources/service/datasource.go index 593da43dedea..43f2ccd79465 100644 --- a/pkg/services/datasources/service/datasource.go +++ b/pkg/services/datasources/service/datasource.go @@ -534,7 +534,7 @@ func (s *Service) httpClientOptions(ctx context.Context, ds *datasources.DataSou ClientCfg: &sdkproxy.ClientCfg{ ClientCert: s.cfg.SecureSocksDSProxy.ClientCert, ClientKey: s.cfg.SecureSocksDSProxy.ClientKey, - RootCA: s.cfg.SecureSocksDSProxy.RootCA, + RootCAs: s.cfg.SecureSocksDSProxy.RootCAs, ProxyAddress: s.cfg.SecureSocksDSProxy.ProxyAddress, ServerName: s.cfg.SecureSocksDSProxy.ServerName, AllowInsecure: s.cfg.SecureSocksDSProxy.AllowInsecure, diff --git a/pkg/setting/setting_secure_socks_proxy.go b/pkg/setting/setting_secure_socks_proxy.go index 815d7f600063..6e034cfa313b 100644 --- a/pkg/setting/setting_secure_socks_proxy.go +++ b/pkg/setting/setting_secure_socks_proxy.go @@ -1,33 +1,41 @@ package setting import ( + "encoding/pem" "errors" + "os" "gopkg.in/ini.v1" ) type SecureSocksDSProxySettings struct { - Enabled bool - ShowUI bool - AllowInsecure bool - ClientCert string - ClientKey string - RootCA string - ProxyAddress string - ServerName string + Enabled bool + ShowUI bool + AllowInsecure bool + ClientCert string + ClientCertFilePath string + ClientKey string + ClientKeyFilePath string + RootCAs []string + RootCAFilePaths []string + ProxyAddress string + ServerName string } func readSecureSocksDSProxySettings(iniFile *ini.File) (SecureSocksDSProxySettings, error) { - s := SecureSocksDSProxySettings{} + s := SecureSocksDSProxySettings{ + RootCAs: []string{}, + RootCAFilePaths: []string{}, + } secureSocksProxySection := iniFile.Section("secure_socks_datasource_proxy") s.Enabled = secureSocksProxySection.Key("enabled").MustBool(false) - s.ClientCert = secureSocksProxySection.Key("client_cert").MustString("") - s.ClientKey = secureSocksProxySection.Key("client_key").MustString("") - s.RootCA = secureSocksProxySection.Key("root_ca_cert").MustString("") s.ProxyAddress = secureSocksProxySection.Key("proxy_address").MustString("") s.ServerName = secureSocksProxySection.Key("server_name").MustString("") s.ShowUI = secureSocksProxySection.Key("show_ui").MustBool(true) s.AllowInsecure = secureSocksProxySection.Key("allow_insecure").MustBool(false) + s.ClientCertFilePath = secureSocksProxySection.Key("client_cert").MustString("") + s.ClientKeyFilePath = secureSocksProxySection.Key("client_key").MustString("") + s.RootCAFilePaths = secureSocksProxySection.Key("root_ca_cert").Strings(" ") if !s.Enabled { return s, nil @@ -40,14 +48,50 @@ func readSecureSocksDSProxySettings(iniFile *ini.File) (SecureSocksDSProxySettin // If the proxy is going to use TLS. if !s.AllowInsecure { // all fields must be specified to use the proxy - if s.RootCA == "" { - return s, errors.New("rootCA required") - } else if s.ClientCert == "" || s.ClientKey == "" { + if len(s.RootCAFilePaths) == 0 { + return s, errors.New("one or more rootCA required") + } else if s.ClientCertFilePath == "" || s.ClientKeyFilePath == "" { return s, errors.New("client key pair required") } else if s.ServerName == "" { return s, errors.New("server name required") } + } else { + return s, nil + } + + if s.ClientCertFilePath != "" { + certPEMBlock, err := os.ReadFile(s.ClientCertFilePath) + if err != nil { + return s, err + } + s.ClientCert = string(certPEMBlock) + } + + if s.ClientKeyFilePath != "" { + keyPEMBlock, err := os.ReadFile(s.ClientKeyFilePath) + if err != nil { + return s, err + } + s.ClientKey = string(keyPEMBlock) + } + + var rootCAs []string + for _, rootCAFile := range s.RootCAFilePaths { + // nolint:gosec + // The gosec G304 warning can be ignored because `rootCAFile` comes from config ini, and we check below if + // it's the right file type. + pemBytes, err := os.ReadFile(rootCAFile) + if err != nil { + return s, err + } + + pemDecoded, _ := pem.Decode(pemBytes) + if pemDecoded == nil || pemDecoded.Type != "CERTIFICATE" { + return s, errors.New("root ca is invalid") + } + rootCAs = append(rootCAs, string(pemBytes)) } + s.RootCAs = rootCAs return s, nil } diff --git a/pkg/setting/setting_secure_socks_proxy_test.go b/pkg/setting/setting_secure_socks_proxy_test.go index 3d8ac9f301c8..c198f70a556f 100644 --- a/pkg/setting/setting_secure_socks_proxy_test.go +++ b/pkg/setting/setting_secure_socks_proxy_test.go @@ -1,25 +1,46 @@ package setting import ( + "bytes" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" "errors" "fmt" + "math/big" + "os" + "path/filepath" "testing" + "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "gopkg.in/ini.v1" ) -func mustNewIniFile(fileContents string) *ini.File { - file, err := ini.Load([]byte(fileContents)) - if err != nil { - panic(fmt.Sprintf("creating ini file for test: %s", err)) - } - return file -} - func TestReadSecureSocksDSProxySettings(t *testing.T) { t.Parallel() + tempDir := t.TempDir() + testFilePath := filepath.Join(tempDir, "test") + testFileData := "foobar" + err := os.WriteFile(testFilePath, []byte(testFileData), 0600) + require.NoError(t, err) + + rootCACertFilePath := filepath.Join(tempDir, "ca.cert") + // nolint:gosec + caCertFile, err := os.Create(rootCACertFilePath) + require.NoError(t, err) + defer func() { + err = caCertFile.Close() + require.NoError(t, err) + }() + + rootCaFileData := createTestRootCAFile(t, rootCACertFilePath) + require.NoError(t, err) + cases := []struct { description string iniFile *ini.File @@ -32,24 +53,27 @@ func TestReadSecureSocksDSProxySettings(t *testing.T) { [secure_socks_datasource_proxy] `), expectedSettings: SecureSocksDSProxySettings{ - Enabled: false, - ClientCert: "", - ClientKey: "", - RootCA: "", - ProxyAddress: "", - ServerName: "", - ShowUI: true, - AllowInsecure: false, + Enabled: false, + ShowUI: true, + AllowInsecure: false, + ClientCertFilePath: "", + ClientCert: "", + ClientKey: "", + ClientKeyFilePath: "", + RootCAs: []string{}, + RootCAFilePaths: []string{}, + ProxyAddress: "", + ServerName: "", }, }, { - description: "root ca is required", + description: "one or more root ca is required", iniFile: mustNewIniFile(` [secure_socks_datasource_proxy] enabled = true proxy_address = address `), - expectedErr: errors.New("rootCA required"), + expectedErr: errors.New("one or more rootCA required"), }, { description: "client cert is required", @@ -106,35 +130,40 @@ server_name = name allow_insecure = true `), expectedSettings: SecureSocksDSProxySettings{ - Enabled: true, - ProxyAddress: "address", - ServerName: "name", - ShowUI: true, - AllowInsecure: true, + Enabled: true, + ProxyAddress: "address", + ServerName: "name", + ShowUI: true, + AllowInsecure: true, + RootCAFilePaths: []string{}, + RootCAs: []string{}, }, }, { description: "custom values", - iniFile: mustNewIniFile(` + iniFile: mustNewIniFile(fmt.Sprintf(` [secure_socks_datasource_proxy] enabled = true - client_cert = cert - client_key = key - root_ca_cert = root_ca + client_cert = %s + client_key = %s + root_ca_cert = %s proxy_address = proxy_address server_name = server_name show_ui = false - allow_insecure = true - `), + allow_insecure = false + `, testFilePath, testFilePath, rootCACertFilePath)), expectedSettings: SecureSocksDSProxySettings{ - Enabled: true, - ClientCert: "cert", - ClientKey: "key", - RootCA: "root_ca", - ProxyAddress: "proxy_address", - ServerName: "server_name", - ShowUI: false, - AllowInsecure: true, + Enabled: true, + ShowUI: false, + AllowInsecure: false, + ClientCert: testFileData, + ClientCertFilePath: testFilePath, + ClientKey: testFileData, + ClientKeyFilePath: testFilePath, + RootCAs: []string{rootCaFileData}, + RootCAFilePaths: []string{rootCACertFilePath}, + ProxyAddress: "proxy_address", + ServerName: "server_name", }, }, } @@ -146,9 +175,56 @@ allow_insecure = true if tt.expectedErr != nil { assert.Equal(t, tt.expectedErr, err) } else { - assert.Equal(t, tt.expectedSettings, settings) assert.NoError(t, err) + assert.Equal(t, tt.expectedSettings, settings) } }) } } + +func createTestRootCAFile(t *testing.T, path string) string { + t.Helper() + + ca := &x509.Certificate{ + SerialNumber: big.NewInt(2019), + Subject: pkix.Name{ + Organization: []string{"Grafana Labs"}, + CommonName: "Grafana", + }, + NotBefore: time.Now(), + NotAfter: time.Now().AddDate(10, 0, 0), + IsCA: true, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, + BasicConstraintsValid: true, + } + caPrivKey, err := rsa.GenerateKey(rand.Reader, 4096) + require.NoError(t, err) + caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &caPrivKey.PublicKey, caPrivKey) + require.NoError(t, err) + + // nolint:gosec + caCertFile, err := os.Create(path) + require.NoError(t, err) + + block := &pem.Block{ + Type: "CERTIFICATE", + Bytes: caBytes, + } + err = pem.Encode(caCertFile, block) + require.NoError(t, err) + + buf := new(bytes.Buffer) + err = pem.Encode(buf, block) + require.NoError(t, err) + + return buf.String() +} + +func mustNewIniFile(fileContents string) *ini.File { + file, err := ini.Load([]byte(fileContents)) + if err != nil { + panic(fmt.Sprintf("creating ini file for test: %s", err)) + } + return file +} From b1e4fc13aa0e3ed2377b94ee3216da376646f9b4 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Tue, 26 Mar 2024 07:03:25 -0700 Subject: [PATCH 109/138] [v10.4.x] Get started with alerting fixes for publish (#85174) Get started with alerting fixes for publish (#85158) * Rename alerting-get-started.md to index.md * edits * edits * prettier * Update docs/sources/tutorials/alerting-get-started/index.md Co-authored-by: tonypowa <45235678+tonypowa@users.noreply.github.com> --------- Co-authored-by: tonypowa Co-authored-by: tonypowa <45235678+tonypowa@users.noreply.github.com> (cherry picked from commit 54270dff36b7fbef61ba99191a646f18d5847509) Co-authored-by: Eve Meelan <81647476+Eve832@users.noreply.github.com> --- .../{alerting-get-started.md => index.md} | 86 +++++++++++-------- 1 file changed, 49 insertions(+), 37 deletions(-) rename docs/sources/tutorials/alerting-get-started/{alerting-get-started.md => index.md} (81%) diff --git a/docs/sources/tutorials/alerting-get-started/alerting-get-started.md b/docs/sources/tutorials/alerting-get-started/index.md similarity index 81% rename from docs/sources/tutorials/alerting-get-started/alerting-get-started.md rename to docs/sources/tutorials/alerting-get-started/index.md index 2b30932f90a6..941993bb1ecd 100644 --- a/docs/sources/tutorials/alerting-get-started/alerting-get-started.md +++ b/docs/sources/tutorials/alerting-get-started/index.md @@ -1,4 +1,23 @@ -# Introduction +--- +Feedback Link: https://github.com/grafana/tutorials/issues/new +authors: + - Antonio Calero +categories: + - alerting +description: Get started with Grafana Alerting by creating your first alert in just a few minutes. Learn how to set up an alert, send alert notifications to a public webhook, and generate sample data to observe your alert in action. +id: alerting-get-started +labels: + products: + - enterprise + - oss + - cloud +tags: + - beginner +title: Get started with Grafana Alerting +weight: 50 +--- + +# Get Started with Grafana Alerting In this guide, we'll walk you through the process of setting up your first alert in just a few minutes. You'll witness your alert in action with real-time data, as well as sending alert notifications. @@ -7,7 +26,7 @@ In this tutorial you will: - Set up an Alert - Send an alert notification to a public webhook. -# Before you begin +## Before you begin Ensure you have the following applications installed. @@ -22,19 +41,19 @@ Download the files to your local machine. 1. Clone the [tutorial environment repository](www.github.com/grafana/tutorial-environment). - ``` + ```promql git clone https://github.com/grafana/tutorial-environment.git ``` 1. Change to the directory where you cloned the repository: - ``` + ```promql cd tutorial-environment ``` 1. Make sure Docker is running: - ``` + ```promql docker --version ``` @@ -42,7 +61,7 @@ Download the files to your local machine. 1. Start the sample application: - ``` + ```promql docker compose up -d ``` @@ -54,7 +73,7 @@ Download the files to your local machine. 1. Ensure all services are up-and-running: - ``` + ```promql docker compose ps ``` @@ -62,7 +81,7 @@ Download the files to your local machine. The Grafana News app should be live on [localhost:8081](http://localhost:8081/). -## Generate data +### Generate data To enhance the hands-on aspect of this tutorial, you can actively participate in the Grafana News application to simulate web traffic and interactions. This enables you to observe data within Grafana and set up alerts accordingly. @@ -78,18 +97,15 @@ To add a link: The link will appear listed under the Grafana News heading. 1. To vote for a link, click the triangle icon next to the name of the link. -## Log in to Grafana +## Create a contact point for Grafana Managed Alerts Besides being an open-source observability tool, Grafana has its own built-in alerting service. This means that you can receive notifications whenever there is an event of interest in your data, and even see these events graphed in your visualizations. -In your browser, navigate to [localhost:3000](http://localhost:3000). -You should get logged in automatically - -## Create a contact point for Grafana Managed Alerts - In this step, we'll set up a new contact point. This contact point will use the _webhooks_ channel. In order to make this work, we also need an endpoint for our webhook channel to receive the alert. We will use [requestbin.com](https://requestbin.com) to quickly set up that test endpoint. This way we can make sure that our alert is actually sending a notification somewhere. -1. Browse to [requestbin.com](https://requestbin.com). +1. In your browser, navigate to [localhost:3000](http://localhost:3000), where Grafana is running. + You should get logged in automatically. +1. In another window, go to [requestbin.com](https://requestbin.com). 1. Under the **Create Request Bin** button, click the link to create a **public bin** instead. 1. From Request Bin, copy the endpoint URL. @@ -115,9 +131,8 @@ Next, we'll establish an alert within Grafana Alerting to notify us whenever our In Grafana, **navigate to Alerting** > **Alert rules**. Click on **New alert rule**. -## Enter alert rule name - -1. Make it short and descriptive as this will appear in your alert notification. For instance, **server-requests-duration** +1. Enter alert rule name + Make it short and descriptive as this will appear in your alert notification. For instance, **server-requests-duration** ## Define query and alert condition @@ -130,24 +145,25 @@ In this section, we define queries, expressions (used to manipulate the data), a {{< /admonition >}} 1. In the Query editor, switch to **Code** mode by clicking the button at the right. -1. Enter the query +1. Enter the following query: - ``` + ```promql sum(rate(tns_request_duration_seconds_count[1m])) by(method) ``` This [PromQL](https://prometheus.io/docs/prometheus/latest/querying/basics/) query calculates the sum of the per-second average rates of increase of the `tns_request_duration_seconds_count` metric over the last 1 minute, grouped by the HTTP method used in the requests. This can be useful for analyzing the request duration trends for different HTTP methods. 1. Keep expressions “B” and “C” as they are. These expressions (**Reduce** and **Threshold**, respectively) come by default when creating a new rule. + The Reduce expression “B”, selects the last value of our query “A”, while the Threshold expression “C” will check if the last value from expression “B” is above a specific value. In addition, the Threshold expression is the alert condition by default. Enter `0.2` as threshold value. You can read more about queries and conditions [here](https://grafana.com/docs/grafana/latest/alerting/fundamentals/alert-rules/queries-conditions/#expression-queries). 1. Click Preview to run the queries. -You should see the request duration for different HTTP methods. + You should see the request duration for different HTTP methods. -{{}} -If it returns “No data,” or an error, you are welcome to post questions in our [Grafana Community forum](https://community.grafana.com/). -{{}} + {{}} + If it returns “No data,” or an error, you are welcome to post questions in our [Grafana Community forum](https://community.grafana.com/). + {{}} ## Set evaluation behavior @@ -164,23 +180,19 @@ An evaluation group defines an evaluation interval - how often a rule is checked Add labels to ease searching or route notifications to a policy. -### Labels - -1. Add `app` as the label key, and `grafana-news` as the value - -### Notifications - -Select who should receive a notification when an alert rule fires. +1. Add a label. + Add `app` as the label key, and `grafana-news` as the value. -1. Under **Contact point**, select **RequestBin** from the drop-down menu. +1. Add a notification recipient. + Under **Contact point**, select **RequestBin** from the drop-down menu. -## Add Annotations +1. Add an annotation (optional). -To provide more context on the alert, you can link a dashboard and panel to our Alert. For that, click **Link Dashboard and panel** button. + To provide more context on the alert, you can link a dashboard and panel to our Alert. To do this, click **Link Dashboard and panel** button. -Linking an alert rule to a panel adds an annotation to the panel when the status of your alert rulechanges. If you don’t have a panel already, and since this is optional, you can skip this step for now and link it after you have finished configuring the alert rule. + Linking an alert rule to a panel adds an annotation to the panel when the status of your alert rulechanges. If you don’t have a panel already, and since this is optional, you can skip this step for now and link it after you have finished configuring the alert rule. -Click **Save rule and exit** at the top right corner. +1. Click **Save rule and exit** at the top right corner. ## Trigger an alert @@ -196,7 +208,7 @@ Once the query `sum(rate(tns_request_duration_seconds_count[1m])) by(method)` re In this tutorial, you have learned how to set up an alert, send alert notifications to a public webhook, and generate some sample data to observe your alert in action. By following these steps, you've gained a foundational understanding of how to leverage Grafana's alerting capabilities to monitor and respond to events of interest in your data. Happy monitoring! -# Learn more +## Learn more Check out the links below to continue your learning journey with Grafana's LGTM stack. From e743c4a88d3245e330bcf28dc131c213b97eae77 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Tue, 26 Mar 2024 17:43:49 +0000 Subject: [PATCH 110/138] [v10.4.x] Alerting: Fix receiver inheritance when provisioning a notification policy (#85192) Alerting: Fix receiver inheritance when provisioning a notification policy (#82007) Terraform Issue: grafana/terraform-provider-grafana#1007 Nested routes should be allowed to inherit the contact point from the root (or direct parent) route but this fails in the provisioning API (it works in the UI) (cherry picked from commit 2188516a21be660c4080884d2c937d9cbfcb8047) Co-authored-by: Julien Duchesne --- .../provisioning/notification_policies.go | 1 + .../notification_policies_test.go | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/pkg/services/ngalert/provisioning/notification_policies.go b/pkg/services/ngalert/provisioning/notification_policies.go index 629a5717b313..eeea63c4f295 100644 --- a/pkg/services/ngalert/provisioning/notification_policies.go +++ b/pkg/services/ngalert/provisioning/notification_policies.go @@ -70,6 +70,7 @@ func (nps *NotificationPolicyService) UpdatePolicyTree(ctx context.Context, orgI return err } + receivers[""] = struct{}{} // Allow empty receiver (inheriting from parent) err = tree.ValidateReceivers(receivers) if err != nil { return fmt.Errorf("%w: %s", ErrValidation, err.Error()) diff --git a/pkg/services/ngalert/provisioning/notification_policies_test.go b/pkg/services/ngalert/provisioning/notification_policies_test.go index 6202848606d1..95b319e5b2df 100644 --- a/pkg/services/ngalert/provisioning/notification_policies_test.go +++ b/pkg/services/ngalert/provisioning/notification_policies_test.go @@ -92,6 +92,31 @@ func TestNotificationPolicyService(t *testing.T) { require.Equal(t, "slack receiver", updated.Receiver) }) + t.Run("no root receiver will error", func(t *testing.T) { + sut := createNotificationPolicyServiceSut() + + newRoute := createTestRoutingTree() + newRoute.Receiver = "" + newRoute.Routes = append(newRoute.Routes, &definitions.Route{ + Receiver: "", + }) + + err := sut.UpdatePolicyTree(context.Background(), 1, newRoute, models.ProvenanceNone) + require.EqualError(t, err, "invalid object specification: root route must specify a default receiver") + }) + + t.Run("allow receiver inheritance", func(t *testing.T) { + sut := createNotificationPolicyServiceSut() + + newRoute := createTestRoutingTree() + newRoute.Routes = append(newRoute.Routes, &definitions.Route{ + Receiver: "", + }) + + err := sut.UpdatePolicyTree(context.Background(), 1, newRoute, models.ProvenanceNone) + require.NoError(t, err) + }) + t.Run("not existing receiver reference will error", func(t *testing.T) { sut := createNotificationPolicyServiceSut() From fef4ca3defd30e4e7d46a34c2c72f7a32e4cba1e Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Tue, 26 Mar 2024 18:59:54 +0000 Subject: [PATCH 111/138] [v10.4.x] Clarify AWS Auth instructions for Grafana Cloud users (#85208) Clarify AWS Auth instructions for Grafana Cloud users (#84312) * Clarify "Grafana Assume Role" feature instructions for Grafana Cloud users Following the recommendations provided in Support escalation https://github.com/grafana/support-escalations/issues/8277 * Update docs/sources/datasources/aws-cloudwatch/aws-authentication/index.md Co-authored-by: Jack Baldry * Update docs/sources/datasources/aws-cloudwatch/aws-authentication/index.md Co-authored-by: Jack Baldry --------- Co-authored-by: Eve Meelan <81647476+Eve832@users.noreply.github.com> Co-authored-by: Jack Baldry (cherry picked from commit ac9523bcad6075b6abac233e16ca04e9a0b8baf6) Co-authored-by: melGL <81323402+melgl@users.noreply.github.com> --- .../datasources/aws-cloudwatch/aws-authentication/index.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/sources/datasources/aws-cloudwatch/aws-authentication/index.md b/docs/sources/datasources/aws-cloudwatch/aws-authentication/index.md index 78d0021b2c67..97ca8723f7f2 100644 --- a/docs/sources/datasources/aws-cloudwatch/aws-authentication/index.md +++ b/docs/sources/datasources/aws-cloudwatch/aws-authentication/index.md @@ -72,7 +72,7 @@ The Grafana Assume Role also helps facilitate this. Using this role, Grafana's A If the **Assume Role ARN** field is left empty, Grafana uses the provided credentials from the selected authentication method directly, and permissions to AWS data must be attached directly to those credentials. The **Assume Role ARN** field is optional for all authentication methods except for Grafana Assume Role. -To disable this feature, refer to the [`assume_role_enabled` documentation][configure-grafana-assume-role-enabled]. +To disable this feature in open source Grafana or Grafana Enterprise, refer to the [`assume_role_enabled` documentation][configure-grafana-assume-role-enabled]. ### Use an external ID @@ -156,7 +156,8 @@ The Grafana Assume Role authentication provider lets you authenticate with AWS w To use the Grafana Assume Role: -1. Put in a request to Customer Support to enable`awsDatasourcesTempCredentials`. +1. Grafana Cloud customers need to open a support ticket to enable the feature `awsDatasourcesTempCredentials`. + This feature is enabled by default in open source Grafana and Grafana Enterprise. 2. Once the feature is enabled, create a new CloudWatch data source (or update an existing one) and select **Grafana Assume Role** as an authentication provider. 3. In the AWS Console, create a new IAM role, and under **Trusted entity type**, select **Another AWS account** as the trusted Entity. 4. Enter Grafana's account id (displayed in the instructions box on the **Settings** tab of the CloudWatch data source configuration) and check the **Require external ID** box. From c5e9aa0b596b247b7839052c722126a34b5e8ab0 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 27 Mar 2024 05:34:54 -0700 Subject: [PATCH 112/138] [v10.4.x] correct a url (#85246) correct a url (#85245) (cherry picked from commit cec25113f614c0bda63b9e73187a56f518ad19b5) Co-authored-by: Eve Meelan <81647476+Eve832@users.noreply.github.com> --- docs/sources/tutorials/alerting-get-started/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/tutorials/alerting-get-started/index.md b/docs/sources/tutorials/alerting-get-started/index.md index 941993bb1ecd..5020c1d6df8a 100644 --- a/docs/sources/tutorials/alerting-get-started/index.md +++ b/docs/sources/tutorials/alerting-get-started/index.md @@ -39,7 +39,7 @@ The sample application generates real data and exposes metrics, which are stored Download the files to your local machine. -1. Clone the [tutorial environment repository](www.github.com/grafana/tutorial-environment). +1. Clone the [tutorial environment repository](https://github.com/grafana/tutorial-environment). ```promql git clone https://github.com/grafana/tutorial-environment.git From eaf0dbe50d37929948b2625fbcd8ae067583dacd Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 27 Mar 2024 10:40:20 -0400 Subject: [PATCH 113/138] [v10.4.x] Added YouTube video to index.md on Time Series (#85276) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added YouTube video to index.md on Time Series (#85188) * Added YouTube video to index.md on Time Series Added a brief description and the YouTube link for the Time Series video. * Update index.md Did quick fix * Update index.md Found double space, removed, hope PR goes through * Update docs/sources/panels-visualizations/visualizations/time-series/index.md Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --------- Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> (cherry picked from commit d4953f4a1f4aad5f5e3717a14238d9094d434e35) Co-authored-by: Señor Performo - Leandro Melendez <54183040+srperf@users.noreply.github.com> --- .../panels-visualizations/visualizations/time-series/index.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/sources/panels-visualizations/visualizations/time-series/index.md b/docs/sources/panels-visualizations/visualizations/time-series/index.md index e41c20fa2bb3..e12b5ca80e5e 100644 --- a/docs/sources/panels-visualizations/visualizations/time-series/index.md +++ b/docs/sources/panels-visualizations/visualizations/time-series/index.md @@ -44,6 +44,10 @@ Time series visualizations are the default and primary way to visualize time ser You can migrate from the old Graph visualization to the new time series visualization. To migrate, open the panel and click the **Migrate** button in the side pane. {{% /admonition %}} +The following video guides you through the creation steps and common customizations of time series visualizations and is great for beginners: + +{{< youtube id="RKtW87cPxsw" >}} + ## Tooltip options Tooltip options control the information overlay that appears when you hover over data points in the graph. From 5430b1412f5b2bc8933ae00b8e1648cba3f5b789 Mon Sep 17 00:00:00 2001 From: Will Browne Date: Wed, 27 Mar 2024 15:52:09 +0100 Subject: [PATCH 114/138] [v10.4.x] Plugins: Pass PDC info as file paths (#85279) pass PDC filepaths --- pkg/plugins/envvars/envvars.go | 6 +++--- pkg/plugins/envvars/envvars_test.go | 22 +++++++++++----------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/pkg/plugins/envvars/envvars.go b/pkg/plugins/envvars/envvars.go index 9b343281b471..0871adfb8554 100644 --- a/pkg/plugins/envvars/envvars.go +++ b/pkg/plugins/envvars/envvars.go @@ -150,9 +150,9 @@ func (s *Service) GetConfigMap(ctx context.Context, pluginID string, _ *auth.Ext if s.cfg.ProxySettings.Enabled { m[proxy.PluginSecureSocksProxyEnabled] = "true" - m[proxy.PluginSecureSocksProxyClientCert] = s.cfg.ProxySettings.ClientCert - m[proxy.PluginSecureSocksProxyClientKey] = s.cfg.ProxySettings.ClientKey - m[proxy.PluginSecureSocksProxyRootCAs] = strings.Join(s.cfg.ProxySettings.RootCAs, " ") + m[proxy.PluginSecureSocksProxyClientCert] = s.cfg.ProxySettings.ClientCertFilePath + m[proxy.PluginSecureSocksProxyClientKey] = s.cfg.ProxySettings.ClientKeyFilePath + m[proxy.PluginSecureSocksProxyRootCAs] = strings.Join(s.cfg.ProxySettings.RootCAFilePaths, " ") m[proxy.PluginSecureSocksProxyProxyAddress] = s.cfg.ProxySettings.ProxyAddress m[proxy.PluginSecureSocksProxyServerName] = s.cfg.ProxySettings.ServerName m[proxy.PluginSecureSocksProxyAllowInsecure] = strconv.FormatBool(s.cfg.ProxySettings.AllowInsecure) diff --git a/pkg/plugins/envvars/envvars_test.go b/pkg/plugins/envvars/envvars_test.go index 9e626fe532ff..3b99feaec564 100644 --- a/pkg/plugins/envvars/envvars_test.go +++ b/pkg/plugins/envvars/envvars_test.go @@ -682,22 +682,22 @@ func TestService_GetConfigMap(t *testing.T) { cfg: &config.Cfg{ Features: featuremgmt.WithFeatures("feat-2", "feat-500", "feat-1"), ProxySettings: setting.SecureSocksDSProxySettings{ - Enabled: true, - ShowUI: true, - ClientCert: "c3rt", - ClientKey: "k3y", - RootCAs: []string{"ca"}, - ProxyAddress: "https://proxy.grafana.com", - ServerName: "secureProxy", - AllowInsecure: true, + Enabled: true, + ShowUI: true, + ClientCertFilePath: "./c3rt", + ClientKeyFilePath: "./k3y", + RootCAFilePaths: []string{"./ca"}, + ProxyAddress: "https://proxy.grafana.com", + ServerName: "secureProxy", + AllowInsecure: true, }, }, expected: map[string]string{ "GF_INSTANCE_FEATURE_TOGGLES_ENABLE": "feat-1,feat-2,feat-500", "GF_SECURE_SOCKS_DATASOURCE_PROXY_SERVER_ENABLED": "true", - "GF_SECURE_SOCKS_DATASOURCE_PROXY_CLIENT_CERT": "c3rt", - "GF_SECURE_SOCKS_DATASOURCE_PROXY_CLIENT_KEY": "k3y", - "GF_SECURE_SOCKS_DATASOURCE_PROXY_ROOT_CA_CERT": "ca", + "GF_SECURE_SOCKS_DATASOURCE_PROXY_CLIENT_CERT": "./c3rt", + "GF_SECURE_SOCKS_DATASOURCE_PROXY_CLIENT_KEY": "./k3y", + "GF_SECURE_SOCKS_DATASOURCE_PROXY_ROOT_CA_CERT": "./ca", "GF_SECURE_SOCKS_DATASOURCE_PROXY_PROXY_ADDRESS": "https://proxy.grafana.com", "GF_SECURE_SOCKS_DATASOURCE_PROXY_SERVER_NAME": "secureProxy", "GF_SECURE_SOCKS_DATASOURCE_PROXY_ALLOW_INSECURE": "true", From fe626877c77ce394972a5595f0cac7f4d3517d03 Mon Sep 17 00:00:00 2001 From: Jo Date: Wed, 27 Mar 2024 17:51:27 +0100 Subject: [PATCH 115/138] [v10.4.x] AuthProxy: Fix missing session for ldap auth proxy users (#85237) AuthProxy: Fix missing session for ldap auth proxy users (#85090) fix missing session for ldap auth proxy users (cherry picked from commit 7649d93d17edcc0814686cc152aa4a4e52739c27) --- pkg/api/login.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pkg/api/login.go b/pkg/api/login.go index 90b2d433a4a6..8a4d1524d73c 100644 --- a/pkg/api/login.go +++ b/pkg/api/login.go @@ -125,12 +125,11 @@ func (hs *HTTPServer) LoginView(c *contextmodel.ReqContext) { if c.IsSignedIn { // Assign login token to auth proxy users if enable_login_token = true - if hs.Cfg.AuthProxyEnabled && - hs.Cfg.AuthProxyEnableLoginToken && - c.SignedInUser.AuthenticatedBy == loginservice.AuthProxyAuthModule { + // LDAP users authenticated by auth proxy are also assigned login token but their auth module is LDAP + if hs.Cfg.AuthProxyEnabled && hs.Cfg.AuthProxyEnableLoginToken && + (c.SignedInUser.AuthenticatedBy == loginservice.AuthProxyAuthModule || c.SignedInUser.AuthenticatedBy == loginservice.LDAPAuthModule) { user := &user.User{ID: c.SignedInUser.UserID, Email: c.SignedInUser.Email, Login: c.SignedInUser.Login} - err := hs.loginUserWithUser(user, c) - if err != nil { + if err := hs.loginUserWithUser(user, c); err != nil { c.Handle(hs.Cfg, http.StatusInternalServerError, "Failed to sign in user", err) return } From 0f779159c55a8476e5e24c713096403aeb118869 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 28 Mar 2024 08:45:58 -0400 Subject: [PATCH 116/138] [v10.4.x] Docs: fix availability note (#85345) Docs: fix availability note (#85315) Fixed availability note (cherry picked from commit 5f38455f311d201f67091cb01aa11775bfb4c992) Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --- docs/sources/setup-grafana/image-rendering/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/setup-grafana/image-rendering/_index.md b/docs/sources/setup-grafana/image-rendering/_index.md index 61fd88e13dcd..7c386d95530d 100644 --- a/docs/sources/setup-grafana/image-rendering/_index.md +++ b/docs/sources/setup-grafana/image-rendering/_index.md @@ -18,7 +18,7 @@ weight: 1000 # Set up image rendering -Grafana supports automatic rendering of panels as PNG images. This allows Grafana to automatically generate images of your panels to include in alert notifications, [PDF export]({{< relref "../../dashboards/create-reports#export-dashboard-as-pdf" >}}), and [Reporting]({{< relref "../../dashboards/create-reports" >}}). PDF Export and Reporting are available only in [Grafana Enterprise]({{< relref "../../introduction/grafana-enterprise" >}}). +Grafana supports automatic rendering of panels as PNG images. This allows Grafana to automatically generate images of your panels to include in alert notifications, [PDF export]({{< relref "../../dashboards/create-reports#export-dashboard-as-pdf" >}}), and [Reporting]({{< relref "../../dashboards/create-reports" >}}). PDF Export and Reporting are available only in [Grafana Enterprise]({{< relref "../../introduction/grafana-enterprise" >}}) and [Grafana Cloud](/docs/grafana-cloud/). > **Note:** Image rendering of dashboards is not supported at this time. From 30100b2a4699992774381c93f4511dc4a09d7844 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 28 Mar 2024 07:49:26 -0500 Subject: [PATCH 117/138] [v10.4.x] [DOC] Clarify compatible log stores for traces to logs (#85349) [DOC] Clarify compatible log stores for traces to logs (#85314) * Clarify compatible log stores for traces to logs * Fixes from prettier (cherry picked from commit fe802f6d8828c67d3daa076c3da86b4670619c9f) Co-authored-by: Kim Nylander <104772500+knylander-grafana@users.noreply.github.com> --- docs/sources/datasources/tempo/configure-tempo-data-source.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/datasources/tempo/configure-tempo-data-source.md b/docs/sources/datasources/tempo/configure-tempo-data-source.md index 6107947d1376..4c8e0b3262f0 100644 --- a/docs/sources/datasources/tempo/configure-tempo-data-source.md +++ b/docs/sources/datasources/tempo/configure-tempo-data-source.md @@ -80,7 +80,7 @@ The following table describes the ways in which you can configure your trace to | Setting name | Description | | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| **Data source** | Defines the target data source. You can select only Loki or Splunk \[logs\] data sources. | +| **Data source** | Defines the target data source. You can select Loki or any compatible log store. | | **Span start time shift** | Shifts the start time for the logs query, based on the span's start time. You can use time units, such as `5s`, `1m`, `3h`. To extend the time to the past, use a negative value. Default: `0`. | | **Span end time shift** | Shifts the end time for the logs query, based on the span's end time. You can use time units. Default: `0`. | | **Tags** | Defines the tags to use in the logs query. Default: `cluster`, `hostname`, `namespace`, `pod`, `service.name`, `service.namespace`. You can change the tag name for example to remove dots from the name if they are not allowed in the target data source. For example, map `http.status` to `http_status`. | From df08b7960addb92f60565575c1d10689da1dc448 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 28 Mar 2024 11:42:54 -0400 Subject: [PATCH 118/138] [v10.4.x] docs: update histogram visualization (#85363) docs: update histogram visualization (#85125) * docs: update histogram visualization docs * docs: updates to histogram visualization * Apply suggestions from code review Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> * Fixed typo I introduced * docs: add youtube video --------- Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> (cherry picked from commit 4a3140a0aaefea33763fc94f2988e3d862334f9c) Co-authored-by: Marie Cruz --- .../visualizations/histogram/index.md | 58 +++++++++++++++++-- .../visualizations/state-timeline/index.md | 8 +-- 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/docs/sources/panels-visualizations/visualizations/histogram/index.md b/docs/sources/panels-visualizations/visualizations/histogram/index.md index 45f468196e0a..a406d7f11935 100644 --- a/docs/sources/panels-visualizations/visualizations/histogram/index.md +++ b/docs/sources/panels-visualizations/visualizations/histogram/index.md @@ -21,17 +21,67 @@ weight: 100 # Histogram -Histograms calculate the distribution of values and present them as a bar chart. The Y-axis and the height of each bar represent the count of values that fall into each bracket while the X-axis represents the value range. +Histograms calculate the distribution of values and present them as a bar chart. Each bar represents a bucket; the y-axis and the height of each bar represent the count of values that fall into each bucket, and the x-axis represents the value range. -{{< figure src="/static/img/docs/histogram-panel/histogram-example-v8-0.png" max-width="625px" caption="Bar chart example" >}} +For example, if you want to understand the distribution of people's heights, you can use a histogram visualization to identify patterns or insights in the data distribution: + +{{< figure src="/static/img/docs/histogram-panel/histogram-example-v8-0.png" max-width="625px" alt="A histogram visualization showing the distribution of people's heights" >}} + +You can use a histogram visualization if you need to: + +- Visualize and analyze data distributions over a specific time range to see how frequently certain values occur. +- Identify any outliers in your data distribution. +- Provide statistical analysis to help with decision-making + +## Configure a histogram visualization + +Once you’ve created a [dashboard](https://grafana.com/docs/grafana//dashboards/build-dashboards/create-dashboard/), the following video shows you how to configure a histogram visualization: + +{{< youtube id="QfJ480j9-KM" >}} ## Supported data formats Histograms support time series and any table results with one or more numerical fields. -## Display options +### Examples + +The following tables are examples of the type of data you need for a histogram visualization and how it should be formatted. + +#### Time-series table + +| Time | Walking (km) | +| ------------------- | ------------ | +| 2024-03-25 21:13:09 | 37.2 | +| 2024-03-25 21:13:10 | 37.1 | +| 2024-03-25 21:13:10 | 37.0 | +| 2024-03-25 21:13:11 | 37.2 | +| 2024-03-25 21:13:11 | 36.9 | +| 2024-03-25 21:13:12 | 36.7 | +| 2024-03-25 21:13:13 | 36.3 | + +The data is converted as follows: + +{{< figure src="/static/img/docs/histogram-panel/histogram-example-time-series.png" max-width="1025px" alt="A histogram visualization showing the walk distribution from random people over time." >}} + +#### Basic numerical table + +| Gender | Height (kg) | Weight (lbs) | +| ------ | ----------- | ------------ | +| Male | 73.8 | 242 | +| Male | 68.8 | 162 | +| Male | 74.1 | 213 | +| Male | 71.7 | 220 | +| Male | 69.9 | 206 | +| Male | 67.3 | 152 | +| Male | 68.8 | 184 | + +The data is converted as follows: + +{{< figure src="/static/img/docs/histogram-panel/histogram-example-height-weight.png" max-width="1025px" alt="A histogram visualization showing the male height and weight distribution" >}} + +## Histogram options -Use the following options to refine your visualization. +Use the following options to refine your histogram visualization. ### Bucket size diff --git a/docs/sources/panels-visualizations/visualizations/state-timeline/index.md b/docs/sources/panels-visualizations/visualizations/state-timeline/index.md index 92e916b6ef35..5384c8143f6a 100644 --- a/docs/sources/panels-visualizations/visualizations/state-timeline/index.md +++ b/docs/sources/panels-visualizations/visualizations/state-timeline/index.md @@ -23,7 +23,7 @@ A state timeline visualization displays data in a way that shows state changes o For example, if you're monitoring the CPU usage of a server, you can use a state timeline to visualize the different states, such as “LOW,” “NORMAL,” “HIGH,” or “CRITICAL,” over time. Each state is represented by a different color and the lengths represent the duration of time that the server remained in that state: -{{< figure src="/static/img/docs/state-timeline-panel/state-timeline-panel.png" max-width="1025px" alt="A state timeline panel showing CPU usage" >}} +{{< figure src="/static/img/docs/state-timeline-panel/state-timeline-panel.png" max-width="1025px" alt="A state timeline visualization showing CPU usage" >}} The state timeline visualization is useful when you need to monitor and analyze changes in states or statuses of various entities over time. You can use one when you need to: @@ -37,7 +37,7 @@ The state timeline visualization is useful when you need to monitor and analyze ## Supported data formats -The state timeline panel works best if you have data capturing the various states of entities over time, formatted as a table. The data must include: +The state timeline visualization works best if you have data capturing the various states of entities over time, formatted as a table. The data must include: - **Timestamps** - Indicate when each state change occurred. This could also be the start time for the state change. You can also add an optional timestamp to indicate the end time for the state change. - **Entity name/identifier** - Represents the name of the entity you're trying to monitor. @@ -65,7 +65,7 @@ The following tables are examples of the type of data you need for a state timel The data is converted as follows, with the [null and empty values visualized as gaps](https://grafana.com/docs/grafana/latest/panels-visualizations/visualizations/state-timeline/#connect-null-values) in the state timeline: -{{< figure src="/static/img/docs/state-timeline-panel/state-timeline-with-null-values.png" max-width="1025px" alt="A state timeline panel with null values showing the status of two servers" >}} +{{< figure src="/static/img/docs/state-timeline-panel/state-timeline-with-null-values.png" max-width="1025px" alt="A state timeline visualization with null values showing the status of two servers" >}} #### Two time columns without null values @@ -80,7 +80,7 @@ The data is converted as follows, with the [null and empty values visualized as The data is converted as follows: -{{< figure src="/static/img/docs/state-timeline-panel/state-timeline-with-two-timestamps.png" max-width="1025px" alt="A state timeline panel with two time columns showing the status of two servers" >}} +{{< figure src="/static/img/docs/state-timeline-panel/state-timeline-with-two-timestamps.png" max-width="1025px" alt="A state timeline visualization with two time columns showing the status of two servers" >}} If your query results aren't in a table format like the preceding examples, especially for time-series data, you can apply specific [transformations](https://stackoverflow.com/questions/68887416/grafana-state-timeline-panel-with-values-states-supplied-by-label) to achieve this. From 1565cc3ebdaca583aa9c897b867c178f6fc6f2bb Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Thu, 28 Mar 2024 19:50:00 -0500 Subject: [PATCH 119/138] [v10.4.x] OptionsPicker: Allow storing raw input even when matches exist (#85394) OptionsPicker: Allow storing raw input even when matches exist (#84790) (cherry picked from commit db6b51cb884cf15ac51b0a8358f9d3437da1ce12) Co-authored-by: Leon Sorokin --- .../pickers/OptionsPicker/reducer.test.ts | 46 ++++++++++++++++++- .../pickers/OptionsPicker/reducer.ts | 22 ++++++++- 2 files changed, 64 insertions(+), 4 deletions(-) diff --git a/public/app/features/variables/pickers/OptionsPicker/reducer.test.ts b/public/app/features/variables/pickers/OptionsPicker/reducer.test.ts index e5d1fc4678dc..9a2dfe161afe 100644 --- a/public/app/features/variables/pickers/OptionsPicker/reducer.test.ts +++ b/public/app/features/variables/pickers/OptionsPicker/reducer.test.ts @@ -569,8 +569,11 @@ describe('optionsPickerReducer', () => { .whenActionIsDispatched(updateOptionsAndFilter(options)) .thenStateShouldEqual({ ...initialState, - options: [{ text: 'All', value: '$__all', selected: true }], - selectedValues: [{ text: 'All', value: '$__all', selected: true }], + options: [ + { text: '> A', value: 'A', selected: false }, + { text: 'All', value: '$__all', selected: false }, + ], + selectedValues: [], queryValue: 'A', highlightIndex: 0, }); @@ -815,6 +818,45 @@ describe('optionsPickerReducer', () => { highlightIndex: 0, }); }); + + it('should offer as-typed option even when matches exist', () => { + const searchQuery = 'a.*'; + + const options: VariableOption[] = 'A AA AB C'.split(' ').map((v) => ({ + selected: false, + text: v, + value: v, + })); + + const expect: VariableOption[] = [ + { + selected: false, + text: '> ' + searchQuery, + value: searchQuery, + }, + ].concat( + 'A AA AB'.split(' ').map((v) => ({ + selected: false, + text: v, + value: v, + })) + ); + + const { initialState } = getVariableTestContext({ + queryValue: searchQuery, + }); + + reducerTester() + .givenReducer(optionsPickerReducer, cloneDeep(initialState)) + .whenActionIsDispatched(updateOptionsAndFilter(options)) + .thenStateShouldEqual({ + ...cloneDeep(initialState), + options: expect, + selectedValues: [], + queryValue: searchQuery, + highlightIndex: 1, + }); + }); }); describe('when large data for updateOptionsFromSearch is dispatched and variable has searchFilter', () => { diff --git a/public/app/features/variables/pickers/OptionsPicker/reducer.ts b/public/app/features/variables/pickers/OptionsPicker/reducer.ts index c9d53cf89bd0..57342c9010ee 100644 --- a/public/app/features/variables/pickers/OptionsPicker/reducer.ts +++ b/public/app/features/variables/pickers/OptionsPicker/reducer.ts @@ -267,13 +267,31 @@ const optionsPickerSlice = createSlice({ } // always sort $__all to the top, even if exact match exists? - opts.sort((a, b) => (a.value === '$__all' ? -1 : 0) - (b.value === '$__all' ? -1 : 0)); + opts.sort((a, b) => (a.value === ALL_VARIABLE_VALUE ? -1 : 0) - (b.value === ALL_VARIABLE_VALUE ? -1 : 0)); } } - state.options = opts; state.highlightIndex = 0; + if (needle !== '') { + // top ranked match index + let firstMatchIdx = opts.findIndex((o) => o.value !== ALL_VARIABLE_VALUE); + + // if there's no match or no exact match, prepend as-typed option + if (firstMatchIdx === -1 || opts[firstMatchIdx].value !== needle) { + opts.unshift({ + selected: false, + text: '> ' + needle, + value: needle, + }); + + // if no match at all, select as-typed, else select best match + state.highlightIndex = firstMatchIdx === -1 ? 0 : firstMatchIdx + 1; + } + } + + state.options = opts; + return applyStateChanges(state, updateDefaultSelection, updateOptions); }, updateOptionsFromSearch: (state, action: PayloadAction): OptionsPickerState => { From 726f38967cd65690a5598dad28cf12ed33af4a93 Mon Sep 17 00:00:00 2001 From: Will Browne Date: Fri, 29 Mar 2024 12:24:35 +0100 Subject: [PATCH 120/138] [10.4.x] Plugins: Send PDC file paths and contents for backwards compatibility (#85301) * Plugins: Send PDC file paths and contents for backwards compatibility * fix * fix test --- go.mod | 8 ++--- go.sum | 13 +++++--- pkg/plugins/envvars/envvars.go | 3 ++ pkg/plugins/envvars/envvars_test.go | 49 ++++++++++++++++++++++++----- 4 files changed, 56 insertions(+), 17 deletions(-) diff --git a/go.mod b/go.mod index 932950ff0264..be38881ec5f0 100644 --- a/go.mod +++ b/go.mod @@ -63,7 +63,7 @@ require ( github.com/grafana/cuetsy v0.1.11 // @grafana/grafana-as-code github.com/grafana/grafana-aws-sdk v0.23.1 // @grafana/aws-datasources github.com/grafana/grafana-azure-sdk-go v1.12.0 // @grafana/partner-datasources - github.com/grafana/grafana-plugin-sdk-go v0.217.0 // @grafana/plugins-platform-backend + github.com/grafana/grafana-plugin-sdk-go v0.218.0 // @grafana/plugins-platform-backend github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // @grafana/backend-platform github.com/hashicorp/go-hclog v1.6.2 // @grafana/plugins-platform-backend github.com/hashicorp/go-plugin v1.6.0 // @grafana/plugins-platform-backend @@ -92,7 +92,7 @@ require ( github.com/prometheus/prometheus v1.8.2-0.20221021121301-51a44e6657c3 // @grafana/alerting-squad-backend github.com/robfig/cron/v3 v3.0.1 // @grafana/backend-platform github.com/russellhaering/goxmldsig v1.4.0 // @grafana/backend-platform - github.com/stretchr/testify v1.8.4 // @grafana/backend-platform + github.com/stretchr/testify v1.9.0 // @grafana/backend-platform github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf // @grafana/backend-platform github.com/ua-parser/uap-go v0.0.0-20211112212520-00c877edfe0f // @grafana/backend-platform github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect @@ -108,7 +108,7 @@ require ( golang.org/x/crypto v0.21.0 // @grafana/backend-platform golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb // @grafana/alerting-squad-backend golang.org/x/net v0.22.0 // @grafana/oss-big-tent @grafana/partner-datasources - golang.org/x/oauth2 v0.16.0 // @grafana/grafana-authnz-team + golang.org/x/oauth2 v0.18.0 // @grafana/grafana-authnz-team golang.org/x/sync v0.6.0 // @grafana/alerting-squad-backend golang.org/x/time v0.5.0 // @grafana/backend-platform golang.org/x/tools v0.17.0 // @grafana/grafana-as-code @@ -206,7 +206,7 @@ require ( github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c // indirect github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/stretchr/objx v0.5.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect github.com/uber/jaeger-lib v2.4.1+incompatible // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect diff --git a/go.sum b/go.sum index 99600516ac9c..bd0f9ae8d684 100644 --- a/go.sum +++ b/go.sum @@ -2535,8 +2535,8 @@ github.com/grafana/grafana-google-sdk-go v0.1.0/go.mod h1:Vo2TKWfDVmNTELBUM+3lkr github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79 h1:r+mU5bGMzcXCRVAuOrTn54S80qbfVkvTdUJZfSfTNbs= github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79/go.mod h1:wc6Hbh3K2TgCUSfBC/BOzabItujtHMESZeFk5ZhdxhQ= github.com/grafana/grafana-plugin-sdk-go v0.114.0/go.mod h1:D7x3ah+1d4phNXpbnOaxa/osSaZlwh9/ZUnGGzegRbk= -github.com/grafana/grafana-plugin-sdk-go v0.217.0 h1:oQjq5KRrVrhweXHxFtEMgjv1KW7hujGiRPIYrsPZ9PE= -github.com/grafana/grafana-plugin-sdk-go v0.217.0/go.mod h1:FdvSvOliqpVLnytM7e89zCFyYPDE6VOn9SIjVQRvVxM= +github.com/grafana/grafana-plugin-sdk-go v0.218.0 h1:hKu6ziTgHHfdc/7UpIcWtBoP44/a7VkAJIBnECoRqTg= +github.com/grafana/grafana-plugin-sdk-go v0.218.0/go.mod h1:Cu+ezYbFY+IYDhIbPhkYegE3wl9VKrntSBkuVuJr+ZE= github.com/grafana/kindsys v0.0.0-20230508162304-452481b63482 h1:1YNoeIhii4UIIQpCPU+EXidnqf449d0C3ZntAEt4KSo= github.com/grafana/kindsys v0.0.0-20230508162304-452481b63482/go.mod h1:GNcfpy5+SY6RVbNGQW264gC0r336Dm+0zgQ5vt6+M8Y= github.com/grafana/prometheus-alertmanager v0.25.1-0.20240208102907-e82436ce63e6 h1:CBm0rwLCPDyarg9/bHJ50rBLYmyMDoyCWpgRMITZhdA= @@ -3537,8 +3537,9 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -3553,8 +3554,9 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.1.1/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= @@ -4124,8 +4126,9 @@ golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= -golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/pkg/plugins/envvars/envvars.go b/pkg/plugins/envvars/envvars.go index 0871adfb8554..dd9894b7ce5e 100644 --- a/pkg/plugins/envvars/envvars.go +++ b/pkg/plugins/envvars/envvars.go @@ -151,8 +151,11 @@ func (s *Service) GetConfigMap(ctx context.Context, pluginID string, _ *auth.Ext if s.cfg.ProxySettings.Enabled { m[proxy.PluginSecureSocksProxyEnabled] = "true" m[proxy.PluginSecureSocksProxyClientCert] = s.cfg.ProxySettings.ClientCertFilePath + m[proxy.PluginSecureSocksProxyClientCertContents] = s.cfg.ProxySettings.ClientCert m[proxy.PluginSecureSocksProxyClientKey] = s.cfg.ProxySettings.ClientKeyFilePath + m[proxy.PluginSecureSocksProxyClientKeyContents] = s.cfg.ProxySettings.ClientKey m[proxy.PluginSecureSocksProxyRootCAs] = strings.Join(s.cfg.ProxySettings.RootCAFilePaths, " ") + m[proxy.PluginSecureSocksProxyRootCAsContents] = strings.Join(s.cfg.ProxySettings.RootCAs, ",") m[proxy.PluginSecureSocksProxyProxyAddress] = s.cfg.ProxySettings.ProxyAddress m[proxy.PluginSecureSocksProxyServerName] = s.cfg.ProxySettings.ServerName m[proxy.PluginSecureSocksProxyAllowInsecure] = strconv.FormatBool(s.cfg.ProxySettings.AllowInsecure) diff --git a/pkg/plugins/envvars/envvars_test.go b/pkg/plugins/envvars/envvars_test.go index 3b99feaec564..3db05a92b40f 100644 --- a/pkg/plugins/envvars/envvars_test.go +++ b/pkg/plugins/envvars/envvars_test.go @@ -684,23 +684,29 @@ func TestService_GetConfigMap(t *testing.T) { ProxySettings: setting.SecureSocksDSProxySettings{ Enabled: true, ShowUI: true, + ClientCert: "c3rt", ClientCertFilePath: "./c3rt", + ClientKey: "k3y", ClientKeyFilePath: "./k3y", RootCAFilePaths: []string{"./ca"}, + RootCAs: []string{"ca"}, ProxyAddress: "https://proxy.grafana.com", ServerName: "secureProxy", AllowInsecure: true, }, }, expected: map[string]string{ - "GF_INSTANCE_FEATURE_TOGGLES_ENABLE": "feat-1,feat-2,feat-500", - "GF_SECURE_SOCKS_DATASOURCE_PROXY_SERVER_ENABLED": "true", - "GF_SECURE_SOCKS_DATASOURCE_PROXY_CLIENT_CERT": "./c3rt", - "GF_SECURE_SOCKS_DATASOURCE_PROXY_CLIENT_KEY": "./k3y", - "GF_SECURE_SOCKS_DATASOURCE_PROXY_ROOT_CA_CERT": "./ca", - "GF_SECURE_SOCKS_DATASOURCE_PROXY_PROXY_ADDRESS": "https://proxy.grafana.com", - "GF_SECURE_SOCKS_DATASOURCE_PROXY_SERVER_NAME": "secureProxy", - "GF_SECURE_SOCKS_DATASOURCE_PROXY_ALLOW_INSECURE": "true", + "GF_INSTANCE_FEATURE_TOGGLES_ENABLE": "feat-1,feat-2,feat-500", + "GF_SECURE_SOCKS_DATASOURCE_PROXY_SERVER_ENABLED": "true", + "GF_SECURE_SOCKS_DATASOURCE_PROXY_CLIENT_CERT": "./c3rt", + "GF_SECURE_SOCKS_DATASOURCE_PROXY_CLIENT_CERT_VAL": "c3rt", + "GF_SECURE_SOCKS_DATASOURCE_PROXY_CLIENT_KEY": "./k3y", + "GF_SECURE_SOCKS_DATASOURCE_PROXY_CLIENT_KEY_VAL": "k3y", + "GF_SECURE_SOCKS_DATASOURCE_PROXY_ROOT_CA_CERT": "./ca", + "GF_SECURE_SOCKS_DATASOURCE_PROXY_ROOT_CA_CERT_VALS": "ca", + "GF_SECURE_SOCKS_DATASOURCE_PROXY_PROXY_ADDRESS": "https://proxy.grafana.com", + "GF_SECURE_SOCKS_DATASOURCE_PROXY_SERVER_NAME": "secureProxy", + "GF_SECURE_SOCKS_DATASOURCE_PROXY_ALLOW_INSECURE": "true", }, }, { @@ -745,6 +751,33 @@ func TestService_GetConfigMap(t *testing.T) { }, expected: map[string]string{}, }, + { + name: "Multiple Root CA certs in proxy settings are supported", + cfg: &config.Cfg{ + ProxySettings: setting.SecureSocksDSProxySettings{ + Enabled: true, + ShowUI: true, + RootCAFilePaths: []string{"./ca", "./ca2"}, + RootCAs: []string{"ca", "ca2"}, + ProxyAddress: "https://proxy.grafana.com", + ServerName: "secureProxy", + AllowInsecure: true, + }, + Features: featuremgmt.WithFeatures(), + }, + expected: map[string]string{ + "GF_SECURE_SOCKS_DATASOURCE_PROXY_SERVER_ENABLED": "true", + "GF_SECURE_SOCKS_DATASOURCE_PROXY_CLIENT_CERT": "", + "GF_SECURE_SOCKS_DATASOURCE_PROXY_CLIENT_CERT_VAL": "", + "GF_SECURE_SOCKS_DATASOURCE_PROXY_CLIENT_KEY": "", + "GF_SECURE_SOCKS_DATASOURCE_PROXY_CLIENT_KEY_VAL": "", + "GF_SECURE_SOCKS_DATASOURCE_PROXY_ROOT_CA_CERT": "./ca ./ca2", + "GF_SECURE_SOCKS_DATASOURCE_PROXY_ROOT_CA_CERT_VALS": "ca,ca2", + "GF_SECURE_SOCKS_DATASOURCE_PROXY_PROXY_ADDRESS": "https://proxy.grafana.com", + "GF_SECURE_SOCKS_DATASOURCE_PROXY_SERVER_NAME": "secureProxy", + "GF_SECURE_SOCKS_DATASOURCE_PROXY_ALLOW_INSECURE": "true", + }, + }, } for _, tc := range tcs { t.Run(tc.name, func(t *testing.T) { From 78e07dc60937cf0746f010ae06943ab2db71c337 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Fri, 29 Mar 2024 21:50:11 +0200 Subject: [PATCH 121/138] [v10.4.x] Plugins: Set correct PDC config values for proxy requests (#85413) Plugins: Set correct PDC config values for proxy requests (#85412) pass appropriate values (cherry picked from commit 22fe7b067cdfbc52543a536de9bf8303fdc26286) Co-authored-by: Will Browne --- pkg/services/datasources/service/datasource.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pkg/services/datasources/service/datasource.go b/pkg/services/datasources/service/datasource.go index 43f2ccd79465..c0f95f56e9b7 100644 --- a/pkg/services/datasources/service/datasource.go +++ b/pkg/services/datasources/service/datasource.go @@ -532,9 +532,12 @@ func (s *Service) httpClientOptions(ctx context.Context, ds *datasources.DataSou }, Timeouts: &sdkproxy.DefaultTimeoutOptions, ClientCfg: &sdkproxy.ClientCfg{ - ClientCert: s.cfg.SecureSocksDSProxy.ClientCert, - ClientKey: s.cfg.SecureSocksDSProxy.ClientKey, - RootCAs: s.cfg.SecureSocksDSProxy.RootCAs, + ClientCert: s.cfg.SecureSocksDSProxy.ClientCertFilePath, + ClientKey: s.cfg.SecureSocksDSProxy.ClientKeyFilePath, + RootCAs: s.cfg.SecureSocksDSProxy.RootCAFilePaths, + ClientCertVal: s.cfg.SecureSocksDSProxy.ClientCert, + ClientKeyVal: s.cfg.SecureSocksDSProxy.ClientKey, + RootCAsVals: s.cfg.SecureSocksDSProxy.RootCAs, ProxyAddress: s.cfg.SecureSocksDSProxy.ProxyAddress, ServerName: s.cfg.SecureSocksDSProxy.ServerName, AllowInsecure: s.cfg.SecureSocksDSProxy.AllowInsecure, From d5e252f8e04c1e052fd83794f54b00084a180caa Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 3 Apr 2024 10:29:36 +0200 Subject: [PATCH 122/138] [v10.4.x] alerging-get-started: update (#85511) alerging-get-started: update (#85434) * alerging-get-started: update * Update index.md * Update index.md (cherry picked from commit 826fa2f2db1408b1ccd7fc37ff1c28809d193964) Co-authored-by: antonio <45235678+tonypowa@users.noreply.github.com> --- .../tutorials/alerting-get-started/index.md | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/docs/sources/tutorials/alerting-get-started/index.md b/docs/sources/tutorials/alerting-get-started/index.md index 5020c1d6df8a..09e11fb79b71 100644 --- a/docs/sources/tutorials/alerting-get-started/index.md +++ b/docs/sources/tutorials/alerting-get-started/index.md @@ -1,7 +1,7 @@ --- Feedback Link: https://github.com/grafana/tutorials/issues/new authors: - - Antonio Calero + - antonio-calero-merello categories: - alerting description: Get started with Grafana Alerting by creating your first alert in just a few minutes. Learn how to set up an alert, send alert notifications to a public webhook, and generate sample data to observe your alert in action. @@ -41,19 +41,19 @@ Download the files to your local machine. 1. Clone the [tutorial environment repository](https://github.com/grafana/tutorial-environment). - ```promql + ``` git clone https://github.com/grafana/tutorial-environment.git ``` 1. Change to the directory where you cloned the repository: - ```promql + ``` cd tutorial-environment ``` 1. Make sure Docker is running: - ```promql + ``` docker --version ``` @@ -61,19 +61,19 @@ Download the files to your local machine. 1. Start the sample application: - ```promql + ``` docker compose up -d ``` The first time you run `docker compose up -d`, Docker downloads all the necessary resources for the tutorial. This might take a few minutes, depending on your internet connection. {{< admonition type="note" >}} - If you already have Grafana, Loki, or Prometheus running on your system, you might see errors, because the Docker image is trying to use ports that your local installations are already using. . If this is the case, stop the services, then run the command again. + If you already have Grafana, Loki, or Prometheus running on your system, you might see errors, because the Docker image is trying to use ports that your local installations are already using. If this is the case, stop the services, then run the command again. {{< /admonition >}} 1. Ensure all services are up-and-running: - ```promql + ``` docker compose ps ``` @@ -107,7 +107,7 @@ In this step, we'll set up a new contact point. This contact point will use the You should get logged in automatically. 1. In another window, go to [requestbin.com](https://requestbin.com). 1. Under the **Create Request Bin** button, click the link to create a **public bin** instead. -1. From Request Bin, copy the endpoint URL. +1. From Request Bin, **copy the endpoint URL**. Your Request Bin is now waiting for the first request. @@ -118,12 +118,11 @@ Next, let's configure a Contact Point in Grafana's Alerting UI to send notificat 1. In **Name**, write **RequestBin**. 1. In **Integration**, choose **Webhook**. 1. In **URL**, paste the endpoint to your request bin. - 1. Click **Test**, and then click **Send test notification** to send a test alert to your request bin. 1. Navigate back to the Request Bin you created earlier. On the left side, there's now a `POST /` entry. Click it to see what information Grafana sent. 1. Return to Grafana and click **Save contact point**. -We have now created a dummy webhook endpoint and created a new Alerting Contact Point in Grafana. Now we can create an alert rule and link it to this new channel. +We have created a dummy webhook endpoint and created a new Alerting Contact Point in Grafana. Now, we can create an alert rule and link it to this new channel. ## Create an alert @@ -180,12 +179,8 @@ An evaluation group defines an evaluation interval - how often a rule is checked Add labels to ease searching or route notifications to a policy. -1. Add a label. - Add `app` as the label key, and `grafana-news` as the value. - -1. Add a notification recipient. - Under **Contact point**, select **RequestBin** from the drop-down menu. - +1. Add a label.Add `app` as the label key, and `grafana-news` as the value. +1. Add a notification recipient. Under **Contact point**, select **RequestBin** from the drop-down menu. 1. Add an annotation (optional). To provide more context on the alert, you can link a dashboard and panel to our Alert. To do this, click **Link Dashboard and panel** button. From 8da97103ad7f821920c2ce678937c20bb5cebcb0 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 3 Apr 2024 11:21:54 -0400 Subject: [PATCH 123/138] [v10.4.x] Docs: add YouTube video link and description (#85537) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docs: add YouTube video link and description (#85484) * Update index.md Adding YouTube video link and description Added a short description about the video and added the video to the page. * Update docs/sources/panels-visualizations/visualizations/logs/index.md Some edits went in. All nice :) Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> * Removed repetition --------- Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> (cherry picked from commit f6a94837c5ef49326bc4916a9b0299ca29a9348a) Co-authored-by: Señor Performo - Leandro Melendez <54183040+srperf@users.noreply.github.com> --- .../panels-visualizations/visualizations/logs/index.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/sources/panels-visualizations/visualizations/logs/index.md b/docs/sources/panels-visualizations/visualizations/logs/index.md index 2068923c1742..17739cafdef7 100644 --- a/docs/sources/panels-visualizations/visualizations/logs/index.md +++ b/docs/sources/panels-visualizations/visualizations/logs/index.md @@ -30,6 +30,10 @@ The logs visualization shows the result of queries that were entered in the Quer To limit the number of lines rendered, you can use the **Max data points** setting in the **Query options**. If it is not set, then the data source will usually enforce a default limit. +The following video provides a walkthrough of creating a logs visualization. You'll also learn how to customize some settings and log visualization caveats: + +{{< youtube id="jSSi_x-fD_8" >}} + ## Log level For logs where a **level** label is specified, we use the value of the label to determine the log level and update color accordingly. If the log doesn't have a level label specified, we try to find out if its content matches any of the supported expressions (see below for more information). The log level is always determined by the first match. In case Grafana is not able to determine a log level, it will be visualized with **unknown** log level. See [supported log levels and mappings of log level abbreviation and expressions][]. From 6b124e20318e6bddf2f4a18c841db172fe44796e Mon Sep 17 00:00:00 2001 From: Drew Slobodnjak <60050885+drew08t@users.noreply.github.com> Date: Thu, 4 Apr 2024 11:02:27 -0700 Subject: [PATCH 124/138] [v10.4.x] Canvas: Infinite Pan Backport (#85608) --- .../canvas/panelcfg/schema-reference.md | 1 + .../panelcfg/x/CanvasPanelCfg_types.gen.ts | 5 +++ .../canvas/runtime/SceneTransformWrapper.tsx | 35 ++++++++++++++++++- public/app/features/canvas/runtime/scene.tsx | 13 +++++-- .../app/plugins/panel/canvas/CanvasPanel.tsx | 13 +++++-- public/app/plugins/panel/canvas/module.tsx | 8 +++++ public/app/plugins/panel/canvas/panelcfg.cue | 2 ++ .../app/plugins/panel/canvas/panelcfg.gen.ts | 5 +++ 8 files changed, 77 insertions(+), 5 deletions(-) diff --git a/docs/sources/developers/kinds/composable/canvas/panelcfg/schema-reference.md b/docs/sources/developers/kinds/composable/canvas/panelcfg/schema-reference.md index ca4647b16ff5..64177f5f42d2 100644 --- a/docs/sources/developers/kinds/composable/canvas/panelcfg/schema-reference.md +++ b/docs/sources/developers/kinds/composable/canvas/panelcfg/schema-reference.md @@ -141,6 +141,7 @@ It extends [BaseDimensionConfig](#basedimensionconfig). | Property | Type | Required | Default | Description | |---------------------|-----------------|----------|---------|--------------------------------------------------------------------------------------------------------------------------------------| +| `infinitePan` | boolean | **Yes** | `true` | Enable infinite pan | | `inlineEditing` | boolean | **Yes** | `true` | Enable inline editing | | `panZoom` | boolean | **Yes** | `true` | Enable pan and zoom | | `root` | [object](#root) | **Yes** | | The root element of canvas (frame), where all canvas elements are nested
TODO: Figure out how to define a default value for this | diff --git a/packages/grafana-schema/src/raw/composable/canvas/panelcfg/x/CanvasPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/canvas/panelcfg/x/CanvasPanelCfg_types.gen.ts index f8d6f1ebc506..44e8b202cf0e 100644 --- a/packages/grafana-schema/src/raw/composable/canvas/panelcfg/x/CanvasPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/canvas/panelcfg/x/CanvasPanelCfg_types.gen.ts @@ -105,6 +105,10 @@ export const defaultCanvasElementOptions: Partial = { }; export interface Options { + /** + * Enable infinite pan + */ + infinitePan: boolean; /** * Enable inline editing */ @@ -138,6 +142,7 @@ export interface Options { } export const defaultOptions: Partial = { + infinitePan: true, inlineEditing: true, panZoom: true, showAdvancedTypes: true, diff --git a/public/app/features/canvas/runtime/SceneTransformWrapper.tsx b/public/app/features/canvas/runtime/SceneTransformWrapper.tsx index c868cd3d497f..ef8458b57319 100644 --- a/public/app/features/canvas/runtime/SceneTransformWrapper.tsx +++ b/public/app/features/canvas/runtime/SceneTransformWrapper.tsx @@ -14,6 +14,15 @@ export const SceneTransformWrapper = ({ scene, children: sceneDiv }: SceneTransf const onZoom = (zoomPanPinchRef: ReactZoomPanPinchRef) => { const scale = zoomPanPinchRef.state.scale; scene.scale = scale; + + if (scene.shouldInfinitePan) { + const isScaleZoomedOut = scale < 1; + + if (isScaleZoomedOut) { + scene.updateSize(scene.width / scale, scene.height / scale); + scene.panel.forceUpdate(); + } + } }; const onZoomStop = (zoomPanPinchRef: ReactZoomPanPinchRef) => { @@ -22,6 +31,25 @@ export const SceneTransformWrapper = ({ scene, children: sceneDiv }: SceneTransf updateMoveable(scale); }; + const onPanning = (_: ReactZoomPanPinchRef, event: MouseEvent | TouchEvent) => { + if (scene.shouldInfinitePan && event instanceof MouseEvent) { + // Get deltaX and deltaY from pan event and add it to current canvas dimensions + let deltaX = event.movementX; + let deltaY = event.movementY; + if (deltaX > 0) { + deltaX = 0; + } + if (deltaY > 0) { + deltaY = 0; + } + + // TODO: Consider bounding to the scene elements instead of allowing "infinite" panning + // TODO: Consider making scene grow in all directions vs just down to the right / bottom + scene.updateSize(scene.width - deltaX, scene.height - deltaY); + scene.panel.forceUpdate(); + } + }; + const onTransformed = ( _: ReactZoomPanPinchRef, state: { @@ -60,6 +88,9 @@ export const SceneTransformWrapper = ({ scene, children: sceneDiv }: SceneTransf } }; + // Set panel content overflow to hidden to prevent canvas content from overflowing + scene.div?.parentElement?.parentElement?.parentElement?.parentElement?.setAttribute('style', `overflow: hidden`); + return ( {/* The
element has child elements that allow for mouse events, so we need to disable the linter rule */} diff --git a/public/app/features/canvas/runtime/scene.tsx b/public/app/features/canvas/runtime/scene.tsx index e753b732e319..11ce7cf39a48 100644 --- a/public/app/features/canvas/runtime/scene.tsx +++ b/public/app/features/canvas/runtime/scene.tsx @@ -71,6 +71,7 @@ export class Scene { isEditingEnabled?: boolean; shouldShowAdvancedTypes?: boolean; shouldPanZoom?: boolean; + shouldInfinitePan?: boolean; skipNextSelectionBroadcast = false; ignoreDataUpdate = false; panel: CanvasPanel; @@ -108,10 +109,11 @@ export class Scene { enableEditing: boolean, showAdvancedTypes: boolean, panZoom: boolean, + infinitePan: boolean, public onSave: (cfg: CanvasFrameOptions) => void, panel: CanvasPanel ) { - this.root = this.load(cfg, enableEditing, showAdvancedTypes, panZoom); + this.root = this.load(cfg, enableEditing, showAdvancedTypes, panZoom, infinitePan); this.subscription = this.editModeEnabled.subscribe((open) => { if (!this.moveable || !this.isEditingEnabled) { @@ -144,7 +146,13 @@ export class Scene { return !this.byName.has(v); }; - load(cfg: CanvasFrameOptions, enableEditing: boolean, showAdvancedTypes: boolean, panZoom: boolean) { + load( + cfg: CanvasFrameOptions, + enableEditing: boolean, + showAdvancedTypes: boolean, + panZoom: boolean, + infinitePan: boolean + ) { this.root = new RootElement( cfg ?? { type: 'frame', @@ -157,6 +165,7 @@ export class Scene { this.isEditingEnabled = enableEditing; this.shouldShowAdvancedTypes = showAdvancedTypes; this.shouldPanZoom = panZoom; + this.shouldInfinitePan = infinitePan; setTimeout(() => { if (this.div) { diff --git a/public/app/plugins/panel/canvas/CanvasPanel.tsx b/public/app/plugins/panel/canvas/CanvasPanel.tsx index 88cdd6f30a06..195838a4231f 100644 --- a/public/app/plugins/panel/canvas/CanvasPanel.tsx +++ b/public/app/plugins/panel/canvas/CanvasPanel.tsx @@ -68,6 +68,7 @@ export class CanvasPanel extends Component { this.props.options.inlineEditing, this.props.options.showAdvancedTypes, this.props.options.panZoom, + this.props.options.infinitePan, this.onUpdateScene, this ); @@ -229,7 +230,14 @@ export class CanvasPanel extends Component { const shouldShowAdvancedTypesSwitched = this.props.options.showAdvancedTypes !== nextProps.options.showAdvancedTypes; const panZoomSwitched = this.props.options.panZoom !== nextProps.options.panZoom; - if (this.needsReload || inlineEditingSwitched || shouldShowAdvancedTypesSwitched || panZoomSwitched) { + const infinitePanSwitched = this.props.options.infinitePan !== nextProps.options.infinitePan; + if ( + this.needsReload || + inlineEditingSwitched || + shouldShowAdvancedTypesSwitched || + panZoomSwitched || + infinitePanSwitched + ) { if (inlineEditingSwitched) { // Replace scene div to prevent selecto instance leaks this.scene.revId++; @@ -240,7 +248,8 @@ export class CanvasPanel extends Component { nextProps.options.root, nextProps.options.inlineEditing, nextProps.options.showAdvancedTypes, - nextProps.options.panZoom + nextProps.options.panZoom, + nextProps.options.infinitePan ); this.scene.updateSize(nextProps.width, nextProps.height); this.scene.updateData(nextProps.data); diff --git a/public/app/plugins/panel/canvas/module.tsx b/public/app/plugins/panel/canvas/module.tsx index 96ef9f144dbe..75566872d8bc 100644 --- a/public/app/plugins/panel/canvas/module.tsx +++ b/public/app/plugins/panel/canvas/module.tsx @@ -39,6 +39,14 @@ export const addStandardCanvasEditorOptions = (builder: PanelOptionsEditorBuilde editor: PanZoomHelp, showIf: (opts) => config.featureToggles.canvasPanelPanZoom && opts.panZoom, }); + builder.addBooleanSwitch({ + path: 'infinitePan', + name: 'Infinite panning', + description: + 'Enable infinite panning - useful for expansive canvases. Warning: this an experimental feature and currently only works well with elements that are top / left constrained', + defaultValue: false, + showIf: (opts) => config.featureToggles.canvasPanelPanZoom && opts.panZoom, + }); }; export const plugin = new PanelPlugin(CanvasPanel) diff --git a/public/app/plugins/panel/canvas/panelcfg.cue b/public/app/plugins/panel/canvas/panelcfg.cue index c68db38ff813..142e5e53f5a7 100644 --- a/public/app/plugins/panel/canvas/panelcfg.cue +++ b/public/app/plugins/panel/canvas/panelcfg.cue @@ -90,6 +90,8 @@ composableKinds: PanelCfg: { showAdvancedTypes: bool | *true // Enable pan and zoom panZoom: bool | *true + // Enable infinite pan + infinitePan: bool | *true // The root element of canvas (frame), where all canvas elements are nested // TODO: Figure out how to define a default value for this root: { diff --git a/public/app/plugins/panel/canvas/panelcfg.gen.ts b/public/app/plugins/panel/canvas/panelcfg.gen.ts index 880ef5d22db8..b8bcd8d76ccf 100644 --- a/public/app/plugins/panel/canvas/panelcfg.gen.ts +++ b/public/app/plugins/panel/canvas/panelcfg.gen.ts @@ -102,6 +102,10 @@ export const defaultCanvasElementOptions: Partial = { }; export interface Options { + /** + * Enable infinite pan + */ + infinitePan: boolean; /** * Enable inline editing */ @@ -135,6 +139,7 @@ export interface Options { } export const defaultOptions: Partial = { + infinitePan: true, inlineEditing: true, panZoom: true, showAdvancedTypes: true, From af94019e2ad4f70655cf64479a59876eca16330e Mon Sep 17 00:00:00 2001 From: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> Date: Thu, 4 Apr 2024 15:00:13 -0400 Subject: [PATCH 125/138] [v10.4.x] Docs: added infinite pan to canvas docs (#85610) Added infinte pan --- .../visualizations/canvas/index.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/sources/panels-visualizations/visualizations/canvas/index.md b/docs/sources/panels-visualizations/visualizations/canvas/index.md index 162639163a91..4b9cd1f3e801 100644 --- a/docs/sources/panels-visualizations/visualizations/canvas/index.md +++ b/docs/sources/panels-visualizations/visualizations/canvas/index.md @@ -95,6 +95,16 @@ You can enable panning and zooming in a canvas. This allows you to both create a {{< video-embed src="/media/docs/grafana/2024-01-05-Canvas-Pan-&-Zoom-Enablement-Video.mp4" max-width="750px" caption="Canvas pan and zoom enablement video" >}} +#### Infinite panning + +You can enable infinite panning in a canvas when pan and zoom is enabled. This allows you to pan and zoom the canvas and uncover larger designs. + +{{% admonition type="note" %}} +Infinite panning is an experimental feature that may not work as expected in all scenarios. For example, elements that are not top-left constrained may experience unexpected movement when panning. +{{% /admonition %}} + + + ### Context menu The context menu lets you perform common tasks quickly and efficiently. Supported functionality includes opening / closing the inline editor, duplicating an element, deleting an element, and more. From 71bee5716bf07e613c04ee82d263c89bdbfcd6f2 Mon Sep 17 00:00:00 2001 From: Giuseppe Guerra Date: Fri, 5 Apr 2024 11:46:05 +0200 Subject: [PATCH 126/138] [v10.4.x] Angular deprecation: Prefer local "angularDetected" value to the remote one (#85631) Angular deprecation: Prefer local "angularDetected" value to the remote one (#85571) * Angular deprecation: Prefer local value to remote * Update tests (cherry picked from commit c033a15aaa76f113a0cd93b01407dab258ac78a3) --- .../admin/__mocks__/localPlugin.mock.ts | 1 + .../admin/__mocks__/remotePlugin.mock.ts | 1 + .../features/plugins/admin/helpers.test.ts | 32 +++++++++++++++++++ public/app/features/plugins/admin/helpers.ts | 2 +- 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/public/app/features/plugins/admin/__mocks__/localPlugin.mock.ts b/public/app/features/plugins/admin/__mocks__/localPlugin.mock.ts index b0744b0a2d8c..341be1f83b53 100644 --- a/public/app/features/plugins/admin/__mocks__/localPlugin.mock.ts +++ b/public/app/features/plugins/admin/__mocks__/localPlugin.mock.ts @@ -68,4 +68,5 @@ export default { signature: 'valid', signatureType: 'community', signatureOrg: 'Alexander Zobnin', + angularDetected: false, } as LocalPlugin; diff --git a/public/app/features/plugins/admin/__mocks__/remotePlugin.mock.ts b/public/app/features/plugins/admin/__mocks__/remotePlugin.mock.ts index d716ae4df5b8..52b9d0a825ca 100644 --- a/public/app/features/plugins/admin/__mocks__/remotePlugin.mock.ts +++ b/public/app/features/plugins/admin/__mocks__/remotePlugin.mock.ts @@ -47,4 +47,5 @@ export default { links: [], }, }, + angularDetected: false, } as RemotePlugin; diff --git a/public/app/features/plugins/admin/helpers.test.ts b/public/app/features/plugins/admin/helpers.test.ts index faef81ce920c..6def922c53d3 100644 --- a/public/app/features/plugins/admin/helpers.test.ts +++ b/public/app/features/plugins/admin/helpers.test.ts @@ -158,6 +158,7 @@ describe('Plugins/Helpers', () => { type: 'app', updatedAt: '2021-05-18T14:53:01.000Z', isFullyInstalled: false, + angularDetected: false, }); }); @@ -237,6 +238,7 @@ describe('Plugins/Helpers', () => { updatedAt: '2021-08-25', installedVersion: '4.2.2', isFullyInstalled: true, + angularDetected: false, }); }); @@ -288,6 +290,7 @@ describe('Plugins/Helpers', () => { updatedAt: '2021-05-18T14:53:01.000Z', installedVersion: '4.2.2', isFullyInstalled: true, + angularDetected: false, }); }); @@ -670,6 +673,35 @@ describe('Plugins/Helpers', () => { // No local or remote expect(mapToCatalogPlugin()).toMatchObject({ updatedAt: '' }); }); + + test('`.angularDetected` - prefers the local', () => { + // Both false shoul return false + expect( + mapToCatalogPlugin({ ...localPlugin, angularDetected: false }, { ...remotePlugin, angularDetected: false }) + ).toMatchObject({ angularDetected: false }); + + // Remote version is using angular, local isn't, should prefer local + expect( + mapToCatalogPlugin({ ...localPlugin, angularDetected: false }, { ...remotePlugin, angularDetected: true }) + ).toMatchObject({ angularDetected: false }); + + // Remote only + expect(mapToCatalogPlugin(undefined, remotePlugin)).toMatchObject({ angularDetected: false }); + expect(mapToCatalogPlugin(undefined, { ...remotePlugin, angularDetected: true })).toMatchObject({ + angularDetected: true, + }); + + // Local only + expect(mapToCatalogPlugin({ ...localPlugin, angularDetected: false }, undefined)).toMatchObject({ + angularDetected: false, + }); + expect(mapToCatalogPlugin({ ...localPlugin, angularDetected: true }, undefined)).toMatchObject({ + angularDetected: true, + }); + + // No local or remote + expect(mapToCatalogPlugin()).toMatchObject({ angularDetected: undefined }); + }); }); describe('sortPlugins()', () => { diff --git a/public/app/features/plugins/admin/helpers.ts b/public/app/features/plugins/admin/helpers.ts index 621d342b6265..a860691a9379 100644 --- a/public/app/features/plugins/admin/helpers.ts +++ b/public/app/features/plugins/admin/helpers.ts @@ -225,7 +225,7 @@ export function mapToCatalogPlugin(local?: LocalPlugin, remote?: RemotePlugin, e error: error?.errorCode, // Only local plugins have access control metadata accessControl: local?.accessControl, - angularDetected: local?.angularDetected || remote?.angularDetected, + angularDetected: local?.angularDetected ?? remote?.angularDetected, isFullyInstalled: Boolean(local) || isDisabled, iam: local?.iam, }; From 1eab6e50c6e9831bf4036e37a5779627e5e34c71 Mon Sep 17 00:00:00 2001 From: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> Date: Fri, 5 Apr 2024 16:58:49 -0400 Subject: [PATCH 127/138] [v10.4.x] docs: add missing viz types to index (#85685) docs: add missing viz types to index (#85400) * docs: add missing viz types to index * prettier * Update _index.md Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> * fix merge mistake * fix cloud links --------- Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> (cherry picked from commit cd055684595f7fbfe7a9dc10656731e0e8760d72) Co-authored-by: David Harris --- .../visualizations/_index.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/docs/sources/panels-visualizations/visualizations/_index.md b/docs/sources/panels-visualizations/visualizations/_index.md index b5c26e0f79ff..e38f957f6be9 100644 --- a/docs/sources/panels-visualizations/visualizations/_index.md +++ b/docs/sources/panels-visualizations/visualizations/_index.md @@ -36,6 +36,7 @@ If you are unsure which visualization to pick, Grafana can provide visualization - [Pie chart][] is typically used where proportionality is important. - [Candlestick][] is typically for financial data where the focus is price/data movement. - [Gauge][] is the traditional rounded visual showing how far a single metric is from a threshold. + - [Trend][] for datasets that have a sequential, numeric x that is not time. - Stats & numbers - [Stat][] for big stats and optional sparkline. - [Bar gauge][] is a horizontal or vertical bar gauge. @@ -47,9 +48,11 @@ If you are unsure which visualization to pick, Grafana can provide visualization - [Flame graph][] is the main visualization for profiling. - [Canvas][] allows you to explicitly place elements within static and dynamic layouts. - [Geomap][] helps you visualize geospatial data. + - [Datagrid][] allows you to create and manipulate data, and act as data source for other panels. - Widgets - [Dashboard list][] can list dashboards. - [Alert list][] can list alerts. + - [Annotations list][] can list available annotations. - [Text][] can show markdown and html. - [News][] can show RSS feeds. @@ -59,7 +62,7 @@ The following video shows you how to create gauge, time series line graph, stats ## Get more -You can add more visualization types by installing panel [panel plugins](https://grafana.com/grafana/plugins/?type=panel). +You can add more visualization types by installing [panel plugins](https://grafana.com/grafana/plugins/?type=panel). ## Examples @@ -183,5 +186,14 @@ A state timeline shows discrete state changes over time. When used with time ser [Table]: "/docs/grafana-cloud/ -> /docs/grafana//panels-visualizations/visualizations/table" [Time series]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/time-series" -[Time series]: "/docs/grafana-cloud/ -> /docs/grafana//panels-visualizations/visualizations/time-series" +[Time series]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/time-series" + +[Trend]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/trend" +[Trend]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/trend" + +[Annotations list]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/annotations" +[Annotations list]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/annotations" + +[Datagrid]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/datagrid" +[Datagrid]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/datagrid" {{% /docs/reference %}} From 8358e3db2215c105f5b9766ea2202dc44276dd2a Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 10:53:26 +0200 Subject: [PATCH 128/138] [v10.4.x] Alerting docs: update `disable_provenance` TF mute_timing (#85713) Alerting docs: update `disable_provenance` TF mute_timing (#85692) (cherry picked from commit d7ad7c6169130629b995b8169f23907ae23132b4) Co-authored-by: Pepe Cano <825430+ppcano@users.noreply.github.com> --- .../terraform-provisioning/index.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/sources/alerting/set-up/provision-alerting-resources/terraform-provisioning/index.md b/docs/sources/alerting/set-up/provision-alerting-resources/terraform-provisioning/index.md index 78f7d1e3704c..716d84e14273 100644 --- a/docs/sources/alerting/set-up/provision-alerting-resources/terraform-provisioning/index.md +++ b/docs/sources/alerting/set-up/provision-alerting-resources/terraform-provisioning/index.md @@ -340,8 +340,6 @@ resource "grafana_message_template" "my_template" { ... ``` -Note that `disable_provenance` is not supported for [grafana_mute_timing](https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/mute_timing). - ## Provision Grafana resources with Terraform To create the previous alerting resources in Grafana with the Terraform CLI, complete the following steps. From 125ec4bdbb36c69d43d52f50e7da8e5ceccc8357 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 11:36:55 -0400 Subject: [PATCH 129/138] =?UTF-8?q?[v10.4.x]=20Docs:=20What=E2=80=99s=20ne?= =?UTF-8?q?w=20&=20Upgrade=20guide=20&=20Breaking=20changes=20v11.0-previe?= =?UTF-8?q?w=20(#85699)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Docs: What’s new & Upgrade guide & Breaking changes v11.0-preview (#84603) * Updated index pages and added 11.0 breaking changes, upgrade guide, and what's new pages * Removed references to 10.4 * Added draft breaking changes * docs: grafana11-upgrade: postgres (#84671) * docs: grafana11-upgrade: postgres * fix typos Co-authored-by: Sriram <153843+yesoreyeram@users.noreply.github.com> * improved text Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> * improved text Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> * improved text --------- Co-authored-by: Sriram <153843+yesoreyeram@users.noreply.github.com> Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> * Added internal note * Added what's new items * Added more breaking changes' * Copy edits * Revert "docs: grafana11-upgrade: postgres" (#85580) Revert "docs: grafana11-upgrade: postgres (#84671)" This reverts commit d766d734c2d152a89caf0a8742689a59a2620231. * Removed internal link and moved PR link * Added new entries * Made fixes * Updated name * Copy edits * Fixed links and minor copy edits * Removed link to Cloud What's new * Added OSS what's new link * Fixed spelling of GitHub * Added Explore Logs and updated Explore Metrics --------- Co-authored-by: Gábor Farkas Co-authored-by: Sriram <153843+yesoreyeram@users.noreply.github.com> (cherry picked from commit fb1afa0c347be9071f4c9b1934ff229619338ced) * Update docs/sources/_index.md * Update docs/sources/_index.md * Update docs/sources/_index.md * Wording fixes --------- Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --- .../breaking-changes-v11-0.md | 220 ++++++++++ .../upgrade-guide/upgrade-v11.0/index.md | 23 ++ docs/sources/whatsnew/_index.md | 4 + docs/sources/whatsnew/whats-new-in-v11-0.md | 381 ++++++++++++++++++ 4 files changed, 628 insertions(+) create mode 100644 docs/sources/breaking-changes/breaking-changes-v11-0.md create mode 100644 docs/sources/upgrade-guide/upgrade-v11.0/index.md create mode 100644 docs/sources/whatsnew/whats-new-in-v11-0.md diff --git a/docs/sources/breaking-changes/breaking-changes-v11-0.md b/docs/sources/breaking-changes/breaking-changes-v11-0.md new file mode 100644 index 000000000000..8122ac01c32e --- /dev/null +++ b/docs/sources/breaking-changes/breaking-changes-v11-0.md @@ -0,0 +1,220 @@ +--- +description: Breaking changes for Grafana v11.0-preview +keywords: + - grafana + - breaking changes + - documentation + - '11.0' + - '11.0-preview' + - release notes +labels: + products: + - cloud + - enterprise + - oss +title: Breaking changes in Grafana v11.0-preview +weight: -3 +--- + + + + +# Breaking changes in Grafana v11.0-preview + +Following are breaking changes that you should be aware of when upgrading to Grafana v11.0-preview. + +For our purposes, a breaking change is any change that requires users or operators to do something. This includes: + +- Changes in one part of the system that could cause other components to fail +- Deprecations or removal of a feature +- Changes to an API that could break automation +- Changes that affect some plugins or functions of Grafana +- Migrations that can’t be rolled back + +For each change, the provided information: + +- Helps you determine if you’re affected +- Describes the change or relevant background information +- Guides you in how to mitigate for the change or migrate +- Provides more learning resources + +For release highlights and deprecations, refer to our [v11.0-preview What’s new](https://grafana.com/docs/grafana//whatsnew/whats-new-in-v11-0/). For the specific steps we recommend when you upgrade to v11.0, check out our [Upgrade guide](https://grafana.com/docs/grafana//upgrade-guide/upgrade-v11.0/). + + + + + +## Users and Operators + +### AngularJS support is turned off by default + +#### Description + +In Grafana v11, support for the deprecated AngularJS framework is turned off by default for all self-managed (on-premise) and Cloud instances of Grafana. This prevents any data source or panel visualization which relies on AngularJS from being loaded, and therefore has the potential to significantly disrupt your dashboards. Support will be fully removed in the next major release of Grafana. + +#### Migration/mitigation + +To avoid disruption, ensure all plugins are up to date and migrate from any remaining AngularJS plugins to a React-based alternative. If a plugin relies on AngularJS, a warning icon and message will be displayed in the [plugins catalog](https://grafana.com/docs/grafana//administration/plugin-management/#plugin-catalog) in Grafana and any dashboard panel where it's used. Additionally, a warning banner will appear in any impacted dashboards. A list of all impacted dashboards can also be generated using the [`detect-angular-dashboards`](https://github.com/grafana/detect-angular-dashboards) tool. + +Our [documentation](https://grafana.com/docs/grafana//developers/angular_deprecation/angular-plugins/) lists all known public plugins and provides migration advice when possible. + +For self-managed users of Grafana and existing Grafana Cloud instances, you can temporarily re-enable support through the [configuration parameter](https://grafana.com/docs/grafana//setup-grafana/configure-grafana/#angular_support_enabled), `angular_support_enabled=false`. However, AngularJS-based plugins will not receive any further updates and we strongly recommend migration as soon as possible. This configuration parameter will also be removed in the next major release after Grafana v11. + +New Grafana Cloud users will be unable to request that support be added to their instance. + +#### Learn more + +Refer to this [blog post](https://grafana.com/blog/2024/03/11/removal-of-angularjs-support-in-grafana-what-you-need-to-know/) for more information. + +### Grafana Enterprise: Anonymous devices are billed as users + +#### Description + +Effective starting in Grafana v11, anonymous users are counted and charged as users in Grafana Enterprise. When you upgrade to v11, anonymous users will be automatically counted as active users against your Grafana Enterprise license. + +#### Migration/mitigation + +Turn off anonymous access, and consider using public dashboards to allow view-only access to publicly-accessible dashboards. + +#### Learn more + +[Anonymous access documentation](https://grafana.com/docs/grafana//setup-grafana/configure-security/configure-authentication/grafana/#anonymous-authentication) + +### Legacy alerting is entirely removed + +Legacy alerting has reached its end-of-life. In Grafana v11 you can no longer enable legacy alerting, and Grafana will fail to start if the settings are not updated to run the new Grafana Alerting. This also means that starting in Grafana v11, it is no longer possible to migrate from legacy alerting to our new alerting. Grafana v10.4.x is the last version that offers migration, so make sure to migrate to the new Grafana Alerting system _before_ upgrading to Grafana v11. Learn more about Grafana Alerting and the advantages of the new system in the [legacy alerting deprecation documentation](https://grafana.com/docs/grafana/v10.4/alerting/set-up/migrating-alerts/legacy-alerting-deprecation/). Learn more about migration in the [upgrade alerting documentation](https://grafana.com/docs/grafana/v10.4/alerting/set-up/migrating-alerts/). + +For more details on the code removal, review the following PRs: + +- [https://github.com/grafana/grafana/pull/83651](https://github.com/grafana/grafana/pull/83651) +- [https://github.com/grafana/grafana/issues/81268](https://github.com/grafana/grafana/issues/81268) + +### Deprecated endpoints and fields in Reporting removed + +#### Description + +In Grafana v11, support for deprecated endpoints and fields in **Reporting** related to the old scheduling format, email, and dashboard is fully removed. This prevents any calls to deprecated endpoints and passing in values to deprecated fields. This feature only affects Cloud and Enterprise customers who use the API to generate reports. + +#### Migration/mitigation + +Ensure deprecated endpoints are updated to new corresponding endpoints and deprecated fields are removed and replaced with new corresponding fields. + +#### Learn more + +The [Reporting documentation](https://grafana.com/docs/grafana//developers/http_api/reporting/) lists all supported endpoints and fields. + +### Change custom branding public dashboard footer behavior + +#### Description + +In Grafana v11, custom branding public dashboard footer behavior is changed to default to the Grafana logo if no footer logo or footer text is set. There is no option to hide the public dashboard footer anymore. This feature only affects Cloud Advanced and Enterprise customers. + +#### Migration/mitigation + +Ensure you have a public dashboard footer logo or footer text set if you don't want to display the default Grafana footer. + +#### Learn more + +[Configure custom branding documentation](https://grafana.com/docs/grafana//setup-grafana/configure-grafana/configure-custom-branding/#custom-branding-for-public-dashboards) for public dashboards + +### Subfolders cause very rare issues with folders that have forward slashes in their names + +#### Description and migration/mitigation + +The upgrade to enable subfolders can cause some issues with alerts in certain cases. If you've previously set up a folder that uses a forward slash in its name, you have an alert rule in that folder, and the notification policy is set to match that folder's name, notifications will be sent to the default receiver instead of the configured receiver. + +In these cases, we recommend that you take these steps before the upgrade to enable subfolders: + +- Create a copy of the affected routes and rewrite the matchers for the new copy. For example, if the original matcher was `grafana_folder=MyFolder/sub-folder`, then the new route matcher will be `grafana_folder=MyFolder\/sub-folder`. +- After enabling subfolders, you can delete the old routes. + +Please note that if you use file provisioning, you can upgrade and update the routes at the same time. + +#### Learn more + +[Subfolders announcement](https://grafana.com/docs/grafana//whatsnew/whats-new-in-v11-0/#subfolders) + +[Provisioning: Provision dashboards into subfolders PR](https://github.com/grafana/grafana/pull/79793) + +### The Input data source is removed + +The direct input data source plugin has been removed in Grafana v11. It has been in alpha for four years and is superseded by [TestData](https://grafana.com/docs/grafana//datasources/testdata/), which ships with Grafana. This is a small deprecation. + +Review [this PR](https://github.com/grafana/grafana/pull/83163) for details. + +### Data sources: Query filtering changes + +The **Disable query** button in the query editor row has caused a lot of confusion among data source developers and end-users. Until now, it has been up to data source developers to filter out any hidden queries before or after they’re executed. Starting from Grafana v11, the tooltip of this button is changed from **Disable query** to **Hide response/Show response**. Responses that are associated with hidden queries will be removed by Grafana before they’re passed to the panel. + +Users of data source plugins that didn't previously remove hidden queries (before or after they were executed) will see a change of behavior as, previously, clicking the **Disable query** button had no impact on the query result. Starting from Grafana v11, responses associated with hidden queries are longer returned to the panel. + +We’re also moving the call to the `datasource.filterQuery` method to the query runner. This means that frontend-only data sources (or any data source that doesn't extend `DataSourceWithBackend` class) can implement this method. This streamlines data source plugin behavior, ensuring filtering works in the same way for all kinds of data source plugins. + +#### Migration/mitigation + +If data is missing in panels, make sure the query editor **Hide response** button is not clicked. + +#### Learn more + +[GitHub PR](https://github.com/grafana/grafana/pull/84656) + +### Chore: Query oauth info from a new instance + +We've added a validation between the response of the ID token HD parameter and the list of allowed domains as an extra layer of security. In the event that the HD parameter doesn't match the list of allowed domains, we're denying access to Grafana. + +If you set Google OAuth configuration using `api_url,` you might be using the legacy implementation of OAuth, which doesn't have the HD parameter describing the organization from which the approved token comes. This could break your login flow. + +You can turn off this feature through the configuration toggle `validate_hd `. Anyone using the legacy Google OAuth configuration should turn off this validation if the ID Token response doesn't have the HD parameter. + +[GitHub PR](https://github.com/grafana/grafana/pull/83229) + +### Changes to how the panel view URL is generated for repeated panels + +#### Description + +With the introduction of the Scenes library to dashboards, the URL that’s generated when viewing an individual repeated panel has changed. We’ve changed how these panels are referenced and what used to be `&viewPanel=panel-5` is now `&viewPanel=panel-3-clone1`. + +This means that the previous URLs won’t work anymore and instead you'll be redirected to the dashboard view and you'll get a _Panel not found_ error. From this point on, the dashboard will continue to work as expected. + +#### Migration/mitigation + +Reopen the panel in view mode and you'll get the new URL. + +## Plugin developers + +### React Router is deprecated + +#### Description + +In Grafana v11 we're marking react-router v5 as deprecated. App plugins should start migrating to use react-router v6. + +#### Migration/mitigation + +For a complete guide, please follow our [migration docs on the developer portal](https://grafana.com/developers/plugin-tools/migration-guides/update-from-grafana-versions/migrate-9_x-to-10_x#update-to-react-router-v6). + +#### Learn more + +- Grafana v9.x to v10.x [migration guide](https://grafana.com/developers/plugin-tools/migration-guides/update-from-grafana-versions/migrate-9_x-to-10_x#update-to-react-router-v6) +- Official react-router v5 to v6 [migration guide](https://reactrouter.com/en/main/upgrading/v5) +- Grafana community forum [topic](https://community.grafana.com/t/migrating-app-plugins-to-use-react-router-v6/115410) + +### Chore: Taint ArrayVector with `never` to further discourage + +[GitHub PR](https://github.com/grafana/grafana/pull/83681) + +The Vector interface that was deprecated in Grafana v10 is further deprecated. Using it now generates build-time Typescript errors, but it remains working at runtime. If you're still using ArrayVector in your code, you should remove it immediately and replace it with plain arrays. Plugins that are compiled against older versions and depend on calling get/set will continue to work because the Array prototype still has a modified prototype. This will be removed in the future. + +### Chore: Remove React 17 peer deps + +[GitHub PR](https://github.com/grafana/grafana/pull/83524) + +We've removed React 17 as a peer dependency from our packages. Anyone using the new versions of these packages should ensure they've upgraded to React 18 following [the upgrade steps](https://react.dev/blog/2022/03/08/react-18-upgrade-guide). + +### Chore: Remove SystemJS from Grafana/Runtime + +[GitHub PR](https://github.com/grafana/grafana/pull/84561) + +SystemJS is no longer exported from `@grafana/runtime`. Plugin developers should instead rely on importing modules/packages using standard TS import syntax and npm/yarn for package installation. diff --git a/docs/sources/upgrade-guide/upgrade-v11.0/index.md b/docs/sources/upgrade-guide/upgrade-v11.0/index.md new file mode 100644 index 000000000000..068171c30035 --- /dev/null +++ b/docs/sources/upgrade-guide/upgrade-v11.0/index.md @@ -0,0 +1,23 @@ +--- +description: Guide for upgrading to Grafana v11.0-preview +keywords: + - grafana + - configuration + - documentation + - upgrade + - '11.0' + - '11.0-preview' +title: Upgrade to Grafana v11.0-preview +menuTitle: Upgrade to v11.0 +weight: 1200 +--- + +# Upgrade to Grafana v11.0-preview + +{{< docs/shared lookup="upgrade/intro.md" source="grafana" version="" >}} + +{{< docs/shared lookup="back-up/back-up-grafana.md" source="grafana" version="" leveloffset="+1" >}} + +{{< docs/shared lookup="upgrade/upgrade-common-tasks.md" source="grafana" version="" >}} + +## Technical notes diff --git a/docs/sources/whatsnew/_index.md b/docs/sources/whatsnew/_index.md index 5e7be79bb36d..db2bdc6294c0 100644 --- a/docs/sources/whatsnew/_index.md +++ b/docs/sources/whatsnew/_index.md @@ -74,6 +74,10 @@ For Grafana versions prior to v9.2, additional information might also be availab For a complete list of every change, with links to pull requests and related issues when available, see the [Changelog](https://github.com/grafana/grafana/blob/main/CHANGELOG.md). +# Grafana 11 + +- [What's new in 11.0-preview](https://grafana.com/docs/grafana//whatsnew/whats-new-in-v11-0/) + ## Grafana 10 - [What's new in 10.4](https://grafana.com/docs/grafana//whatsnew/whats-new-in-v10-4/) diff --git a/docs/sources/whatsnew/whats-new-in-v11-0.md b/docs/sources/whatsnew/whats-new-in-v11-0.md new file mode 100644 index 000000000000..72f4a0127eb1 --- /dev/null +++ b/docs/sources/whatsnew/whats-new-in-v11-0.md @@ -0,0 +1,381 @@ +--- +description: Feature and improvement highlights for Grafana v11.0-preview +keywords: + - grafana + - new + - documentation + - '11.0' + - '11.0-preview' + - release notes +labels: +products: + - cloud + - enterprise + - oss +title: What's new in Grafana v11.0-preview +weight: -42 +--- + + + + +# What’s new in Grafana v11.0-preview + +Welcome to Grafana 11.0-preview! This preview release contains several improvements, most notably, the ability to explore your metrics and logs without queries. We've taken strides to improve the dashboard experience with subfolders becoming generally available and the addition of enhanced flowcharting capabilities. We've also migrated the dashboard viewing experience so that it's using our Scenes library. + +For even more detail about all the changes in this release, refer to the [changelog](https://github.com/grafana/grafana/blob/main/CHANGELOG.md). For the specific steps we recommend when you upgrade to v11.0-preview, check out our [Upgrade Guide](https://grafana.com/docs/grafana//upgrade-guide/upgrade-v11.0/). + +## Breaking changes + +For Grafana v11.0-preview, we've also provided a list of [breaking changes](https://grafana.com/docs/grafana//breaking-changes/breaking-changes-v11-0) to help you upgrade with greater confidence. For information about these along with guidance on how to proceed, refer to [Breaking changes in Grafana v11.0-preview](https://grafana.com/docs/grafana//breaking-changes/breaking-changes-v11-0/). + + + + + + + +## Dashboards and visualizations + +### Scenes for viewers + + + +_Generally available in all editions of Grafana_ + +Dashboards, when accessed by users with the Viewer role, are now using the Scenes library. Those users shouldn't see any difference in the dashboards apart from two small changes to the user interface (UI): the variables UI has slightly changed and the time picker is now part of the dashboard container. + +Dashboards aren't affected for users in other roles. + +This is the first step towards a more robust and dynamic dashboarding system that we'll be releasing in the upcoming months. + +### Scenes powered Dashboards + + + +_Available in public preview in all editions of Grafana_ + +For the past few months we've been working on a major update of our **Dashboards** architecture and migrated it to the Scenes library. This migration provides us with more stable, dynamic, and flexible dashboards as well as setting the foundation for what we envision the future of Grafana dashboards will be. Here are two of the improvements that are being introduced as part of this work. + +#### Edit mode + +It can be difficult to efficiently navigate through the visually cluttered options during the dashboard editing process. With the introduction of the edit mode, we aim to provide an easier way to discover and interact with the dashboard edit experience. + +#### Fixed positioning of template variables and time picker + +We moved the time picker into the dashboard canvas and now, together with template variables, it will stick to the top as you scroll through your dashboard. This has historically been a very [requested feature](https://github.com/grafana/grafana/issues/11166) that we're very happy to be able to finally roll out! + +#### Known limitations + +- The [variable dependency graph](https://grafana.com/docs/grafana//dashboards/variables/inspect-variable/) is not yet available. +- It's no longer possible to switch a regular panel to a library panel from the edit view. + +If you want to learn more, in detail, about all the improvements we've made, don't miss our blog post. + +### Subfolders + + + +_Generally available in all editions of Grafana_ + +Subfolders are here at last! + +Some of you want subfolders in order to keep things tidier. It’s easy for dashboard sprawl to get out of control, and setting up folders in a nested hierarchy helps with that. + +Others of you want subfolders in order to create nested layers of permissions, where teams have access at different levels that reflect their organization’s hierarchy. + +We are thrilled to bring this long-awaited functionality to our community of users! Subfolders are currently being rolled out to Grafana Cloud instances and will be generally available to all Grafana users for the Grafana 11 release. + +**Just a quick note**: the upgrade to enable subfolders can cause some issues with alerts in certain cases. We think these cases are pretty rare, but just in case, you’ll want to check for this: + +If you've previously set up a folder that uses a forward slash in its name, and you have an alert rule in that folder, and the notification policy is set to match that folder's name, notifications will be sent to the default receiver instead of the configured receiver. + +To correct this, take the following steps: + +- Create a copy of the affected routes +- Rewrite the matchers for the new copy. For example, if the original matcher was `grafanafolder=folder_with/in_title`, then the new route matcher will be `grafana_folder=folder_with/_in_title` +- After rewriting the matchers, you can delete the old routes. + +If you use file provisioning, you can upgrade and update the routes at the same time. + +### Use AI to generate titles and descriptions for panels and dashboards + + + +_Generally available in all editions of Grafana_ + +You can now use generative AI to assist you in your Grafana dashboards. So far generative AI can help you generate **panel and dashboard titles and descriptions** - You can now generate a title and description for your panel or dashboard based on the data you've added to it. This is useful when you want to quickly visualize your data and don't want to spend time coming up with a title or description. + +Make sure to enable and configure Grafana's LLM app plugin. For more information, refer to the [Grafana LLM app plugin documentation](https://grafana.com/docs/grafana-cloud/alerting-and-irm/machine-learning/llm-plugin/). + +When enabled, look for the **✨ Auto generate** option next to the **Title** and **Description** fields in your panels and dashboards, or when you press the **Save** button. + +![Auto-generate a panel description using AI](/media/docs/grafana/dashboards/auto-generate-description-10-2.gif) + +### Substring matcher added to the filter by value transformation + + + +_Generally available in Grafana Cloud and Open Source_ + +This update to the **Filter data by values** transformation simplifies data filtering by enabling partial string matching on field values thanks to two new matchers: **Contains substring** and **Does not contain substring**. With the substring matcher built into the **Filter data by values** transformation, you can efficiently filter large datasets, displaying relevant information with speed and precision. Whether you're searching for keywords, product names, or user IDs, this feature streamlines the process, saving time and effort while ensuring accurate data output. + +In the **Filter data by values** transformation, simply add a condition, choose a field, choose your matcher, and then input the string to match against. + +This update will be rolled out to customers over the next few weeks. + +{{< video-embed src="/media/docs/grafana/substring-matcher.mp4" >}} + +### Improvements to the canvas visualization + + + +_Generally available in all editions of Grafana_ + +We've made a number of improvements to the canvas visualization. + +#### Enhanced flowcharting functionality + +With this release, we've updated the canvas visualization to include much-requested flowcharting features. These improvements are: + +- Addition of widely-used elements: cloud, parallelogram, and triangle. +- Addition of midpoint controls so that the connectors no longer have to be straight lines. +- Addition of more connector styles including dashed lines as well as corner radius and direction control. +- Horizontal and vertical snapping for connectors. +- Addition of rounded corner styling for elements. +- Ability to rotate elements in the canvas. + +#### Universal data link support + +We've updated data links so that you can add them to almost all elements or element properties that are tied to data. Previously, you could only add data links to text elements or elements that used the `TextConfig` object. This update removes that limitation. + +{{< admonition type="note" >}} +This update doesn't apply to the drone and button elements. +{{< /admonition >}} + +[Documentation](https://grafana.com/docs/grafana//panels-visualizations/visualizations/canvas/) + +### Infinite panning for the canvas visualization + + + +_Available in public preview in all editions of Grafana_ + +With the newly added **Infinite panning** editor option, you can now view and navigate very large canvases. This option is displayed when the **Pan and zoom** switch is enabled. + +To try out this feature, you must first enable the `canvasPanelPanZoom` feature toggle. + +[Documentation](https://grafana.com/docs/grafana//panels-visualizations/visualizations/canvas/) + +### Colored table rows with conditional formatting + + + +_Generally available in all editions of Grafana_ + +Grafana 11 adds the ability to color full table rows using the **Colored background** cell type of the table visualization. When you configure fields in a table to use this cell type, an option to apply the color of the cell to the entire row becomes available. + +{{< figure src="/static/img/docs/tables/colored-rows.png" max-width="500px" alt="Colored row background" class="docs-image--no-shadow" >}} + +This feature is useful for a wide variety of use cases including mapping status fields to colors (for example, `info`, `debug`, `warning`) and allowing rows to be colored based on threshold values. This is one of the first steps in making formatting tables more seamless, and allows for quick scanning of data using the table visualization. + +To learn more, refer to the [documentation for the Colored background cell type](https://grafana.com/docs/grafana//panels-visualizations/visualizations/table/#color-background-gradient-or-solid). + +### Set threshold colors in the Config from query transformation + + + +_Generally available in all editions of Grafana_ + +You now have the ability to customize specific colors for individual thresholds when using the **Config from query results** transformer. Previously, when you added multiple thresholds, they all defaulted to the same color, red. With this addition, you gain the flexibility to assign distinct colors to each threshold. + +This feature addresses a common pain point highlighted by users. With customizable threshold colors, you now have greater control over your data representation, fostering more insightful and impactful analyses across diverse datasets. + +## Reporting + +### PDF export improvements + + + +_Available in public preview in Grafana Cloud and Enterprise_ + +Introducing a major performance improvement for the PDF export feature. + +Are you tired of waiting for your PDF to be generated or your report to be sent? We're working on a major update of the dashboard-to-PDF feature to make it faster for large dashboards. The generation time will no longer be proportional to the number of panels in your dashboard. As an example, an SLO dashboard containing around 200 panels has gone from taking more than seven minutes to be generated to only eleven seconds. + +This update also fixes all [caveats](https://grafana.com/docs/grafana//dashboards/create-reports/#caveats) related to rendering a report with panels or rows set to repeat by a variable, like rendering repeating panels inside collapsed rows. + +To try out this update, enable the `newPDFRendering` [feature toggle](https://grafana.com/docs/grafana//setup-grafana/configure-grafana/feature-toggles/). + +## Alerting + +### Keep Last State for Grafana Managed Alerting + + + +_Generally available in all editions of Grafana_ + +(Re-)introducing "Keep Last State" to Grafana managed alert rules. + +You can now choose to keep the last evaluated state of an alert rule when that rule produces "No Data" or "Error" results. Simply choose the "Keep Last State" option for no data or error handling when editing a rule. Refer to the Alerting documentation on state and health of alert rules for more information.[](https://grafana.com/docs/grafana//alerting/fundamentals/alert-rules/state-and-health/#state-and-health-of-alert-rules) + +### Alert detail view redesign + + + +_Generally available in all editions of Grafana_ + +The new alert rule detail view has a new look and feel with helpful metadata at the top. The namespace and group are shown in the breadcrumb navigation. This is interactive and can be used to filter rules by namespace or group. The rest of the alert detail content is split up into tabs: + +**Query and conditions** + +View the details of the query that is used for the alert rule, including the expressions and intermediate values for each step of the expression pipeline. A graph view is included for range queries and data sources that return time series-like data frames. + +**Instances** + +Explore each alert instance, its status, labels and various other metadata for multi-dimensional alert rules. + +**History** + +Explore the recorded history for an alert rule. + +**Details** + +Debug or audit using the alert rule metadata and view the alert rule annotations. + +![Image shows details of an alert rule](/media/docs/alerting/alert-detail-view.png) + +## Data sources + +### Explore Metrics + + + +_Generally available in all editions of Grafana_ + +Explore Metrics is a query-less experience for browsing Prometheus-compatible metrics. Search for or filter to find a metric. Quickly find related metrics - all in just a few clicks. No PromQL to be found anywhere! With Explore Metrics, you can: + +- easily slice and dice metrics based on their labels, so you can see anomalies right away +- See the right visualization for your metric based on its type (e.g. gauge vs. counter) without writing it yourself +- surface other metrics relevant to the current metric +- “explore in a drawer” - expand a drawer over a dashboard with more content, so you don’t lose your place +- view a history of user steps when navigating through metrics and their filters +- easily pivot to other related telemetry - IE, logs or traces + +… all without writing any queries! + + + +### Explore Logs + + + +_Experimental in Grafana Open Source and Enterprise_ + +Explore Logs is a queryless experience for exploring Loki logs - no LogQL required! The primary interaction modes are point-and-click based on log volume, similar to Explore Metrics. + +Highlights: + +- View log volume and log line samples when you first land in Explore Logs (no more "blank screen!") +- Explore additional labels and detected fields in a similar way, focusing on volume and distribution; add them to your "query" to refine your logs search without needing LogQL + – See common patterns in your log lines, to easily filter out noise or focus in on anomalies +- For power users, an easy way to hop into the familiar Explore while preserving context + +Explore Logs is Open Source, and in preview - some papercuts are to be expected. Give it a try and let us know what you think! + +### Azure Monitor: Current User authentication + + + +_Experimental in all editions of Grafana_ + +You can now configure the Azure Monitor data source to authenticate as the logged-in Grafana user when making query and resource requests if you also use Azure Entra to sign your users into Grafana. + +Current User authentication allows you to enforce Azure RBAC restrictions on your Grafana users by removing the need to provide broad service credentials. Once a data source is configured with Current User authentication a user will **only** have access to resources they can access directly in Azure. + +Additionally, data sources configured to use Current User authentication are less likely to be impacted by throttling issues due to the individual level of access. + +Current User authentication does not inherently support backend features such as alerting. To account for this, data sources configured with Current User authentication can optionally specify service credentials that will be utilized for backend features when no signed-in user is available. + +To get started with Current User authentication, refer to the [Azure Monitor data source documentation](https://grafana.com/docs/grafana//datasources/azure-monitor/#configure-current-user-authentication). + +{{< figure src="/media/docs/grafana/data-sources/screenshot-current-user.png" alt="Data source configured with Current User authentication" >}} + +### Removal of old Tempo Search and Loki Search in Tempo + + + +_Generally available in all editions of Grafana_ + +#### Removal of old Tempo Search tab + +In Grafana v10.1, we added a Tempo search editor powered by TraceQL (search tab). We also recommended using this new editor over the older non-TraceQL powered editor. + +The older non-TraceQL powered editor has been removed. Any existing queries using the older editor will be automatically migrated to the new TraceQL-powered editor. + +The new TraceQL-powered editor makes it much easier to build your query by way of static filters, better input/selection validation, copy query to the TraceQL tab, query preview, dedicated status filter, and the ability to run aggregate by (metrics summary) queries. + +Refer to [Query tracing data](https://grafana.com/docs/grafana//datasources/tempo/query-editor/) to learn more. + +#### Removal of Loki Search tab in Tempo + +The Loki Search tab has been around since before we could natively query Tempo for traces. +This search is used by a low number of users in comparison to the TraceQL-powered editor (Search tab) or the TraceQL tab itself. + +If you would like to see what logs are linked to a specific trace or service, you can use the [Trace to logs feature](https://grafana.com/docs/grafana//datasources/tempo/configure-tempo-data-source/#trace-to-logs), which provides an easy way to create a custom link and set an appropriate time range if necessary. + +### MSSQL: Windows Active Directory (Kerberos) authentication + + + +_Generally available in Grafana Open Source and Enterprise_ + +You can now use Windows Active Directory (or Kerberos) to authenticate to MSSQL servers from Grafana. + +There are four primary ways to authenticate from Grafana to a MSSQL instance with Windows Active Directory: + +1. Windows Active Directory username and password +1. Specify the path to a valid [keytab file](https://web.mit.edu/kerberos/krb5-1.12/doc/basic/keytab_def.html). +1. Specify the path to an up to date [credential cache](https://web.mit.edu/kerberos/krb5-1.12/doc/basic/ccache_def.html). +1. Specify the path to a JSON document that holds information about several credential caches and the user and database for each one. + +To get started, refer to the [Getting Started documentation for MSSQL](https://grafana.com/docs/grafana//getting-started/get-started-grafana-ms-sql-server/#windows-active-directory-kerberos). + +## Authentication and authorization + +### New strong password policy + + + +_Available in public preview in Grafana Open Source and Enterprise_ + +If you manage your users using Grafana's built-in basic authorization as an identity provider, consider enabling our new strong password policy feature. + +Starting with Grafana v11.0, you can enable an opinionated strong password policy feature. This configuration option validates all password updates to comply with our strong password policy. + +To learn more about Grafana's strong password policy, refer to the [documentation](https://grafana.com/docs/grafana//setup-grafana/configure-security/configure-authentication/grafana/#strong-password-policy). + +### Anonymous users are billed in Grafana Enterprise + + + +_Generally available in Grafana Enterprise_ + +We are announcing a license change to the anonymous access feature in Grafana 11. As you may already be aware, anonymous access allows users access to Grafana without login credentials. Anonymous access was an early feature of Grafana to share dashboards; however, we recently introduced [Public Dashboards](https://grafana.com/docs/grafana//dashboards/dashboard-public/) which allows you to share dashboards in a more secure manner. We also noticed that anonymous access inadvertently resulted in user licensing issues. After careful consideration, we have decided to charge for the continued use of anonymous access starting in Grafana 11. + +**Affected Grafana versions** + +[Anonymous authentication](https://grafana.com/docs/grafana//setup-grafana/configure-security/configure-authentication/grafana/#anonymous-authentication) is disabled by default in Grafana Cloud. This licensing change only affects Grafana Enterprise (self-managed) edition. Anonymous users will be charged as active users in Grafana Enterprise. + +[Documentation](https://grafana.com/docs/grafana//setup-grafana/configure-security/configure-authentication/grafana/#anonymous-devices) From f7070df4d34e2f6564ce9fc6323982255d01cf5a Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 17:44:10 +0200 Subject: [PATCH 130/138] [v10.4.x] Alerting docs: add `Template variable interpolation` section in file provisioning (#85745) Alerting docs: add `Template variable interpolation` section in file provisioning (#84106) * Alerting docs: add `Template variable interpolation` section in file provisioning * Update docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> * Update docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md Co-authored-by: Matthew Jacobson --------- Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> Co-authored-by: Matthew Jacobson (cherry picked from commit 0672bdf397b68cf81bb9e1f4e2265b05a828b769) Co-authored-by: Pepe Cano <825430+ppcano@users.noreply.github.com> --- .../file-provisioning/index.md | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md b/docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md index e5f2c33bb7c8..8986febb57c4 100644 --- a/docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md +++ b/docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md @@ -799,6 +799,40 @@ deleteMuteTimes: name: mti_1 ``` +## Template variable interpolation + +Provisioning interpolates environment variables using the `$variable` syntax. + +```yaml +contactPoints: + - orgId: 1 + name: My Contact Email Point + receivers: + - uid: 1 + type: email + settings: + addresses: $EMAIL +``` + +In this example, provisioning replaces `$EMAIL` with the value of the `EMAIL` environment variable or an empty string if it is not present. For more information, refer to [Using environment variables in the Provision documentation][provisioning_env_vars]. + +In alerting resources, most properties support template variable interpolation, with a few exceptions: + +- Alert rule annotations: `groups[].rules[].annotations` +- Alert rule time range: `groups[].rules[].relativeTimeRange` +- Alert rule query model: `groups[].rules[].data.model` +- Mute timings name: `muteTimes[].name` +- Mute timings time intervals: `muteTimes[].time_intervals[]` +- Notification template name: `templates[].name` +- Notification template content: `templates[].template` + +Note for properties that support interpolation, you may unexpectedly substitute template variables when not intended. To avoid this, you can escape the `$variable` with `$$variable`. + +For example, when provisioning a `subject` property in a `contactPoints.receivers.settings` object that is meant to use the `$labels` variable. + +1. `subject: '{{ $labels }}'` will interpolate, incorrectly defining the subject as `subject: '{{ }}'`. +1. `subject: '{{ $$labels }}'` will not interpolate, correctly defining the subject as `subject: '{{ $labels }}'`. + ## More examples For more examples on the concept of this guide: @@ -825,6 +859,7 @@ For more examples on the concept of this guide: [export_mute_timings]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/set-up/provision-alerting-resources/export-alerting-resources#export-mute-timings" [provisioning]: "/docs/ -> /docs/grafana//administration/provisioning" +[provisioning_env_vars]: "/docs/ -> /docs/grafana//administration/provisioning#using-environment-variables" [reload-provisioning-configurations]: "/docs/ -> /docs/grafana//developers/http_api/admin#reload-provisioning-configurations" From 46f63365c8461acb7f6f75dddfd561dd5af66aa0 Mon Sep 17 00:00:00 2001 From: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> Date: Mon, 8 Apr 2024 12:05:35 -0400 Subject: [PATCH 131/138] [v10.4.x] Docs: Re-order features and update intro in Grafana 11.0-preview What's new (#85749) * Docs: Re-order features and update intro in Grafana 11.0-preview What's new (#85702) * Re-order features and update intro in Grafana 11.0-preview What's new * Removed title casing --------- Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> (cherry picked from commit 3865b8c980a0e148c05fd8fb94bb47b0d5e632e1) * Removed old content kept in error --------- Co-authored-by: Mitch Seaman --- docs/sources/whatsnew/whats-new-in-v11-0.md | 120 ++++++++++---------- 1 file changed, 62 insertions(+), 58 deletions(-) diff --git a/docs/sources/whatsnew/whats-new-in-v11-0.md b/docs/sources/whatsnew/whats-new-in-v11-0.md index 72f4a0127eb1..b679ca3bc0b4 100644 --- a/docs/sources/whatsnew/whats-new-in-v11-0.md +++ b/docs/sources/whatsnew/whats-new-in-v11-0.md @@ -21,7 +21,9 @@ weight: -42 # What’s new in Grafana v11.0-preview -Welcome to Grafana 11.0-preview! This preview release contains several improvements, most notably, the ability to explore your metrics and logs without queries. We've taken strides to improve the dashboard experience with subfolders becoming generally available and the addition of enhanced flowcharting capabilities. We've also migrated the dashboard viewing experience so that it's using our Scenes library. +Welcome to Grafana 11.0-preview! This release contains some major improvements: most notably, the ability to explore your Prometheus metrics and loki logs without writing any PromQL or LogQL, using Explore Metrics and Explore Logs. The dashboard experience is better than ever with Edit mode for dashboards, AI-generated dashboard names and descriptions, and general availability for subfolders. You can also take advantage of improvements to the Canvas and Table panels, new Transformations, a revamp of the Alert Rule page, and more. + +Why "preview?" The Grafana 11.0 stable release is planned for this May. This is an early release to coincide with [Grafanacon 2024](https://grafana.com/about/events/grafanacon/2024/), so that you can try the new functionality early. To understand the differences between preview and GA releases, review the [release life cycle](https://grafana.com/docs/release-life-cycle/). For even more detail about all the changes in this release, refer to the [changelog](https://github.com/grafana/grafana/blob/main/CHANGELOG.md). For the specific steps we recommend when you upgrade to v11.0-preview, check out our [Upgrade Guide](https://grafana.com/docs/grafana//upgrade-guide/upgrade-v11.0/). @@ -46,19 +48,45 @@ Use full URLs for links. When linking to versioned docs, replace the version wit -## Dashboards and visualizations +## Explore Metrics and Logs -### Scenes for viewers +### Explore Metrics - + -_Generally available in all editions of Grafana_ +_Public preview in all editions of Grafana_ -Dashboards, when accessed by users with the Viewer role, are now using the Scenes library. Those users shouldn't see any difference in the dashboards apart from two small changes to the user interface (UI): the variables UI has slightly changed and the time picker is now part of the dashboard container. +Explore Metrics is a query-less experience for browsing Prometheus-compatible metrics. Search or filter to find a metric. Quickly find related metrics - all in just a few clicks. No PromQL to be found anywhere! With Explore Metrics, you can: -Dashboards aren't affected for users in other roles. +- easily slice and dice metrics based on their labels, so you can see anomalies right away +- See the right visualization for your metric based on its type (e.g. gauge vs. counter) without writing it yourself +- surface other metrics relevant to the current metric +- “explore in a drawer” - expand a drawer over a dashboard with more content, so you don’t lose your place +- view a history of user steps when navigating through metrics and their filters +- easily pivot to other related telemetry - IE, logs or traces -This is the first step towards a more robust and dynamic dashboarding system that we'll be releasing in the upcoming months. +… all without writing any queries! + + + +### Explore Logs + + + +_Experimental in Grafana Open Source and Enterprise_ + +Explore Logs is a queryless experience for exploring Loki logs - no LogQL required! The primary interaction modes are point-and-click based on log volume, similar to Explore Metrics. + +Highlights: + +- View log volume and log line samples when you first land in Explore Logs (no more "blank screen!") +- Explore additional labels and detected fields in a similar way, focusing on volume and distribution; add them to your "query" to refine your logs search without needing LogQL + – See common patterns in your log lines, to easily filter out noise or focus in on anomalies +- For power users, an easy way to hop into the familiar Explore while preserving context + +Explore Logs is Open Source, and experimental - some papercuts are to be expected. Give it a try and let us know what you think! + +## Dashboards and visualizations ### Scenes powered Dashboards @@ -83,6 +111,18 @@ We moved the time picker into the dashboard canvas and now, together with templa If you want to learn more, in detail, about all the improvements we've made, don't miss our blog post. +### Scenes for viewers + + + +_Generally available in all editions of Grafana_ + +Dashboards, when accessed by users with the Viewer role, are now using the Scenes library. Those users shouldn't see any difference in the dashboards apart from two small changes to the user interface (UI): the variables UI has slightly changed and the time picker is now part of the dashboard container. + +Dashboards aren't affected for users in other roles. + +This is the first step towards a more robust and dynamic dashboarding system that we'll be releasing in the upcoming months. + ### Subfolders @@ -123,20 +163,6 @@ When enabled, look for the **✨ Auto generate** option next to the **Title** an ![Auto-generate a panel description using AI](/media/docs/grafana/dashboards/auto-generate-description-10-2.gif) -### Substring matcher added to the filter by value transformation - - - -_Generally available in Grafana Cloud and Open Source_ - -This update to the **Filter data by values** transformation simplifies data filtering by enabling partial string matching on field values thanks to two new matchers: **Contains substring** and **Does not contain substring**. With the substring matcher built into the **Filter data by values** transformation, you can efficiently filter large datasets, displaying relevant information with speed and precision. Whether you're searching for keywords, product names, or user IDs, this feature streamlines the process, saving time and effort while ensuring accurate data output. - -In the **Filter data by values** transformation, simply add a condition, choose a field, choose your matcher, and then input the string to match against. - -This update will be rolled out to customers over the next few weeks. - -{{< video-embed src="/media/docs/grafana/substring-matcher.mp4" >}} - ### Improvements to the canvas visualization @@ -202,6 +228,20 @@ You now have the ability to customize specific colors for individual thresholds This feature addresses a common pain point highlighted by users. With customizable threshold colors, you now have greater control over your data representation, fostering more insightful and impactful analyses across diverse datasets. +### Substring matcher added to the Filter by value transformation + + + +_Generally available in Grafana Cloud and Open Source_ + +This update to the **Filter data by values** transformation simplifies data filtering by enabling partial string matching on field values thanks to two new matchers: **Contains substring** and **Does not contain substring**. With the substring matcher built into the **Filter data by values** transformation, you can efficiently filter large datasets, displaying relevant information with speed and precision. Whether you're searching for keywords, product names, or user IDs, this feature streamlines the process, saving time and effort while ensuring accurate data output. + +In the **Filter data by values** transformation, simply add a condition, choose a field, choose your matcher, and then input the string to match against. + +This update will be rolled out to customers over the next few weeks. + +{{< video-embed src="/media/docs/grafana/substring-matcher.mp4" >}} + ## Reporting ### PDF export improvements @@ -258,42 +298,6 @@ Debug or audit using the alert rule metadata and view the alert rule annotations ## Data sources -### Explore Metrics - - - -_Generally available in all editions of Grafana_ - -Explore Metrics is a query-less experience for browsing Prometheus-compatible metrics. Search for or filter to find a metric. Quickly find related metrics - all in just a few clicks. No PromQL to be found anywhere! With Explore Metrics, you can: - -- easily slice and dice metrics based on their labels, so you can see anomalies right away -- See the right visualization for your metric based on its type (e.g. gauge vs. counter) without writing it yourself -- surface other metrics relevant to the current metric -- “explore in a drawer” - expand a drawer over a dashboard with more content, so you don’t lose your place -- view a history of user steps when navigating through metrics and their filters -- easily pivot to other related telemetry - IE, logs or traces - -… all without writing any queries! - - - -### Explore Logs - - - -_Experimental in Grafana Open Source and Enterprise_ - -Explore Logs is a queryless experience for exploring Loki logs - no LogQL required! The primary interaction modes are point-and-click based on log volume, similar to Explore Metrics. - -Highlights: - -- View log volume and log line samples when you first land in Explore Logs (no more "blank screen!") -- Explore additional labels and detected fields in a similar way, focusing on volume and distribution; add them to your "query" to refine your logs search without needing LogQL - – See common patterns in your log lines, to easily filter out noise or focus in on anomalies -- For power users, an easy way to hop into the familiar Explore while preserving context - -Explore Logs is Open Source, and in preview - some papercuts are to be expected. Give it a try and let us know what you think! - ### Azure Monitor: Current User authentication From 2c9344abfc0b5465b1e06913ea2d13f323f7e8cc Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 12:20:38 -0400 Subject: [PATCH 132/138] [v10.4.x] Docs: add youtube links to g11 preview what's new (#85751) Docs: add youtube links to g11 preview what's new (#85738) * Added youtube links * Commented scenes video out (cherry picked from commit fe3b6d3c5eddd3fc11de07360baff33af41f751f) Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --- docs/sources/whatsnew/whats-new-in-v11-0.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/docs/sources/whatsnew/whats-new-in-v11-0.md b/docs/sources/whatsnew/whats-new-in-v11-0.md index b679ca3bc0b4..059861c7d7d1 100644 --- a/docs/sources/whatsnew/whats-new-in-v11-0.md +++ b/docs/sources/whatsnew/whats-new-in-v11-0.md @@ -67,7 +67,9 @@ Explore Metrics is a query-less experience for browsing Prometheus-compatible me … all without writing any queries! - +To learn more, refer to the following video demo: + +{{< youtube id="JbaPufQs5LY" >}} ### Explore Logs @@ -111,6 +113,8 @@ We moved the time picker into the dashboard canvas and now, together with templa If you want to learn more, in detail, about all the improvements we've made, don't miss our blog post. + + ### Scenes for viewers @@ -149,6 +153,8 @@ To correct this, take the following steps: If you use file provisioning, you can upgrade and update the routes at the same time. +{{< youtube id="R9mehA0EssU" >}} + ### Use AI to generate titles and descriptions for panels and dashboards @@ -163,6 +169,8 @@ When enabled, look for the **✨ Auto generate** option next to the **Title** an ![Auto-generate a panel description using AI](/media/docs/grafana/dashboards/auto-generate-description-10-2.gif) +{{< youtube id="s61WHREHuYE" >}} + ### Improvements to the canvas visualization @@ -190,6 +198,8 @@ We've updated data links so that you can add them to almost all elements or elem This update doesn't apply to the drone and button elements. {{< /admonition >}} +{{< youtube id="0iO2gqv0XNA" >}} + [Documentation](https://grafana.com/docs/grafana//panels-visualizations/visualizations/canvas/) ### Infinite panning for the canvas visualization @@ -218,6 +228,8 @@ This feature is useful for a wide variety of use cases including mapping status To learn more, refer to the [documentation for the Colored background cell type](https://grafana.com/docs/grafana//panels-visualizations/visualizations/table/#color-background-gradient-or-solid). +{{< youtube id="PLfADTtCnmg" >}} + ### Set threshold colors in the Config from query transformation @@ -258,6 +270,8 @@ This update also fixes all [caveats](https://grafana.com/docs/grafana//setup-grafana/configure-grafana/feature-toggles/). +{{< youtube id="ypk1usnE7D8" >}} + ## Alerting ### Keep Last State for Grafana Managed Alerting From 5591796ba860ec55cfb064e5ddb21af5a48b8a0d Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 21:28:45 +0300 Subject: [PATCH 133/138] [v10.4.x] PR to document Explore Metrics (previously datatrails) (#85760) PR to document Explore Metrics (previously datatrails) (#85212) * text dump * initial edits * more edits * added more info, made edits * first draft * removed some commented out content * final edits * made requested changes * feature name change * missed a metrics explore - fixed * ran prettier --------- Co-authored-by: lwandz13 (cherry picked from commit 3721682a02437cdbb802c8ed021aabd4344a1716) Co-authored-by: Eve Meelan <81647476+Eve832@users.noreply.github.com> --- docs/sources/explore/explore-metrics.md | 72 +++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 docs/sources/explore/explore-metrics.md diff --git a/docs/sources/explore/explore-metrics.md b/docs/sources/explore/explore-metrics.md new file mode 100644 index 000000000000..a72d0a242efa --- /dev/null +++ b/docs/sources/explore/explore-metrics.md @@ -0,0 +1,72 @@ +--- +labels: + products: + - cloud + - enterprise + - oss +title: Explore Metrics +aliases: +description: This topic describes the Explore Metrics feature +weight: 200 +--- + +# Grafana Explore Metrics + +Grafana Explore Metrics is a query-less experience for browsing **Prometheus-compatible** metrics. Quickly find related metrics with just a few simple clicks, without needing to write PromQL queries to retrieve metrics. + +{{% admonition type="warning" %}} +Explore Metrics is currently in [private preview](/docs/release-life-cycle/). Grafana Labs offers support on a best-effort basis, and breaking changes might occur prior to the feature being made generally available. +{{% /admonition %}} + +With Explore Metrics, you can: + +- easily slice and dice metrics based on their labels, so you can immediately see anomalies and identify issues +- see the right visualization for your metric based on its type (gauge vs. counter, for example) without building it yourself +- surface other metrics relevant to the current metric +- “explore in a drawer” - expand a drawer over a dashboard with more content so you don’t lose your place +- view a history of user steps when navigating through metrics and their filters +- easily pivot to other related telemetry, including logs or traces + +You can access Explore Metrics either as a standalone experience or as part of Grafana dashboards. + +## Standalone experience + +To access Explore Metrics as a standalone experience: + +1. Click the arrow next to **Explore** in the Grafana left-side menu and click **Metrics**. You are taken to an overview page that shows recent metrics, bookmarks, and the option to select a new metric exploration. +1. To get started with a new exploration, click **+ New metric exploration**. +1. Select **Prometheus** or any Prometheus-compatible data source available in the drop-down menu under **Data source**. +1. Click **+ Add label** to select a label-value pair from the drop-down menu. You can add multiple label-value pairs. A label type will appear above the selected label with a drop-down list of options from which to choose. For example, if you select the label `container` a drop-down list of available containers appears. +1. You can also search for metrics using keywords under **Search metrics** in the search bar. +1. Use the time picker to select a date and time range from the drop-down menu or use an absolute time range. +1. Click the down arrow next to the **Refresh** icon to set a refresh rate from the drop-down menu. The default is `Off`. +1. Click the **Settings** icon and toggle **Always keep selected metric graph in-view** to keep your main graph always in view on the Breakdown drill-down tab. + +The **History** button in the upper left corner tracks every step navigating through metric exploration. + +![show metrics explore overview](/media/metrics-explore/metrics-explore-overview.png) + +### Metrics exploration + +To further explore a metric, click **Select** in the upper right corner of the metric visualization. + +![show select box](/media/metrics-explore/select-metric.png) + +- The **Overview** tab provides a description for each metric, as well as the metric `type` and `unit` associated with the metric. It also provides a list of labels associated with the metric. Click on any label to view drill-down visualizations. +- The **Breakdown** tab depicts time series visualizations for each of the label-value pairs for the selected metric. You can further drill down on each label and click **Add to filter** to add the label/value pair into your filters. You can also change the **View** from grid to rows. +- The **Related metrics** tab depicts related metrics with relevant key words. You can repeat the drill down process for any related metric. Toggle **SHow previews** to preview visualizations. + +Once you have gathered your metrics exploration data you can: + +- Click the **Explore** icon on the right side to open the graph in Explore, where you can modify the query or add the graph to a dashboard or incident. +- Click the **Share** icon on the right side to copy the metric drill down URL to the clipboard so it can be shared. +- Click the **Star** icon on the right side to bookmark and save the metrics exploration. + +## Dashboard experience + +To access Explore Metrics via a dashboard: + +1. Navigate to your dashboard. +1. Select a time series panel. +1. Click the panel menu in the upper right and select **Explore Metrics**. If there are multiple metrics, click on the one you want to explore. +1. You will see a slide out drawer with the Metrics Experience, starting with the drill down. You can access the standalone experience by clicking **Open** in the upper right. From acb8d033ed40d06c9fb7030522a895a24ff21858 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 15:15:54 -0400 Subject: [PATCH 134/138] [v10.4.x] Docs: g11 preview whats new fixes (#85762) Docs: g11 preview whats new fixes (#85759) * Made style fixes to intro * Updated upgrade guide menu title * Commented Explore metrics docs link back in (cherry picked from commit 8014665ab55955984a7cebc0b47a12d32f37c666) Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --- docs/sources/upgrade-guide/upgrade-v11.0/index.md | 2 +- docs/sources/whatsnew/whats-new-in-v11-0.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/sources/upgrade-guide/upgrade-v11.0/index.md b/docs/sources/upgrade-guide/upgrade-v11.0/index.md index 068171c30035..db6373cec196 100644 --- a/docs/sources/upgrade-guide/upgrade-v11.0/index.md +++ b/docs/sources/upgrade-guide/upgrade-v11.0/index.md @@ -8,7 +8,7 @@ keywords: - '11.0' - '11.0-preview' title: Upgrade to Grafana v11.0-preview -menuTitle: Upgrade to v11.0 +menuTitle: Upgrade to v11.0-preview weight: 1200 --- diff --git a/docs/sources/whatsnew/whats-new-in-v11-0.md b/docs/sources/whatsnew/whats-new-in-v11-0.md index 059861c7d7d1..19e8ae502a85 100644 --- a/docs/sources/whatsnew/whats-new-in-v11-0.md +++ b/docs/sources/whatsnew/whats-new-in-v11-0.md @@ -21,7 +21,7 @@ weight: -42 # What’s new in Grafana v11.0-preview -Welcome to Grafana 11.0-preview! This release contains some major improvements: most notably, the ability to explore your Prometheus metrics and loki logs without writing any PromQL or LogQL, using Explore Metrics and Explore Logs. The dashboard experience is better than ever with Edit mode for dashboards, AI-generated dashboard names and descriptions, and general availability for subfolders. You can also take advantage of improvements to the Canvas and Table panels, new Transformations, a revamp of the Alert Rule page, and more. +Welcome to Grafana 11.0-preview! This release contains some major improvements: most notably, the ability to explore your Prometheus metrics and Loki logs without writing any PromQL or LogQL, using Explore Metrics and Explore Logs. The dashboard experience is better than ever with edit mode for dashboards, AI-generated dashboard names and descriptions, and general availability for subfolders. You can also take advantage of improvements to the canvas and table visualizations, new transformations, a revamp of the Alert Rule page, and more. Why "preview?" The Grafana 11.0 stable release is planned for this May. This is an early release to coincide with [Grafanacon 2024](https://grafana.com/about/events/grafanacon/2024/), so that you can try the new functionality early. To understand the differences between preview and GA releases, review the [release life cycle](https://grafana.com/docs/release-life-cycle/). @@ -67,7 +67,7 @@ Explore Metrics is a query-less experience for browsing Prometheus-compatible me … all without writing any queries! -To learn more, refer to the following video demo: +To learn more, refer to the Explore Metrics [documentation](https://grafana.com/docs/grafana//explore/explore-metrics/) as well as the following video demo: {{< youtube id="JbaPufQs5LY" >}} From 87f391e6b366897b19ae42dca6741c1ba5fae75d Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Tue, 9 Apr 2024 12:31:39 +0100 Subject: [PATCH 135/138] [v10.4.x] Chore: Update RPM docs to include beta release references (#85792) Chore: Update RPM docs to include beta release references (#85753) * Update RPM docs to include beta release references * andreas/update-installation-docs/ run lint * Don't number lists --------- Co-authored-by: jev forsberg (cherry picked from commit 3420e942acaa010761ca705a864a32eb3f49dc5a) Co-authored-by: Andreas Christou --- .../installation/redhat-rhel-fedora/index.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/sources/setup-grafana/installation/redhat-rhel-fedora/index.md b/docs/sources/setup-grafana/installation/redhat-rhel-fedora/index.md index ba5d83dc62b4..92c077900aed 100644 --- a/docs/sources/setup-grafana/installation/redhat-rhel-fedora/index.md +++ b/docs/sources/setup-grafana/installation/redhat-rhel-fedora/index.md @@ -21,10 +21,12 @@ If you install via RPM or the `.tar.gz` file, then you must manually update Graf If you install from the RPM repository, then Grafana is automatically updated every time you update your applications. -| Grafana Version | Package | Repository | -| ------------------ | ------------------ | ------------------------- | -| Grafana Enterprise | grafana-enterprise | `https://rpm.grafana.com` | -| Grafana OSS | grafana | `https://rpm.grafana.com` | +| Grafana Version | Package | Repository | +| ------------------------- | ------------------ | ------------------------------ | +| Grafana Enterprise | grafana-enterprise | `https://rpm.grafana.com` | +| Grafana Enterprise (Beta) | grafana-enterprise | `https://rpm-beta.grafana.com` | +| Grafana OSS | grafana | `https://rpm.grafana.com` | +| Grafana OSS (Beta) | grafana | `https://rpm-beta.grafana.com` | {{% admonition type="note" %}} Grafana Enterprise is the recommended and default edition. It is available for free and includes all the features of the OSS edition. You can also upgrade to the [full Enterprise feature set](/products/enterprise/?utm_source=grafana-install-page), which has support for [Enterprise plugins](/grafana/plugins/?enterprise=1&utcm_source=grafana-install-page). @@ -32,6 +34,10 @@ Grafana Enterprise is the recommended and default edition. It is available for f To install Grafana from the RPM repository, complete the following steps: +{{% admonition type="note" %}} +If you wish to install beta versions of Grafana, substitute the repository URL for the beta URL listed above. +{{% /admonition %}} + 1. Import the GPG key: ```bash @@ -53,12 +59,6 @@ To install Grafana from the RPM repository, complete the following steps: sslcacert=/etc/pki/tls/certs/ca-bundle.crt ``` -1. To prevent beta versions from being installed, add the following exclude line to your `.repo` file. - - ```bash - exclude=*beta* - ``` - 1. To install Grafana OSS, run the following command: ```bash From f97672fc237e4a821fd7a97f5e4a747f31c0fcf5 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Tue, 9 Apr 2024 09:35:58 -0400 Subject: [PATCH 136/138] [v10.4.x] Docs: add updated youtube link (#85802) Docs: add updated youtube link (#85801) Updated youtube link (cherry picked from commit 1b1450e5935c44af2671260a2694306aea06eec0) Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --- docs/sources/whatsnew/whats-new-in-v11-0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/whatsnew/whats-new-in-v11-0.md b/docs/sources/whatsnew/whats-new-in-v11-0.md index 19e8ae502a85..18707bd3784c 100644 --- a/docs/sources/whatsnew/whats-new-in-v11-0.md +++ b/docs/sources/whatsnew/whats-new-in-v11-0.md @@ -113,7 +113,7 @@ We moved the time picker into the dashboard canvas and now, together with templa If you want to learn more, in detail, about all the improvements we've made, don't miss our blog post. - +{{< youtube id="kcKwBhvrsHc" >}} ### Scenes for viewers From 7ceb112f37d54c554e46858cacd285dad8fa1f85 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Tue, 9 Apr 2024 14:32:14 -0500 Subject: [PATCH 137/138] [v10.4.x] Docs: Fix wrong word for tempo example config (#85817) Docs: Fix wrong word for tempo example config (#85046) Update configure-tempo-data-source.md Replace traceToProfiles with tracesToProfiles (cherry picked from commit 4205491788235c0b3f81d62849e5ca4593d18c6c) Co-authored-by: wissy <10373091+wissyhost@users.noreply.github.com> --- docs/sources/datasources/tempo/configure-tempo-data-source.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/datasources/tempo/configure-tempo-data-source.md b/docs/sources/datasources/tempo/configure-tempo-data-source.md index 4c8e0b3262f0..0f357e597844 100644 --- a/docs/sources/datasources/tempo/configure-tempo-data-source.md +++ b/docs/sources/datasources/tempo/configure-tempo-data-source.md @@ -259,7 +259,7 @@ datasources: queries: - name: 'Sample query' query: 'sum(rate(traces_spanmetrics_latency_bucket{$$__tags}[5m]))' - traceToProfiles: + tracesToProfiles: datasourceUid: 'grafana-pyroscope-datasource' tags: ['job', 'instance', 'pod', 'namespace'] profileTypeId: 'process_cpu:cpu:nanoseconds:cpu:nanoseconds' From 22809dea50455ae875624827dd277b17621b4ed4 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 10 Apr 2024 09:19:40 -0400 Subject: [PATCH 138/138] [v10.4.x] Docs: add unit scaling clarification (#85871) Docs: add unit scaling clarification (#85830) * Added unit scaling information * Edited (cherry picked from commit d666b92317a5c54a8b6165b6a932387b442f5bd6) Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --- .../panels-visualizations/configure-standard-options/index.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/sources/panels-visualizations/configure-standard-options/index.md b/docs/sources/panels-visualizations/configure-standard-options/index.md index a72a65672c8c..b8a302e57637 100644 --- a/docs/sources/panels-visualizations/configure-standard-options/index.md +++ b/docs/sources/panels-visualizations/configure-standard-options/index.md @@ -84,6 +84,10 @@ You can also paste a native emoji in the **Unit** drop-down and select it as a c ![A time series visualization using custom thumbs up emoji units](/media/docs/grafana/panels-visualizations/thumbsup_panel_v11.0.png) +#### Control unit scaling + +By default, Grafana automatically scales the unit based on the magnitude of the value. For example, if you have values of 0.14kW and 3000kW, Grafana displays them as 140W and 3MW, respectively. You can use custom units to control this behavior by setting a prefix, suffix, or custom SI unit. + #### String units Sometimes Grafana is too aggressive in interpreting strings and displaying them as numbers. To configure Grafana to show the original string value, select **Misc > String** in the **Unit** drop-down.