From 9aa23dd73f926866f5d2ff2ca0f50a94276288af Mon Sep 17 00:00:00 2001 From: bo0tzz Date: Mon, 16 Dec 2024 09:21:53 +0100 Subject: [PATCH 01/38] Docs: Remove bad `info.` from generic-oauth JMESPaths (#94592) * Remove bad `info.` from generic-oauth JMESPaths * fix: remove nesting from example payloads * Lint --------- Co-authored-by: Mihaly Gyongyosi --- .../generic-oauth/index.md | 56 ++++++------------- 1 file changed, 17 insertions(+), 39 deletions(-) diff --git a/docs/sources/setup-grafana/configure-security/configure-authentication/generic-oauth/index.md b/docs/sources/setup-grafana/configure-security/configure-authentication/generic-oauth/index.md index 2d6eb5fd39d..1c9571f712d 100644 --- a/docs/sources/setup-grafana/configure-security/configure-authentication/generic-oauth/index.md +++ b/docs/sources/setup-grafana/configure-security/configure-authentication/generic-oauth/index.md @@ -239,14 +239,10 @@ Payload: ```json { ... - "info": { - ... - "groups": [ - "engineer", - "admin", - ], - ... - }, + "groups": [ + "engineer", + "admin", + ], ... } ``` @@ -254,7 +250,7 @@ Payload: Config: ```bash -role_attribute_path = contains(info.groups[*], 'admin') && 'Admin' || contains(info.groups[*], 'editor') && 'Editor' || 'Viewer' +role_attribute_path = contains(groups[*], 'admin') && 'Admin' || contains(groups[*], 'editor') && 'Editor' || 'Viewer' ``` ##### Map server administrator role @@ -266,13 +262,9 @@ Payload: ```json { ... - "info": { - ... - "roles": [ - "admin", - ], - ... - }, + "roles": [ + "admin", + ], ... } ``` @@ -280,7 +272,7 @@ Payload: Config: ```ini -role_attribute_path = contains(info.roles[*], 'admin') && 'GrafanaAdmin' || contains(info.roles[*], 'editor') && 'Editor' || 'Viewer' +role_attribute_path = contains(roles[*], 'admin') && 'GrafanaAdmin' || contains(roles[*], 'editor') && 'Editor' || 'Viewer' allow_assign_grafana_admin = true ``` @@ -305,26 +297,16 @@ Payload: ```json { - ... - "info": { - ... - "roles": [ - "org_foo", - "org_bar", - "another_org" - ], - ... - }, - ... + "roles": ["org_foo", "org_bar", "another_org"] } ``` Config: ```ini -role_attribute_path = contains(info.roles[*], 'admin') && 'GrafanaAdmin' || 'None' +role_attribute_path = contains(roles[*], 'admin') && 'GrafanaAdmin' || 'None' allow_assign_grafana_admin = true -org_attribute_path = info.roles +org_attribute_path = roles org_mapping = org_foo:org_foo:Viewer org_bar:org_bar:Editor *:org_baz:Editor ``` @@ -347,7 +329,7 @@ To learn more about group synchronization, refer to [Configure team sync](https: Configuration: ```bash -groups_attribute_path = info.groups +groups_attribute_path = groups ``` Payload: @@ -355,14 +337,10 @@ Payload: ```json { ... - "info": { - ... - "groups": [ - "engineers", - "analysts", - ], - ... - }, + "groups": [ + "engineers", + "analysts", + ], ... } ``` From a0558749f01bd02bafba5f08f24c93290fad5db5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 10:10:01 +0100 Subject: [PATCH 02/38] Update dependency eslint-plugin-jsdoc to v50.6.1 (#97958) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- packages/grafana-prometheus/package.json | 2 +- yarn.lock | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index dce0a29338a..24d970d0346 100644 --- a/package.json +++ b/package.json @@ -180,7 +180,7 @@ "eslint-plugin-import": "^2.31.0", "eslint-plugin-jest": "28.9.0", "eslint-plugin-jest-dom": "^5.4.0", - "eslint-plugin-jsdoc": "50.5.0", + "eslint-plugin-jsdoc": "50.6.1", "eslint-plugin-jsx-a11y": "6.10.2", "eslint-plugin-lodash": "8.0.0", "eslint-plugin-no-barrel-files": "^1.1.1", diff --git a/packages/grafana-prometheus/package.json b/packages/grafana-prometheus/package.json index 784c9b83e87..646dace723b 100644 --- a/packages/grafana-prometheus/package.json +++ b/packages/grafana-prometheus/package.json @@ -110,7 +110,7 @@ "eslint-config-prettier": "9.1.0", "eslint-plugin-import": "^2.31.0", "eslint-plugin-jest": "28.9.0", - "eslint-plugin-jsdoc": "50.5.0", + "eslint-plugin-jsdoc": "50.6.1", "eslint-plugin-jsx-a11y": "6.10.2", "eslint-plugin-lodash": "8.0.0", "eslint-plugin-react": "7.37.2", diff --git a/yarn.lock b/yarn.lock index a79d86e3f6d..3e29e05dc5f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3676,7 +3676,7 @@ __metadata: eslint-config-prettier: "npm:9.1.0" eslint-plugin-import: "npm:^2.31.0" eslint-plugin-jest: "npm:28.9.0" - eslint-plugin-jsdoc: "npm:50.5.0" + eslint-plugin-jsdoc: "npm:50.6.1" eslint-plugin-jsx-a11y: "npm:6.10.2" eslint-plugin-lodash: "npm:8.0.0" eslint-plugin-react: "npm:7.37.2" @@ -15782,9 +15782,9 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-jsdoc@npm:50.5.0": - version: 50.5.0 - resolution: "eslint-plugin-jsdoc@npm:50.5.0" +"eslint-plugin-jsdoc@npm:50.6.1": + version: 50.6.1 + resolution: "eslint-plugin-jsdoc@npm:50.6.1" dependencies: "@es-joy/jsdoccomment": "npm:~0.49.0" are-docs-informative: "npm:^0.0.2" @@ -15799,7 +15799,7 @@ __metadata: synckit: "npm:^0.9.1" peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - checksum: 10/4abe3ac34ad0d3bf34238968b6961c4ea9ec8eb058046f554cf60a702a91ac294eda8e475cadeaa1951e1a5317dd055543407787b04256fbd0728454af7e2ad0 + checksum: 10/53fceff38a5317bb7c42c15a622100515aec89aea0d2bbf07e7d2d07eacdaa10ce625232a1bc7c1497f7bbe044675123d30cd3e123fa52fe5c7a9c336a59709c languageName: node linkType: hard @@ -17723,7 +17723,7 @@ __metadata: eslint-plugin-import: "npm:^2.31.0" eslint-plugin-jest: "npm:28.9.0" eslint-plugin-jest-dom: "npm:^5.4.0" - eslint-plugin-jsdoc: "npm:50.5.0" + eslint-plugin-jsdoc: "npm:50.6.1" eslint-plugin-jsx-a11y: "npm:6.10.2" eslint-plugin-lodash: "npm:8.0.0" eslint-plugin-no-barrel-files: "npm:^1.1.1" From ca758062cd168ef117823ce0a3da621f8be313db Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:36:36 +0000 Subject: [PATCH 03/38] Update dependency eslint-plugin-jest-dom to v5.5.0 (#97957) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 3e29e05dc5f..96cf91c3d39 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15749,8 +15749,8 @@ __metadata: linkType: hard "eslint-plugin-jest-dom@npm:^5.4.0": - version: 5.4.0 - resolution: "eslint-plugin-jest-dom@npm:5.4.0" + version: 5.5.0 + resolution: "eslint-plugin-jest-dom@npm:5.5.0" dependencies: "@babel/runtime": "npm:^7.16.3" requireindex: "npm:^1.2.0" @@ -15760,7 +15760,7 @@ __metadata: peerDependenciesMeta: "@testing-library/dom": optional: true - checksum: 10/b8b0b0249d066658a75723892bc6f52d6bcf03ff0a69fc5020548c49f740613a8f3acce647f8f04b292606d2bd0ab3372a695aa3d90b4efb19e71870bbddf637 + checksum: 10/73aaaa6117abbe3b197bc6b1e45839aaa9c2b4c86e7efbc4ff29f03318ec7f019a8e32652c06c61f06fdb22fb296c068a802a268e7b88aa6b71d3477d949b2c6 languageName: node linkType: hard From 1ac6143f4e892a7ba4afed048eb30d508d653127 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:37:16 +0000 Subject: [PATCH 04/38] Update dependency knip to v5.40.0 (#97965) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/yarn.lock b/yarn.lock index 96cf91c3d39..cb54903864b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -20712,8 +20712,8 @@ __metadata: linkType: hard "knip@npm:^5.10.0": - version: 5.37.1 - resolution: "knip@npm:5.37.1" + version: 5.40.0 + resolution: "knip@npm:5.40.0" dependencies: "@nodelib/fs.walk": "npm:1.2.8" "@snyk/github-codeowners": "npm:1.1.0" @@ -20726,7 +20726,7 @@ __metadata: picocolors: "npm:^1.1.0" picomatch: "npm:^4.0.1" pretty-ms: "npm:^9.0.0" - smol-toml: "npm:^1.3.0" + smol-toml: "npm:^1.3.1" strip-json-comments: "npm:5.0.1" summary: "npm:2.1.0" zod: "npm:^3.22.4" @@ -20737,7 +20737,7 @@ __metadata: bin: knip: bin/knip.js knip-bun: bin/knip-bun.js - checksum: 10/e73962f7daac5eb3d275654bbf719e91001aca8d03da9d0dc303cbe0cd47000114cf99d341b377b866f815e7d6821e3fdb1fca24e0a178e8204c1adaa2f2f41c + checksum: 10/238d76428a1f0cd3a184ebd9aaea2e07b3b8434cdee6c6e9230d6ae31f18b93188e2b60fbd64769d2448ce5b0114e662ee536843207514b1e95060b8740218d8 languageName: node linkType: hard @@ -27680,7 +27680,7 @@ __metadata: languageName: node linkType: hard -"smol-toml@npm:^1.3.0": +"smol-toml@npm:^1.3.1": version: 1.3.1 resolution: "smol-toml@npm:1.3.1" checksum: 10/b999828ea46cf44ae90b6293884d6a139dfb4545ac6f86cbd1002568a943a43d8895ad82413855d095eec0c0bc21d23413c0a25a26c7fad6395c2ce42c2fdbd0 From 97959b60bb63e9f39975b79d89a7732bc1fd3d8c Mon Sep 17 00:00:00 2001 From: Karl Persson Date: Mon, 16 Dec 2024 10:39:29 +0100 Subject: [PATCH 05/38] Team: front end cleanup (#97945) * Remove permissions levels that don't exists for team memberships * Remove Permission from team structure * Use WithAccessControlMetadata * Remove roles from base Team interface --- .../profile/UserProfileEditPage.test.tsx | 2 -- .../features/profile/state/reducers.test.ts | 6 ++--- public/app/features/teams/TeamList.tsx | 9 ++++--- .../app/features/teams/__mocks__/teamMocks.ts | 1 - public/app/features/teams/state/actions.ts | 6 ++--- public/app/types/acl.ts | 2 -- public/app/types/teams.ts | 24 ++++++++++--------- 7 files changed, 23 insertions(+), 27 deletions(-) diff --git a/public/app/features/profile/UserProfileEditPage.test.tsx b/public/app/features/profile/UserProfileEditPage.test.tsx index 87d3f2bd7dc..9f0adc7cee1 100644 --- a/public/app/features/profile/UserProfileEditPage.test.tsx +++ b/public/app/features/profile/UserProfileEditPage.test.tsx @@ -8,7 +8,6 @@ import * as useQueryParams from 'app/core/hooks/useQueryParams'; import { TestProvider } from '../../../test/helpers/TestProvider'; import { backendSrv } from '../../core/services/backend_srv'; -import { TeamPermissionLevel } from '../../types'; import { getMockTeam } from '../teams/__mocks__/teamMocks'; import { Props, UserProfileEditPage } from './UserProfileEditPage'; @@ -45,7 +44,6 @@ const defaultProps: Props = { email: 'team.one@test.com', avatarUrl: '/avatar/07d881f402480a2a511a9a15b5fa82c0', memberCount: 2000, - permission: TeamPermissionLevel.Admin, }), ], orgs: [ diff --git a/public/app/features/profile/state/reducers.test.ts b/public/app/features/profile/state/reducers.test.ts index c0f62ef1591..352f824cc55 100644 --- a/public/app/features/profile/state/reducers.test.ts +++ b/public/app/features/profile/state/reducers.test.ts @@ -1,5 +1,5 @@ import { reducerTester } from '../../../../test/core/redux/reducerTester'; -import { OrgRole, TeamPermissionLevel } from '../../../types'; +import { OrgRole } from '../../../types'; import { getMockTeam } from '../../teams/__mocks__/teamMocks'; import { @@ -92,13 +92,13 @@ describe('userReducer', () => { .givenReducer(userReducer, { ...initialUserState, teamsAreLoading: true }) .whenActionIsDispatched( teamsLoaded({ - teams: [getMockTeam(1, 'aaaaaa', { permission: TeamPermissionLevel.Admin })], + teams: [getMockTeam(1, 'aaaaaa')], }) ) .thenStateShouldEqual({ ...initialUserState, teamsAreLoading: false, - teams: [getMockTeam(1, 'aaaaaa', { permission: TeamPermissionLevel.Admin })], + teams: [getMockTeam(1, 'aaaaaa')], }); }); }); diff --git a/public/app/features/teams/TeamList.tsx b/public/app/features/teams/TeamList.tsx index 35dd58c3355..a3c1155ade9 100644 --- a/public/app/features/teams/TeamList.tsx +++ b/public/app/features/teams/TeamList.tsx @@ -23,13 +23,13 @@ import { Page } from 'app/core/components/Page/Page'; import { fetchRoleOptions } from 'app/core/components/RolePicker/api'; import { Trans, t } from 'app/core/internationalization'; import { contextSrv } from 'app/core/services/context_srv'; -import { AccessControlAction, Role, StoreState, Team } from 'app/types'; +import { AccessControlAction, Role, StoreState, TeamWithRoles } from 'app/types'; import { TeamRolePicker } from '../../core/components/RolePicker/TeamRolePicker'; import { deleteTeam, loadTeams, changePage, changeQuery, changeSort } from './state/actions'; -type Cell = CellProps; +type Cell = CellProps; export interface OwnProps {} export interface State { @@ -37,13 +37,12 @@ export interface State { } // this is dummy data to pass to the table while the real data is loading -const skeletonData: Team[] = new Array(3).fill(null).map((_, index) => ({ +const skeletonData: TeamWithRoles[] = new Array(3).fill(null).map((_, index) => ({ id: index, uid: '', memberCount: 0, name: '', orgId: 0, - permission: 0, })); export const TeamList = ({ @@ -76,7 +75,7 @@ export const TeamList = ({ const canCreate = contextSrv.hasPermission(AccessControlAction.ActionTeamsCreate); const displayRolePicker = shouldDisplayRolePicker(); - const columns: Array> = useMemo( + const columns: Array> = useMemo( () => [ { id: 'avatarUrl', diff --git a/public/app/features/teams/__mocks__/teamMocks.ts b/public/app/features/teams/__mocks__/teamMocks.ts index 5cfbe77a143..1e75b8a6283 100644 --- a/public/app/features/teams/__mocks__/teamMocks.ts +++ b/public/app/features/teams/__mocks__/teamMocks.ts @@ -24,7 +24,6 @@ export const getMockTeam = (i = 1, uid = 'aaaaaa', overrides = {}): Team => { avatarUrl: 'some/url/', email: `test-${uid}@test.com`, memberCount: i, - permission: TeamPermissionLevel.Member, accessControl: { isEditor: false }, orgId: 0, ...overrides, diff --git a/public/app/features/teams/state/actions.ts b/public/app/features/teams/state/actions.ts index 38f3a110a97..32c0e1fdd22 100644 --- a/public/app/features/teams/state/actions.ts +++ b/public/app/features/teams/state/actions.ts @@ -5,7 +5,7 @@ import { FetchDataArgs } from '@grafana/ui'; import { updateNavIndex } from 'app/core/actions'; import { contextSrv } from 'app/core/core'; import { accessControlQueryParam } from 'app/core/utils/accessControl'; -import { AccessControlAction, Team, TeamMember, ThunkResult } from 'app/types'; +import { AccessControlAction, TeamWithRoles, TeamMember, ThunkResult, Team } from 'app/types'; import { buildNavModel } from './navModel'; import { @@ -46,9 +46,9 @@ export function loadTeams(initial = false): ThunkResult { contextSrv.hasPermission(AccessControlAction.ActionTeamsRolesList) ) { dispatch(rolesFetchBegin()); - const teamIds = response?.teams.map((t: Team) => t.id); + const teamIds = response?.teams.map((t: TeamWithRoles) => t.id); const roles = await getBackendSrv().post(`/api/access-control/teams/roles/search`, { teamIds }); - response.teams.forEach((t: Team) => { + response.teams.forEach((t: TeamWithRoles) => { t.roles = roles ? roles[t.id] || [] : []; }); dispatch(rolesFetchEnd()); diff --git a/public/app/types/acl.ts b/public/app/types/acl.ts index 3cbb2c110e1..b939d67c726 100644 --- a/public/app/types/acl.ts +++ b/public/app/types/acl.ts @@ -2,9 +2,7 @@ import { OrgRole } from '@grafana/data'; export enum TeamPermissionLevel { Admin = 4, - Editor = 2, Member = 0, - Viewer = 1, } export { OrgRole as OrgRole }; diff --git a/public/app/types/teams.ts b/public/app/types/teams.ts index 52407a544f9..26f4e6f3aa7 100644 --- a/public/app/types/teams.ts +++ b/public/app/types/teams.ts @@ -1,5 +1,6 @@ +import { WithAccessControlMetadata } from '@grafana/data'; + import { Role } from './accessControl'; -import { TeamPermissionLevel } from './acl'; export interface TeamDTO { /** @@ -13,14 +14,16 @@ export interface TeamDTO { } // This is the team resource with permissions and metadata expanded -export interface Team { - id: number; // TODO switch to UUID - uid: string; // Prefer UUID - +export interface Team extends WithAccessControlMetadata { /** - * AccessControl metadata associated with a given resource. + * Internal id of team + * @deprecated use uid instead */ - accessControl?: Record; + id: number; + /** + * A unique identifier for the team. + */ + uid: string; // Prefer UUID /** * AvatarUrl is the team's avatar URL. */ @@ -41,10 +44,9 @@ export interface Team { * OrgId is the ID of an organisation the team belongs to. */ orgId: number; - /** - * TODO - it seems it's a team_member.permission, unlikely it should belong to the team kind - */ - permission: TeamPermissionLevel; +} + +export interface TeamWithRoles extends Team { /** * RBAC roles assigned to the team. */ From e85e65834329a0c7e2f745dd246f83ccfb5fae07 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:40:12 +0000 Subject: [PATCH 06/38] Update dependency @floating-ui/react to v0.27.1 (#98004) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- packages/grafana-prometheus/package.json | 2 +- packages/grafana-ui/package.json | 2 +- yarn.lock | 14 +++++++------- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 24d970d0346..cfb12ec49ad 100644 --- a/package.json +++ b/package.json @@ -256,7 +256,7 @@ "@emotion/css": "11.13.5", "@emotion/react": "11.14.0", "@fingerprintjs/fingerprintjs": "^3.4.2", - "@floating-ui/react": "0.27.0", + "@floating-ui/react": "0.27.1", "@formatjs/intl-durationformat": "^0.7.0", "@glideapps/glide-data-grid": "^6.0.0", "@grafana/aws-sdk": "0.5.0", diff --git a/packages/grafana-prometheus/package.json b/packages/grafana-prometheus/package.json index 646dace723b..740fd985222 100644 --- a/packages/grafana-prometheus/package.json +++ b/packages/grafana-prometheus/package.json @@ -37,7 +37,7 @@ }, "dependencies": { "@emotion/css": "11.13.5", - "@floating-ui/react": "0.27.0", + "@floating-ui/react": "0.27.1", "@grafana/data": "11.5.0-pre", "@grafana/experimental": "2.1.5", "@grafana/faro-web-sdk": "1.12.2", diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index 91238168a2b..60cb2105c49 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -49,7 +49,7 @@ "@emotion/css": "11.13.5", "@emotion/react": "11.14.0", "@emotion/serialize": "1.3.3", - "@floating-ui/react": "0.27.0", + "@floating-ui/react": "0.27.1", "@grafana/data": "11.5.0-pre", "@grafana/e2e-selectors": "11.5.0-pre", "@grafana/faro-web-sdk": "^1.3.6", diff --git a/yarn.lock b/yarn.lock index cb54903864b..3a8d6f719d7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2649,9 +2649,9 @@ __metadata: languageName: node linkType: hard -"@floating-ui/react@npm:0.27.0": - version: 0.27.0 - resolution: "@floating-ui/react@npm:0.27.0" +"@floating-ui/react@npm:0.27.1": + version: 0.27.1 + resolution: "@floating-ui/react@npm:0.27.1" dependencies: "@floating-ui/react-dom": "npm:^2.1.2" "@floating-ui/utils": "npm:^0.2.8" @@ -2659,7 +2659,7 @@ __metadata: peerDependencies: react: ">=17.0.0" react-dom: ">=17.0.0" - checksum: 10/b04e8b356c6ffebbd7033cfb0ba7c08e83b3c0314b28e860ff1502595ca6eb245ef8b935b8879af044edca38a27335fefff15eddaabe3a7d39bcfd255b7fcd86 + checksum: 10/18262251e729f7496627a9ea14eabdc7e3d1031a8dc2b08e2f8613240b5a515c0970b87367df858c715240da384711a0620a522287d85390cc2da023571012e3 languageName: node linkType: hard @@ -3625,7 +3625,7 @@ __metadata: dependencies: "@emotion/css": "npm:11.13.5" "@emotion/eslint-plugin": "npm:11.12.0" - "@floating-ui/react": "npm:0.27.0" + "@floating-ui/react": "npm:0.27.1" "@grafana/data": "npm:11.5.0-pre" "@grafana/e2e-selectors": "npm:11.5.0-pre" "@grafana/experimental": "npm:2.1.5" @@ -3928,7 +3928,7 @@ __metadata: "@emotion/react": "npm:11.14.0" "@emotion/serialize": "npm:1.3.3" "@faker-js/faker": "npm:^9.0.0" - "@floating-ui/react": "npm:0.27.0" + "@floating-ui/react": "npm:0.27.1" "@grafana/data": "npm:11.5.0-pre" "@grafana/e2e-selectors": "npm:11.5.0-pre" "@grafana/faro-web-sdk": "npm:^1.3.6" @@ -17550,7 +17550,7 @@ __metadata: "@emotion/eslint-plugin": "npm:11.12.0" "@emotion/react": "npm:11.14.0" "@fingerprintjs/fingerprintjs": "npm:^3.4.2" - "@floating-ui/react": "npm:0.27.0" + "@floating-ui/react": "npm:0.27.1" "@formatjs/intl-durationformat": "npm:^0.7.0" "@glideapps/glide-data-grid": "npm:^6.0.0" "@grafana/aws-sdk": "npm:0.5.0" From fccb7816b53353fe411c5acdfdb6f780ae9accca Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 10:03:37 +0000 Subject: [PATCH 07/38] Update dependency @rollup/plugin-typescript to v12.1.2 (#98007) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 3a8d6f719d7..7ca1d85809a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6610,8 +6610,8 @@ __metadata: linkType: hard "@rollup/plugin-typescript@npm:^12.1.0": - version: 12.1.1 - resolution: "@rollup/plugin-typescript@npm:12.1.1" + version: 12.1.2 + resolution: "@rollup/plugin-typescript@npm:12.1.2" dependencies: "@rollup/pluginutils": "npm:^5.1.0" resolve: "npm:^1.22.1" @@ -6624,7 +6624,7 @@ __metadata: optional: true tslib: optional: true - checksum: 10/838d5e67d1b383154fab7ae1b0c58e91844c70380210b12c1d5f2ed5d2264d4fbd21ff991a13a4a72078dce897b5c482c70554a21671269219aa9d2525f14dcd + checksum: 10/1fd201b9430125686bcdb3eecfa4f8d9d5005a9d454f2d733c0fdc0f58e28f772209ecbfe4f5d1a42a2a7ac25746a5f37d15897d695326eaea0fe3a30857375d languageName: node linkType: hard From 089111f702accf39e738b1140a6848000d686bcb Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Mon, 16 Dec 2024 11:50:07 +0100 Subject: [PATCH 08/38] Plugins: Set migration handler to definne its own PanelMigrationModel and add tests (#97743) * Add custom panel model type for the setMigrationHandler * Add tests --- .../src/panel/PanelPlugin.test.tsx | 175 ++++++++++++++++++ packages/grafana-data/src/types/panel.ts | 22 ++- 2 files changed, 196 insertions(+), 1 deletion(-) diff --git a/packages/grafana-data/src/panel/PanelPlugin.test.tsx b/packages/grafana-data/src/panel/PanelPlugin.test.tsx index 50801dd8a84..59d8bf9d75b 100644 --- a/packages/grafana-data/src/panel/PanelPlugin.test.tsx +++ b/packages/grafana-data/src/panel/PanelPlugin.test.tsx @@ -5,6 +5,7 @@ import { standardFieldConfigEditorRegistry, } from '../field/standardFieldConfigEditorRegistry'; import { FieldConfigProperty, FieldConfigPropertyItem } from '../types/fieldOverrides'; +import { PanelMigrationModel } from '../types/panel'; import { PanelOptionsEditorBuilder } from '../utils/OptionsUIBuilders'; import { PanelPlugin } from './PanelPlugin'; @@ -308,4 +309,178 @@ describe('PanelPlugin', () => { }); }); }); + + describe('setMigrationHandler', () => { + it('should handle synchronous migrations', () => { + const panel = new PanelPlugin(() =>
Panel
); + const mockMigration = () => ({ + newOption: 'migrated', + }); + + panel.setMigrationHandler(mockMigration); + + const migrationModel: PanelMigrationModel = { + id: 1, + type: 'test-panel', + options: { oldOption: 'value' }, + fieldConfig: { defaults: {}, overrides: [] }, + pluginVersion: '1.0.0', + }; + + expect(panel.onPanelMigration).toBeDefined(); + expect(panel.onPanelMigration!(migrationModel)).toEqual({ + newOption: 'migrated', + }); + }); + + it('should handle async migrations', async () => { + const panel = new PanelPlugin(() =>
Panel
); + const mockAsyncMigration = async () => { + return Promise.resolve({ + newOption: 'async-migrated', + }); + }; + + panel.setMigrationHandler(mockAsyncMigration); + + const migrationModel: PanelMigrationModel = { + id: 1, + type: 'test-panel', + options: { oldOption: 'value' }, + fieldConfig: { defaults: {}, overrides: [] }, + }; + + const result = await panel.onPanelMigration!(migrationModel); + expect(result).toEqual({ + newOption: 'async-migrated', + }); + }); + + it('should handle complex panel migrations with advanced transformations', () => { + const panel = new PanelPlugin(() =>
Panel
); + + const mockMigration = (model: PanelMigrationModel) => { + const { options, fieldConfig, title, id, type, pluginVersion } = model; + + //notice many of these migrations don't make sense in real code but are here + //to make sure the attributes of the PanelMigrationModel are used and tested + const baseMigration = { + ...options, + display: { + ...options.display, + mode: options.display?.type === 'legacy' ? 'modern' : options.display?.mode, + title: title?.toLowerCase() ?? 'untitled', + panelId: `${type}-${id}`, + }, + thresholds: options.thresholds?.map((t: { value: string | number; color: string }) => ({ + ...t, + value: typeof t.value === 'string' ? parseInt(t.value, 10) : t.value, + // Use fieldConfig defaults for threshold colors if available + color: fieldConfig.defaults?.color ?? t.color, + })), + metadata: { + migrationVersion: pluginVersion ? `${pluginVersion} -> 2.0.0` : '2.0.0', + migratedFields: Object.keys(fieldConfig.defaults ?? {}), + overrideCount: fieldConfig.overrides?.length ?? 0, + }, + // Merge custom field defaults into options + customDefaults: fieldConfig.defaults?.custom ?? {}, + // Transform overrides into a map + overrideMap: fieldConfig.overrides?.reduce( + (acc, override) => ({ + ...acc, + [override.matcher.id]: override.properties, + }), + {} + ), + }; + + // Apply panel type specific migrations + if (type.includes('visualization')) { + return { + ...baseMigration, + visualizationSpecific: { + enhanced: true, + legacyFormat: false, + }, + }; + } + + return baseMigration; + }; + + panel.setMigrationHandler(mockMigration); + + const complexModel: PanelMigrationModel = { + id: 123, + type: 'visualization-panel', + title: 'Complex METRICS', + pluginVersion: '1.0.0', + options: { + display: { + type: 'legacy', + showHeader: true, + }, + thresholds: [ + { value: '90', color: 'red' }, + { value: '50', color: 'yellow' }, + ], + queries: ['A', 'B'], + }, + fieldConfig: { + defaults: { + color: { mode: 'thresholds' }, + custom: { + lineWidth: 1, + fillOpacity: 0.5, + }, + mappings: [], + }, + overrides: [ + { + matcher: { id: 'byName', options: 'cpu' }, + properties: [{ id: 'color', value: 'red' }], + }, + { + matcher: { id: 'byValue', options: 'memory' }, + properties: [{ id: 'unit', value: 'bytes' }], + }, + ], + }, + }; + + const result = panel.onPanelMigration!(complexModel); + + expect(result).toMatchObject({ + display: { + mode: 'modern', + showHeader: true, + title: 'complex metrics', + panelId: 'visualization-panel-123', + }, + thresholds: [ + { value: 90, color: { mode: 'thresholds' } }, + { value: 50, color: { mode: 'thresholds' } }, + ], + queries: ['A', 'B'], + metadata: { + migrationVersion: '1.0.0 -> 2.0.0', + migratedFields: ['color', 'custom', 'mappings'], + overrideCount: 2, + }, + customDefaults: { + lineWidth: 1, + fillOpacity: 0.5, + }, + overrideMap: { + byName: [{ id: 'color', value: 'red' }], + byValue: [{ id: 'unit', value: 'bytes' }], + }, + visualizationSpecific: { + enhanced: true, + legacyFormat: false, + }, + }); + }); + }); }); diff --git a/packages/grafana-data/src/types/panel.ts b/packages/grafana-data/src/types/panel.ts index 7cfe9263ce3..91083493c83 100644 --- a/packages/grafana-data/src/types/panel.ts +++ b/packages/grafana-data/src/types/panel.ts @@ -134,12 +134,32 @@ export interface PanelEditorProps { data?: PanelData; } +/** + * This type mirrors the required properties from PanelModel needed for migration handlers. + * + * By maintaining a separate type definition, we ensure that changes to PanelModel + * that would break third-party migration handlers are caught at compile time, + * rather than failing silently when third-party code attempts to use an incompatible panel. + * + * TOptions must be any to follow the same pattern as PanelModel + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export interface PanelMigrationModel { + id: number; + type: string; + title?: string; + options: TOptions; + fieldConfig: PanelModel['fieldConfig']; + pluginVersion?: string; + targets?: PanelModel['targets']; +} + /** * Called when a panel is first loaded with current panel model to migrate panel options if needed. * Can return panel options, or a Promise that resolves to panel options for async migrations */ export type PanelMigrationHandler = ( - panel: PanelModel + panel: PanelMigrationModel ) => Partial | Promise>; /** From f62d9db29f55bdf3cabd58601d530ef8f83b2149 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 10:51:26 +0000 Subject: [PATCH 09/38] Update dependency msw to v2.6.9 (#98012) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index cfb12ec49ad..5711eebb24c 100644 --- a/package.json +++ b/package.json @@ -211,7 +211,7 @@ "knip": "^5.10.0", "lerna": "8.1.8", "mini-css-extract-plugin": "2.9.2", - "msw": "2.6.8", + "msw": "2.6.9", "mutationobserver-shim": "0.3.7", "ngtemplate-loader": "2.1.0", "node-notifier": "10.0.1", diff --git a/yarn.lock b/yarn.lock index 7ca1d85809a..030863fa1dd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17784,7 +17784,7 @@ __metadata: moment-timezone: "npm:0.5.46" monaco-editor: "npm:0.34.1" moveable: "npm:0.53.0" - msw: "npm:2.6.8" + msw: "npm:2.6.9" mutationobserver-shim: "npm:0.3.7" nanoid: "npm:^5.0.4" ngtemplate-loader: "npm:2.1.0" @@ -22253,9 +22253,9 @@ __metadata: languageName: node linkType: hard -"msw@npm:2.6.8": - version: 2.6.8 - resolution: "msw@npm:2.6.8" +"msw@npm:2.6.9": + version: 2.6.9 + resolution: "msw@npm:2.6.9" dependencies: "@bundled-es-modules/cookie": "npm:^2.0.1" "@bundled-es-modules/statuses": "npm:^1.0.1" @@ -22282,7 +22282,7 @@ __metadata: optional: true bin: msw: cli/index.js - checksum: 10/35d551c0fffe8b12cf174ae70ea8560bcc2e67f8887f20b43c7a3903ad4dc4272dc1c92f9ae68d30ad56435b391bcc5379495b1f9f0badcd4f2fdb614fbf7244 + checksum: 10/20a74a5e49b780567aa3430c0de9f27830208f931d6109087a24566fcb3e68f058ff51b022891bfe6fe0f320afad22b4039593722b928aa9c4ab5b05c2746c4a languageName: node linkType: hard From 06c0fa70c2b2aaf562a045968a588a4d07f3c101 Mon Sep 17 00:00:00 2001 From: Ezequiel Victorero Date: Mon, 16 Dec 2024 07:53:52 -0300 Subject: [PATCH 10/38] Docs: Update reporting attachment config description (#97847) Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --- docs/sources/dashboards/create-reports/index.md | 2 +- .../configure-grafana/enterprise-configuration/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sources/dashboards/create-reports/index.md b/docs/sources/dashboards/create-reports/index.md index 0e083ff75e4..56efdfda8ca 100644 --- a/docs/sources/dashboards/create-reports/index.md +++ b/docs/sources/dashboards/create-reports/index.md @@ -317,7 +317,7 @@ concurrent_render_limit = 4 # Set the scale factor for rendering images. 2 is enough for monitor resolutions # 4 would be better for printed material. Setting a higher value affects performance and memory image_scale_factor = 2 -# Set the maximum file size in megabytes for the CSV attachments +# Set the maximum file size in megabytes for the report email attachments max_attachment_size_mb = 10 # Path to the directory containing font files fonts_path = diff --git a/docs/sources/setup-grafana/configure-grafana/enterprise-configuration/index.md b/docs/sources/setup-grafana/configure-grafana/enterprise-configuration/index.md index 5aaaa2253a6..eaeb1527c3d 100644 --- a/docs/sources/setup-grafana/configure-grafana/enterprise-configuration/index.md +++ b/docs/sources/setup-grafana/configure-grafana/enterprise-configuration/index.md @@ -152,7 +152,7 @@ Scale factor for rendering images. Value `2` is enough for monitor resolutions, ### max_attachment_size_mb -Set the maximum file size in megabytes for the CSV attachments. +Set the maximum file size in megabytes for the report email attachments. ### fonts_path From 22dbde3126e0d0a9ae8a9af533604c7ed682799d Mon Sep 17 00:00:00 2001 From: Jack Baldry Date: Mon, 16 Dec 2024 11:01:54 +0000 Subject: [PATCH 11/38] Don't run PR preview on forks (#97963) --- .github/workflows/deploy-pr-preview.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy-pr-preview.yml b/.github/workflows/deploy-pr-preview.yml index 370351f99c0..348d79efedc 100644 --- a/.github/workflows/deploy-pr-preview.yml +++ b/.github/workflows/deploy-pr-preview.yml @@ -11,6 +11,7 @@ on: jobs: deploy-pr-preview: + if: github.repository == 'grafana/grafana' uses: grafana/writers-toolkit/.github/workflows/deploy-preview.yml@main with: sha: ${{ github.event.pull_request.head.sha }} @@ -20,4 +21,4 @@ jobs: repo: grafana website_directory: content/docs/grafana/latest relative_prefix: /docs/grafana/latest/ - index_file: true \ No newline at end of file + index_file: true From c983af175514eaa9935196a36ea91f504dc5064a Mon Sep 17 00:00:00 2001 From: Pepe Cano <825430+ppcano@users.noreply.github.com> Date: Mon, 16 Dec 2024 12:08:10 +0100 Subject: [PATCH 12/38] Alerting docs: `reorder rules` action in DS rules (#97974) Alerting docs (minor) - mention `reorder rules` action in DS rules --- .../alerting-rules/create-data-source-managed-rule.md | 2 +- .../create-data-source-managed-recording-rules.md | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/sources/alerting/alerting-rules/create-data-source-managed-rule.md b/docs/sources/alerting/alerting-rules/create-data-source-managed-rule.md index 04d079125e3..582a2d84130 100644 --- a/docs/sources/alerting/alerting-rules/create-data-source-managed-rule.md +++ b/docs/sources/alerting/alerting-rules/create-data-source-managed-rule.md @@ -129,7 +129,7 @@ Use [alert rule evaluation](ref:alert-rule-evaluation) to determine how frequent If you are creating a new evaluation group, specify the interval for the group. - All rules within the same group are evaluated sequentially over the same time interval. + All rules within the same group are evaluated sequentially over the same time interval. You can reorder them from the **Alert rules** page. 1. Enter a pending period. diff --git a/docs/sources/alerting/alerting-rules/create-recording-rules/create-data-source-managed-recording-rules.md b/docs/sources/alerting/alerting-rules/create-recording-rules/create-data-source-managed-recording-rules.md index 9abbc0219d3..375268e520c 100644 --- a/docs/sources/alerting/alerting-rules/create-recording-rules/create-data-source-managed-recording-rules.md +++ b/docs/sources/alerting/alerting-rules/create-recording-rules/create-data-source-managed-recording-rules.md @@ -66,7 +66,9 @@ Select your data source and enter a query. The queries used in data source-manag 1. From the **Group** dropdown, select an existing group within the selected namespace or add a new one. - Newly created rules are appended to the end of the group. Rules within a group are run sequentially at a regular interval, with the same evaluation time. + Rules within a group are run sequentially at a regular interval, with the same evaluation time. + + Newly created rules are appended to the end of the group, and you can reorder them from the **Alert rules** page. ## Add labels From 9f416e14288093df4e9e246c0790e6a95fb18211 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 11:18:17 +0000 Subject: [PATCH 13/38] Update dependency prettier to v3.4.2 (#97972) * Update dependency prettier to v3.4.2 * run prettier --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Ashley Harrison --- package.json | 4 ++-- packages/grafana-icons/package.json | 2 +- packages/grafana-prometheus/package.json | 2 +- public/app/features/playlist/PlaylistSrv.ts | 6 +++--- yarn.lock | 16 ++++++++-------- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index 5711eebb24c..e43dffec32a 100644 --- a/package.json +++ b/package.json @@ -220,7 +220,7 @@ "postcss-loader": "8.1.1", "postcss-reporter": "7.1.0", "postcss-scss": "4.0.9", - "prettier": "3.3.3", + "prettier": "3.4.2", "pseudoizer": "^0.1.0", "react-refresh": "0.14.0", "react-select-event": "5.5.1", @@ -452,7 +452,7 @@ }, "packageManager": "yarn@4.5.3", "dependenciesMeta": { - "prettier@3.3.3": { + "prettier@3.4.2": { "unplugged": true } }, diff --git a/packages/grafana-icons/package.json b/packages/grafana-icons/package.json index 4b1f5bc29cb..cf6f78f7810 100644 --- a/packages/grafana-icons/package.json +++ b/packages/grafana-icons/package.json @@ -49,7 +49,7 @@ "@types/react": "18.3.3", "@types/react-dom": "18.2.25", "esbuild": "0.24.0", - "prettier": "3.3.3", + "prettier": "3.4.2", "react": "18.2.0", "react-dom": "18.2.0", "rimraf": "6.0.1", diff --git a/packages/grafana-prometheus/package.json b/packages/grafana-prometheus/package.json index 740fd985222..90e251a8c02 100644 --- a/packages/grafana-prometheus/package.json +++ b/packages/grafana-prometheus/package.json @@ -121,7 +121,7 @@ "jest": "29.7.0", "jest-environment-jsdom": "29.7.0", "jest-matcher-utils": "29.7.0", - "prettier": "3.3.3", + "prettier": "3.4.2", "react": "18.2.0", "react-dom": "18.2.0", "react-select-event": "5.5.1", diff --git a/public/app/features/playlist/PlaylistSrv.ts b/public/app/features/playlist/PlaylistSrv.ts index c193de2a032..d11f817a369 100644 --- a/public/app/features/playlist/PlaylistSrv.ts +++ b/public/app/features/playlist/PlaylistSrv.ts @@ -25,10 +25,10 @@ export class PlaylistSrv extends StateManagerBase { private nextTimeoutId: ReturnType | undefined; private urls: string[] = []; // the URLs we need to load private index = 0; - private declare interval: number; - private declare startUrl: string; + declare private interval: number; + declare private startUrl: string; private numberOfLoops = 0; - private declare validPlaylistUrl: string; + declare private validPlaylistUrl: string; private locationListenerUnsub?: () => void; private api: PlaylistAPI; diff --git a/yarn.lock b/yarn.lock index 030863fa1dd..8c1c91d0d8d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3696,7 +3696,7 @@ __metadata: moment-timezone: "npm:0.5.46" monaco-promql: "npm:1.7.4" pluralize: "npm:8.0.0" - prettier: "npm:3.3.3" + prettier: "npm:3.4.2" prismjs: "npm:1.29.0" react: "npm:18.2.0" react-dom: "npm:18.2.0" @@ -3791,7 +3791,7 @@ __metadata: "@types/react": "npm:18.3.3" "@types/react-dom": "npm:18.2.25" esbuild: "npm:0.24.0" - prettier: "npm:3.3.3" + prettier: "npm:3.4.2" react: "npm:18.2.0" react-dom: "npm:18.2.0" rimraf: "npm:6.0.1" @@ -17798,7 +17798,7 @@ __metadata: postcss-loader: "npm:8.1.1" postcss-reporter: "npm:7.1.0" postcss-scss: "npm:4.0.9" - prettier: "npm:3.3.3" + prettier: "npm:3.4.2" prismjs: "npm:1.29.0" pseudoizer: "npm:^0.1.0" rc-slider: "npm:11.1.7" @@ -17887,7 +17887,7 @@ __metadata: yaml: "npm:^2.0.0" yargs: "npm:^17.5.1" dependenciesMeta: - prettier@3.3.3: + prettier@3.4.2: unplugged: true languageName: unknown linkType: soft @@ -24438,12 +24438,12 @@ __metadata: languageName: node linkType: hard -"prettier@npm:3.3.3, prettier@npm:^3.1.1": - version: 3.3.3 - resolution: "prettier@npm:3.3.3" +"prettier@npm:3.4.2, prettier@npm:^3.1.1": + version: 3.4.2 + resolution: "prettier@npm:3.4.2" bin: prettier: bin/prettier.cjs - checksum: 10/5beac1f30b5b40162532b8e2f7c3a4eb650910a2695e9c8512a62ffdc09dae93190c29db9107fa7f26d1b6c71aad3628ecb9b5de1ecb0911191099be109434d7 + checksum: 10/a3e806fb0b635818964d472d35d27e21a4e17150c679047f5501e1f23bd4aa806adf660f0c0d35214a210d5d440da6896c2e86156da55f221a57938278dc326e languageName: node linkType: hard From b36b7ec18eaa45f6ebdec58f607ae55ea10c0e57 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 11:20:06 +0000 Subject: [PATCH 14/38] Update dependency eslint to v9.17.0 (#98014) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- packages/grafana-eslint-rules/package.json | 2 +- packages/grafana-plugin-configs/package.json | 2 +- packages/grafana-prometheus/package.json | 2 +- yarn.lock | 30 ++++++++++---------- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/package.json b/package.json index e43dffec32a..1a049dfc29a 100644 --- a/package.json +++ b/package.json @@ -175,7 +175,7 @@ "esbuild": "0.24.0", "esbuild-loader": "4.2.2", "esbuild-plugin-browserslist": "^0.15.0", - "eslint": "9.16.0", + "eslint": "9.17.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-import": "^2.31.0", "eslint-plugin-jest": "28.9.0", diff --git a/packages/grafana-eslint-rules/package.json b/packages/grafana-eslint-rules/package.json index ef60d8ce70c..ed5a49011b1 100644 --- a/packages/grafana-eslint-rules/package.json +++ b/packages/grafana-eslint-rules/package.json @@ -18,7 +18,7 @@ }, "devDependencies": { "@typescript-eslint/types": "^8.9.0", - "eslint": "9.16.0", + "eslint": "9.17.0", "tslib": "2.7.0" }, "private": true diff --git a/packages/grafana-plugin-configs/package.json b/packages/grafana-plugin-configs/package.json index 05150eb6c65..48e1c86dc58 100644 --- a/packages/grafana-plugin-configs/package.json +++ b/packages/grafana-plugin-configs/package.json @@ -12,7 +12,7 @@ "@types/eslint": "9.6.1", "@types/webpack-bundle-analyzer": "^4.7.0", "copy-webpack-plugin": "12.0.2", - "eslint": "9.16.0", + "eslint": "9.17.0", "eslint-webpack-plugin": "4.2.0", "fork-ts-checker-webpack-plugin": "9.0.2", "glob": "11.0.0", diff --git a/packages/grafana-prometheus/package.json b/packages/grafana-prometheus/package.json index 90e251a8c02..276829ec77c 100644 --- a/packages/grafana-prometheus/package.json +++ b/packages/grafana-prometheus/package.json @@ -106,7 +106,7 @@ "copy-webpack-plugin": "12.0.2", "css-loader": "7.1.2", "esbuild": "0.24.0", - "eslint": "9.16.0", + "eslint": "9.17.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-import": "^2.31.0", "eslint-plugin-jest": "28.9.0", diff --git a/yarn.lock b/yarn.lock index 8c1c91d0d8d..d8174f21d3a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2572,10 +2572,10 @@ __metadata: languageName: node linkType: hard -"@eslint/js@npm:9.16.0": - version: 9.16.0 - resolution: "@eslint/js@npm:9.16.0" - checksum: 10/122da09b6a2c6a92d68be26146af1da17d9d4e03cf9435a874d341f18519122eef9ed229e52a1b781dc5987239754954e80a0b11bbe8f65df96e9ef8f3b438ad +"@eslint/js@npm:9.17.0": + version: 9.17.0 + resolution: "@eslint/js@npm:9.17.0" + checksum: 10/1a89e62f5c50e75d44565b7f3b91701455a999132c991e10bac59c118fbb54bdd54be22b9bda1ac730f78a2e64604403d65ce5dd7726d80b2632982cfc3d84ac languageName: node linkType: hard @@ -3363,7 +3363,7 @@ __metadata: dependencies: "@typescript-eslint/types": "npm:^8.9.0" "@typescript-eslint/utils": "npm:^8.9.0" - eslint: "npm:9.16.0" + eslint: "npm:9.17.0" tslib: "npm:2.7.0" languageName: unknown linkType: soft @@ -3592,7 +3592,7 @@ __metadata: "@types/eslint": "npm:9.6.1" "@types/webpack-bundle-analyzer": "npm:^4.7.0" copy-webpack-plugin: "npm:12.0.2" - eslint: "npm:9.16.0" + eslint: "npm:9.17.0" eslint-webpack-plugin: "npm:4.2.0" fork-ts-checker-webpack-plugin: "npm:9.0.2" glob: "npm:11.0.0" @@ -3672,7 +3672,7 @@ __metadata: date-fns: "npm:3.6.0" debounce-promise: "npm:3.1.2" esbuild: "npm:0.24.0" - eslint: "npm:9.16.0" + eslint: "npm:9.17.0" eslint-config-prettier: "npm:9.1.0" eslint-plugin-import: "npm:^2.31.0" eslint-plugin-jest: "npm:28.9.0" @@ -13385,7 +13385,7 @@ __metadata: languageName: node linkType: hard -"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.5": +"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" dependencies: @@ -15972,16 +15972,16 @@ __metadata: languageName: node linkType: hard -"eslint@npm:9.16.0": - version: 9.16.0 - resolution: "eslint@npm:9.16.0" +"eslint@npm:9.17.0": + version: 9.17.0 + resolution: "eslint@npm:9.17.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.2.0" "@eslint-community/regexpp": "npm:^4.12.1" "@eslint/config-array": "npm:^0.19.0" "@eslint/core": "npm:^0.9.0" "@eslint/eslintrc": "npm:^3.2.0" - "@eslint/js": "npm:9.16.0" + "@eslint/js": "npm:9.17.0" "@eslint/plugin-kit": "npm:^0.2.3" "@humanfs/node": "npm:^0.16.6" "@humanwhocodes/module-importer": "npm:^1.0.1" @@ -15990,7 +15990,7 @@ __metadata: "@types/json-schema": "npm:^7.0.15" ajv: "npm:^6.12.4" chalk: "npm:^4.0.0" - cross-spawn: "npm:^7.0.5" + cross-spawn: "npm:^7.0.6" debug: "npm:^4.3.2" escape-string-regexp: "npm:^4.0.0" eslint-scope: "npm:^8.2.0" @@ -16017,7 +16017,7 @@ __metadata: optional: true bin: eslint: bin/eslint.js - checksum: 10/b47a34392a55bc08594ee2fed2777d7aff96f38b584791ccded44d88b72795acfe15b18643fd4046f680734a1f16244d554f34a485f660fa723e25d609fb12ba + checksum: 10/a48ee67dd4e737974bbb49ca5d12d0ce35bcd874507807599e3655bb398320ab27c9deed1aad508a963967815e626c21208f52158c2fc0796d0cc8186528efeb languageName: node linkType: hard @@ -17718,7 +17718,7 @@ __metadata: esbuild: "npm:0.24.0" esbuild-loader: "npm:4.2.2" esbuild-plugin-browserslist: "npm:^0.15.0" - eslint: "npm:9.16.0" + eslint: "npm:9.17.0" eslint-config-prettier: "npm:9.1.0" eslint-plugin-import: "npm:^2.31.0" eslint-plugin-jest: "npm:28.9.0" From ed3eacced96239d09b07e5aa16dfb07c9e93fec3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 13:23:24 +0200 Subject: [PATCH 15/38] Update dependency rc-cascader to v3.31.0 (#98015) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- packages/grafana-ui/package.json | 2 +- yarn.lock | 30 +++++++++++++++++++++++------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index 60cb2105c49..cd1cb51358d 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -83,7 +83,7 @@ "monaco-editor": "0.34.1", "ol": "7.4.0", "prismjs": "1.29.0", - "rc-cascader": "3.30.0", + "rc-cascader": "3.31.0", "rc-drawer": "7.2.0", "rc-slider": "11.1.7", "rc-time-picker": "^3.7.3", diff --git a/yarn.lock b/yarn.lock index d8174f21d3a..262e4238d7e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4015,7 +4015,7 @@ __metadata: ol: "npm:7.4.0" prismjs: "npm:1.29.0" process: "npm:^0.11.10" - rc-cascader: "npm:3.30.0" + rc-cascader: "npm:3.31.0" rc-drawer: "npm:7.2.0" rc-slider: "npm:11.1.7" rc-time-picker: "npm:^3.7.3" @@ -24952,19 +24952,19 @@ __metadata: languageName: node linkType: hard -"rc-cascader@npm:3.30.0": - version: 3.30.0 - resolution: "rc-cascader@npm:3.30.0" +"rc-cascader@npm:3.31.0": + version: 3.31.0 + resolution: "rc-cascader@npm:3.31.0" dependencies: "@babel/runtime": "npm:^7.25.7" classnames: "npm:^2.3.1" rc-select: "npm:~14.16.2" - rc-tree: "npm:~5.10.1" + rc-tree: "npm:~5.11.0" rc-util: "npm:^5.43.0" peerDependencies: react: ">=16.9.0" react-dom: ">=16.9.0" - checksum: 10/c4ed8e122ad2dcc37fb1b190f4514fc040bf60b74bf90735c7485054978687387c039a977b151b28164fd41301f073c5491acd8557cd8841c9cd71c19b8166ee + checksum: 10/e0ffd71141630cd2f813a44ae9df57495c0118a80785a05e8faef374ea2a49a1ab6f5f21584f57911c22611c1431be2d76bd3d0c9b304d95931ac6fb2f5e0ad5 languageName: node linkType: hard @@ -25088,7 +25088,7 @@ __metadata: languageName: node linkType: hard -"rc-tree@npm:5.10.1, rc-tree@npm:~5.10.1": +"rc-tree@npm:5.10.1": version: 5.10.1 resolution: "rc-tree@npm:5.10.1" dependencies: @@ -25104,6 +25104,22 @@ __metadata: languageName: node linkType: hard +"rc-tree@npm:~5.11.0": + version: 5.11.0 + resolution: "rc-tree@npm:5.11.0" + dependencies: + "@babel/runtime": "npm:^7.10.1" + classnames: "npm:2.x" + rc-motion: "npm:^2.0.1" + rc-util: "npm:^5.16.1" + rc-virtual-list: "npm:^3.5.1" + peerDependencies: + react: "*" + react-dom: "*" + checksum: 10/d1a8d544354c4345a352811e5db57a10b1e7c2bf237bc394eb94256bdfc071fc0aefd6b201fe526d127e315b1ed2ab4ca7a363a05ab2d12a12fafcf7fdcbdf05 + languageName: node + linkType: hard + "rc-trigger@npm:^2.2.0": version: 2.6.5 resolution: "rc-trigger@npm:2.6.5" From 3af96acc121571718bdeaf24fa9d83321a647215 Mon Sep 17 00:00:00 2001 From: Matheus Macabu Date: Mon, 2 Dec 2024 16:25:00 +0100 Subject: [PATCH 16/38] UsageInsights: Include panelId and panelName in events when available --- packages/grafana-data/src/types/datasource.ts | 1 + .../features/dashboard-scene/scene/DashboardScene.test.tsx | 2 ++ .../app/features/dashboard-scene/scene/DashboardScene.tsx | 1 + public/app/features/dashboard/state/PanelModel.ts | 1 + public/app/features/query/state/PanelQueryRunner.test.ts | 6 ++++++ public/app/features/query/state/PanelQueryRunner.ts | 6 ++++++ public/app/features/query/state/queryAnalytics.test.ts | 6 ++++++ public/app/features/query/state/queryAnalytics.ts | 5 ++--- 8 files changed, 25 insertions(+), 3 deletions(-) diff --git a/packages/grafana-data/src/types/datasource.ts b/packages/grafana-data/src/types/datasource.ts index 11fdd815a00..2db63544741 100644 --- a/packages/grafana-data/src/types/datasource.ts +++ b/packages/grafana-data/src/types/datasource.ts @@ -557,6 +557,7 @@ export interface DataQueryRequest { rangeRaw?: RawTimeRange; timeInfo?: string; // The query time description (blue text in the upper right) panelId?: number; + panelName?: string; panelPluginId?: string; dashboardUID?: string; headers?: Record; diff --git a/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx b/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx index 19a1a023f3d..8e70170c3ff 100644 --- a/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx @@ -638,6 +638,7 @@ describe('DashboardScene', () => { app: CoreApp.Dashboard, dashboardUID: 'dash-1', panelId: 1, + panelName: 'Panel A', panelPluginId: 'table', }); }); @@ -653,6 +654,7 @@ describe('DashboardScene', () => { app: CoreApp.Dashboard, dashboardUID: 'dash-1', panelId: 1, + panelName: 'Panel A', panelPluginId: 'table', }); }); diff --git a/public/app/features/dashboard-scene/scene/DashboardScene.tsx b/public/app/features/dashboard-scene/scene/DashboardScene.tsx index 94ad83c9e3f..edb9303fa1f 100644 --- a/public/app/features/dashboard-scene/scene/DashboardScene.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardScene.tsx @@ -620,6 +620,7 @@ export class DashboardScene extends SceneObjectBase { app: CoreApp.Dashboard, dashboardUID: this.state.uid, panelId, + panelName: panel?.state?.title, panelPluginId: panel?.state.pluginId, scopes: this._scopesFacade?.value, }; diff --git a/public/app/features/dashboard/state/PanelModel.ts b/public/app/features/dashboard/state/PanelModel.ts index b8ca782906c..1ad7b07c086 100644 --- a/public/app/features/dashboard/state/PanelModel.ts +++ b/public/app/features/dashboard/state/PanelModel.ts @@ -380,6 +380,7 @@ export class PanelModel implements DataConfigSource, IPanelModel { datasource: this.datasource, queries: this.targets, panelId: this.id, + panelName: this.title, panelPluginId: this.type, dashboardUID: dashboardUID, timezone: dashboardTimezone, diff --git a/public/app/features/query/state/PanelQueryRunner.test.ts b/public/app/features/query/state/PanelQueryRunner.test.ts index e57cc8ea7a1..a870bfb3d40 100644 --- a/public/app/features/query/state/PanelQueryRunner.test.ts +++ b/public/app/features/query/state/PanelQueryRunner.test.ts @@ -160,6 +160,7 @@ function describeQueryRunnerScenario( raw: { from: '1d', to: 'now' }, }, panelId: 1, + panelName: 'PanelName', queries: [{ refId: 'A' }], } as QueryRunnerOptions; @@ -198,6 +199,11 @@ describe('PanelQueryRunner', () => { expect(ctx.queryCalledWith?.scopedVars.__interval!.text).toBe('5m'); expect(ctx.queryCalledWith?.scopedVars.__interval_ms!.text).toBe('300000'); }); + + it('should pass the panel id and name', async () => { + expect(ctx.queryCalledWith?.panelId).toBe(1); + expect(ctx.queryCalledWith?.panelName).toBe('PanelName'); + }); }); describeQueryRunnerScenario('with maxDataPoints', (ctx) => { diff --git a/public/app/features/query/state/PanelQueryRunner.ts b/public/app/features/query/state/PanelQueryRunner.ts index 329d4186a8e..ffefaf7b4f1 100644 --- a/public/app/features/query/state/PanelQueryRunner.ts +++ b/public/app/features/query/state/PanelQueryRunner.ts @@ -50,6 +50,7 @@ export interface QueryRunnerOptions< datasource: DataSourceRef | DataSourceApi | null; queries: TQuery[]; panelId?: number; + panelName?: string; panelPluginId?: string; dashboardUID?: string; timezone: TimeZone; @@ -258,6 +259,7 @@ export class PanelQueryRunner { timezone, datasource, panelId, + panelName, panelPluginId, dashboardUID, timeRange, @@ -283,6 +285,7 @@ export class PanelQueryRunner { requestId: getNextRequestId(), timezone, panelId, + panelName, panelPluginId, dashboardUID, range: timeRange, @@ -328,6 +331,9 @@ export class PanelQueryRunner { request.intervalMs = norm.intervalMs; request.filters = this.templateSrv.getAdhocFilters(ds.name, true); + request.panelId = panelId; + request.panelName = panelName; + this.lastRequest = request; this.pipeToSubject(runRequest(ds, request), panelId, false, addErroDSVariable); diff --git a/public/app/features/query/state/queryAnalytics.test.ts b/public/app/features/query/state/queryAnalytics.test.ts index 3e450b21b17..2b0863132b2 100644 --- a/public/app/features/query/state/queryAnalytics.test.ts +++ b/public/app/features/query/state/queryAnalytics.test.ts @@ -118,6 +118,7 @@ describe('emitDataRequestEvent', () => { it('Should report meta analytics', () => { const data = getTestData({ panelId: 2, + panelName: 'Panel Name2', }); emitDataRequestEvent(datasource)(data); @@ -130,6 +131,7 @@ describe('emitDataRequestEvent', () => { datasourceType: datasource.type, source: CoreApp.Dashboard, panelId: 2, + panelName: 'Panel Name2', dashboardUid: 'test', // from dashboard srv dataSize: 0, duration: 1, @@ -144,6 +146,7 @@ describe('emitDataRequestEvent', () => { const data = getTestData( { panelId: 2, + panelName: 'Panel Name2', }, partiallyCachedSeries ); @@ -158,6 +161,7 @@ describe('emitDataRequestEvent', () => { datasourceType: datasource.type, source: CoreApp.Dashboard, panelId: 2, + panelName: 'Panel Name2', dashboardUid: 'test', dataSize: 2, duration: 1, @@ -172,6 +176,7 @@ describe('emitDataRequestEvent', () => { const data = getTestData( { panelId: 2, + panelName: 'Panel Name2', }, multipleDataframesWithSameRefId ); @@ -186,6 +191,7 @@ describe('emitDataRequestEvent', () => { datasourceType: datasource.type, source: CoreApp.Dashboard, panelId: 2, + panelName: 'Panel Name2', dashboardUid: 'test', // from dashboard srv dataSize: 2, duration: 1, diff --git a/public/app/features/query/state/queryAnalytics.ts b/public/app/features/query/state/queryAnalytics.ts index 337fe6d4b00..cdc6057f2db 100644 --- a/public/app/features/query/state/queryAnalytics.ts +++ b/public/app/features/query/state/queryAnalytics.ts @@ -31,6 +31,8 @@ export function emitDataRequestEvent(datasource: DataSourceApi) { panelId: 0, panelPluginId: data.request?.panelPluginId, duration: data.request.endTime! - data.request.startTime, + ...(data?.request?.panelId && Number.isInteger(data.request.panelId) && { panelId: data.request.panelId }), + ...(data?.request?.panelName && { panelName: data.request.panelName }), }; enrichWithInfo(eventData, data); @@ -62,9 +64,6 @@ export function emitDataRequestEvent(datasource: DataSourceApi) { eventData.totalQueries = Object.keys(queryCacheStatus).length; eventData.cachedQueries = Object.values(queryCacheStatus).filter((val) => val === true).length; - if (data.request && Number.isInteger(data.request.panelId)) { - eventData.panelId = data.request.panelId; - } const dashboard = getDashboardSrv().getCurrent(); if (dashboard) { From 954bd9f312d518e8968b6361f97415fc2968ad93 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 11:57:53 +0000 Subject: [PATCH 17/38] Update dependency @floating-ui/react to v0.27.2 (#98011) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- packages/grafana-prometheus/package.json | 2 +- packages/grafana-ui/package.json | 2 +- yarn.lock | 14 +++++++------- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 1a049dfc29a..340dde42837 100644 --- a/package.json +++ b/package.json @@ -256,7 +256,7 @@ "@emotion/css": "11.13.5", "@emotion/react": "11.14.0", "@fingerprintjs/fingerprintjs": "^3.4.2", - "@floating-ui/react": "0.27.1", + "@floating-ui/react": "0.27.2", "@formatjs/intl-durationformat": "^0.7.0", "@glideapps/glide-data-grid": "^6.0.0", "@grafana/aws-sdk": "0.5.0", diff --git a/packages/grafana-prometheus/package.json b/packages/grafana-prometheus/package.json index 276829ec77c..8059b2414ca 100644 --- a/packages/grafana-prometheus/package.json +++ b/packages/grafana-prometheus/package.json @@ -37,7 +37,7 @@ }, "dependencies": { "@emotion/css": "11.13.5", - "@floating-ui/react": "0.27.1", + "@floating-ui/react": "0.27.2", "@grafana/data": "11.5.0-pre", "@grafana/experimental": "2.1.5", "@grafana/faro-web-sdk": "1.12.2", diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index cd1cb51358d..3a8731a5746 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -49,7 +49,7 @@ "@emotion/css": "11.13.5", "@emotion/react": "11.14.0", "@emotion/serialize": "1.3.3", - "@floating-ui/react": "0.27.1", + "@floating-ui/react": "0.27.2", "@grafana/data": "11.5.0-pre", "@grafana/e2e-selectors": "11.5.0-pre", "@grafana/faro-web-sdk": "^1.3.6", diff --git a/yarn.lock b/yarn.lock index 262e4238d7e..25eaa8dee5b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2649,9 +2649,9 @@ __metadata: languageName: node linkType: hard -"@floating-ui/react@npm:0.27.1": - version: 0.27.1 - resolution: "@floating-ui/react@npm:0.27.1" +"@floating-ui/react@npm:0.27.2": + version: 0.27.2 + resolution: "@floating-ui/react@npm:0.27.2" dependencies: "@floating-ui/react-dom": "npm:^2.1.2" "@floating-ui/utils": "npm:^0.2.8" @@ -2659,7 +2659,7 @@ __metadata: peerDependencies: react: ">=17.0.0" react-dom: ">=17.0.0" - checksum: 10/18262251e729f7496627a9ea14eabdc7e3d1031a8dc2b08e2f8613240b5a515c0970b87367df858c715240da384711a0620a522287d85390cc2da023571012e3 + checksum: 10/c9ff0d7216cc7b51f066e8927852ba014bf51c79e48a1837f99760750df37fc3ed010dcdc89e57e673e2740e3bd2b91ccdcc6ccd13ec927950110a18b6b9cefa languageName: node linkType: hard @@ -3625,7 +3625,7 @@ __metadata: dependencies: "@emotion/css": "npm:11.13.5" "@emotion/eslint-plugin": "npm:11.12.0" - "@floating-ui/react": "npm:0.27.1" + "@floating-ui/react": "npm:0.27.2" "@grafana/data": "npm:11.5.0-pre" "@grafana/e2e-selectors": "npm:11.5.0-pre" "@grafana/experimental": "npm:2.1.5" @@ -3928,7 +3928,7 @@ __metadata: "@emotion/react": "npm:11.14.0" "@emotion/serialize": "npm:1.3.3" "@faker-js/faker": "npm:^9.0.0" - "@floating-ui/react": "npm:0.27.1" + "@floating-ui/react": "npm:0.27.2" "@grafana/data": "npm:11.5.0-pre" "@grafana/e2e-selectors": "npm:11.5.0-pre" "@grafana/faro-web-sdk": "npm:^1.3.6" @@ -17550,7 +17550,7 @@ __metadata: "@emotion/eslint-plugin": "npm:11.12.0" "@emotion/react": "npm:11.14.0" "@fingerprintjs/fingerprintjs": "npm:^3.4.2" - "@floating-ui/react": "npm:0.27.1" + "@floating-ui/react": "npm:0.27.2" "@formatjs/intl-durationformat": "npm:^0.7.0" "@glideapps/glide-data-grid": "npm:^6.0.0" "@grafana/aws-sdk": "npm:0.5.0" From ccb2be5962ef3e3f5e37741d2fd00901aa4784c6 Mon Sep 17 00:00:00 2001 From: Sven Grossmann Date: Mon, 16 Dec 2024 12:58:36 +0100 Subject: [PATCH 18/38] Menu: Change left/right padding to `12px` (#97033) * Menu: Change left/right padding to `12px` * add border radius * fix wrong rebase --- packages/grafana-ui/src/components/Menu/MenuItem.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grafana-ui/src/components/Menu/MenuItem.tsx b/packages/grafana-ui/src/components/Menu/MenuItem.tsx index 31e46fd5580..c2a4654113a 100644 --- a/packages/grafana-ui/src/components/Menu/MenuItem.tsx +++ b/packages/grafana-ui/src/components/Menu/MenuItem.tsx @@ -222,8 +222,9 @@ const getStyles = (theme: GrafanaTheme2) => { flexDirection: 'column', alignItems: 'stretch', justifyContent: 'center', - padding: theme.spacing(0.5, 2), + padding: theme.spacing(0.5, 1.5), minHeight: theme.spacing(4), + borderRadius: theme.shape.radius.default, margin: 0, border: 'none', width: '100%', From d7e07d999341ac9ff192444bc698da9bc93e683c Mon Sep 17 00:00:00 2001 From: Gilles De Mey Date: Mon, 16 Dec 2024 13:26:55 +0100 Subject: [PATCH 19/38] Alerting: Fix missing instances and history when Grafana rule is stored in folder with / (#97956) --- .../alerting/unified/hooks/useFolder.test.ts | 27 +++++++++++++++++++ .../alerting/unified/hooks/useFolder.ts | 8 +++++- 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 public/app/features/alerting/unified/hooks/useFolder.test.ts diff --git a/public/app/features/alerting/unified/hooks/useFolder.test.ts b/public/app/features/alerting/unified/hooks/useFolder.test.ts new file mode 100644 index 00000000000..3c480cb464a --- /dev/null +++ b/public/app/features/alerting/unified/hooks/useFolder.test.ts @@ -0,0 +1,27 @@ +import { mockFolder } from '../mocks'; + +import { stringifyFolder } from './useFolder'; + +describe('with slashes', () => { + it('should correctly stringify a folder', () => { + const folder = mockFolder({ title: 'my/folder' }); + expect(stringifyFolder(folder)).toEqual('my\\/folder'); + }); + + it('should correctly stringify a nested folder', () => { + const folder = mockFolder({ title: 'my/folder', parents: [mockFolder({ title: 'parent/slash' })] }); + expect(stringifyFolder(folder)).toEqual('parent\\/slash/my\\/folder'); + }); +}); + +describe('without slashes', () => { + it('should correctly stringify a folder', () => { + const folder = mockFolder({ title: 'my folder' }); + expect(stringifyFolder(folder)).toEqual('my folder'); + }); + + it('should correctly stringify a nested folder', () => { + const folder = mockFolder({ title: 'my folder', parents: [mockFolder({ title: 'my parent' })] }); + expect(stringifyFolder(folder)).toEqual('my parent/my folder'); + }); +}); diff --git a/public/app/features/alerting/unified/hooks/useFolder.ts b/public/app/features/alerting/unified/hooks/useFolder.ts index e4fcd3882f8..8939ae8ad4c 100644 --- a/public/app/features/alerting/unified/hooks/useFolder.ts +++ b/public/app/features/alerting/unified/hooks/useFolder.ts @@ -34,5 +34,11 @@ export function useFolder(uid?: string): ReturnBag { } export function stringifyFolder({ title, parents }: FolderDTO) { - return parents && parents?.length ? [...parents.map((p) => p.title), title].join('/') : title; + return parents && parents?.length + ? [...parents.map((p) => p.title), title].map(encodeTitle).join('/') + : encodeTitle(title); +} + +export function encodeTitle(title: string): string { + return title.replaceAll('/', '\\/'); } From dee47bbef2e3c6f9476759f294724586e709ef3a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 12:36:03 +0000 Subject: [PATCH 20/38] Update dependency rc-tooltip to v6.3.1 (#98023) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- packages/grafana-ui/package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index 3a8731a5746..39377eb2920 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -87,7 +87,7 @@ "rc-drawer": "7.2.0", "rc-slider": "11.1.7", "rc-time-picker": "^3.7.3", - "rc-tooltip": "6.2.1", + "rc-tooltip": "6.3.1", "react-calendar": "^5.1.0", "react-colorful": "5.6.1", "react-custom-scrollbars-2": "4.5.0", diff --git a/yarn.lock b/yarn.lock index 25eaa8dee5b..e43c58a767e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4019,7 +4019,7 @@ __metadata: rc-drawer: "npm:7.2.0" rc-slider: "npm:11.1.7" rc-time-picker: "npm:^3.7.3" - rc-tooltip: "npm:6.2.1" + rc-tooltip: "npm:6.3.1" react: "npm:18.2.0" react-calendar: "npm:^5.1.0" react-colorful: "npm:5.6.1" @@ -25074,9 +25074,9 @@ __metadata: languageName: node linkType: hard -"rc-tooltip@npm:6.2.1": - version: 6.2.1 - resolution: "rc-tooltip@npm:6.2.1" +"rc-tooltip@npm:6.3.1": + version: 6.3.1 + resolution: "rc-tooltip@npm:6.3.1" dependencies: "@babel/runtime": "npm:^7.11.2" "@rc-component/trigger": "npm:^2.0.0" @@ -25084,7 +25084,7 @@ __metadata: peerDependencies: react: ">=16.9.0" react-dom: ">=16.9.0" - checksum: 10/a82064d6d521ba4c03d074505402f6c38f9f50439037235969546b694e38977bab3420b46080bde295aca2436e6725d64b0a330a5ccdd51932deabbb1bf7585b + checksum: 10/e871f4430ba3711edc002cb55cd189471ae353bc2262ce648d14148d2648efa0849af87e85a750d03b23532a56c506724a6756bef1d42dcd48d061ccdf0024d8 languageName: node linkType: hard From 1180ea07b77965c4ab1882a017acda0496a4174c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 12:36:29 +0000 Subject: [PATCH 21/38] Update dependency rc-tree to v5.11.0 (#98024) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 20 ++------------------ 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/package.json b/package.json index 340dde42837..c90a496be52 100644 --- a/package.json +++ b/package.json @@ -365,7 +365,7 @@ "prismjs": "1.29.0", "rc-slider": "11.1.7", "rc-time-picker": "3.7.3", - "rc-tree": "5.10.1", + "rc-tree": "5.11.0", "re-resizable": "6.10.3", "react": "18.2.0", "react-diff-viewer-continued": "^3.4.0", diff --git a/yarn.lock b/yarn.lock index e43c58a767e..ca23238a094 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17803,7 +17803,7 @@ __metadata: pseudoizer: "npm:^0.1.0" rc-slider: "npm:11.1.7" rc-time-picker: "npm:3.7.3" - rc-tree: "npm:5.10.1" + rc-tree: "npm:5.11.0" re-resizable: "npm:6.10.3" react: "npm:18.2.0" react-diff-viewer-continued: "npm:^3.4.0" @@ -25088,23 +25088,7 @@ __metadata: languageName: node linkType: hard -"rc-tree@npm:5.10.1": - version: 5.10.1 - resolution: "rc-tree@npm:5.10.1" - dependencies: - "@babel/runtime": "npm:^7.10.1" - classnames: "npm:2.x" - rc-motion: "npm:^2.0.1" - rc-util: "npm:^5.16.1" - rc-virtual-list: "npm:^3.5.1" - peerDependencies: - react: "*" - react-dom: "*" - checksum: 10/3fd1ad26ecce4435212aba83a87af8256805a8c2a3be3729995043848d7af267bcfc89dd09393fc5962f7a802b83184ad2736d407e18f007ce1a4c9ebd7a5629 - languageName: node - linkType: hard - -"rc-tree@npm:~5.11.0": +"rc-tree@npm:5.11.0, rc-tree@npm:~5.11.0": version: 5.11.0 resolution: "rc-tree@npm:5.11.0" dependencies: From 62c1735a61bbee3e817f09c7822c78555d76e919 Mon Sep 17 00:00:00 2001 From: Leonor Oliveira <9090754+leonorfmartins@users.noreply.github.com> Date: Mon, 16 Dec 2024 14:08:29 +0100 Subject: [PATCH 22/38] Implement k8s count handler (#97955) * Implement k8s count handler * Fix endpoint * Fix type converstions * Add tests for foldercounts * Add more tests * Only use sql-fallback if no values in unistore * Update gomod * Fix test * Update pkg/api/folder_test.go Co-authored-by: Bruno Abrantes * Go.mod --------- Co-authored-by: Bruno Abrantes --- pkg/api/folder.go | 52 +++++++++++- pkg/api/folder_test.go | 116 ++++++++++++++++++++++++++ pkg/apis/folder/v0alpha1/types.go | 8 ++ pkg/registry/apis/folders/register.go | 2 +- pkg/tests/apis/folder/folders_test.go | 2 +- 5 files changed, 174 insertions(+), 6 deletions(-) diff --git a/pkg/api/folder.go b/pkg/api/folder.go index 047923e7950..ffbe433e3fd 100644 --- a/pkg/api/folder.go +++ b/pkg/api/folder.go @@ -50,8 +50,6 @@ func (hs *HTTPServer) registerFolderAPI(apiRoute routing.RouteRegister, authoriz folderRoute.Group("/:uid", func(folderUidRoute routing.RouteRegister) { folderUidRoute.Post("/move", authorize(accesscontrol.EvalPermission(dashboards.ActionFoldersWrite, uidScope)), routing.Wrap(hs.MoveFolder)) - folderUidRoute.Get("/counts", authorize(accesscontrol.EvalPermission(dashboards.ActionFoldersRead, uidScope)), routing.Wrap(hs.GetFolderDescendantCounts)) - folderUidRoute.Group("/permissions", func(folderPermissionRoute routing.RouteRegister) { folderPermissionRoute.Get("/", authorize(accesscontrol.EvalPermission(dashboards.ActionFoldersPermissionsRead, uidScope)), routing.Wrap(hs.GetFolderPermissionList)) folderPermissionRoute.Post("/", authorize(accesscontrol.EvalPermission(dashboards.ActionFoldersPermissionsWrite, uidScope)), routing.Wrap(hs.UpdateFolderPermissions)) @@ -66,6 +64,7 @@ func (hs *HTTPServer) registerFolderAPI(apiRoute routing.RouteRegister, authoriz folderUidRoute.Put("/", handler.updateFolder) folderUidRoute.Delete("/", handler.deleteFolder) folderUidRoute.Get("/", handler.getFolder) + folderUidRoute.Get("/counts", handler.countFolderContent) }) } else { folderRoute.Post("/", authorize(accesscontrol.EvalPermission(dashboards.ActionFoldersCreate)), routing.Wrap(hs.CreateFolder)) @@ -74,6 +73,7 @@ func (hs *HTTPServer) registerFolderAPI(apiRoute routing.RouteRegister, authoriz folderUidRoute.Put("/", authorize(accesscontrol.EvalPermission(dashboards.ActionFoldersWrite, uidScope)), routing.Wrap(hs.UpdateFolder)) folderUidRoute.Delete("/", authorize(accesscontrol.EvalPermission(dashboards.ActionFoldersDelete, uidScope)), routing.Wrap(hs.DeleteFolder)) folderUidRoute.Get("/", authorize(accesscontrol.EvalPermission(dashboards.ActionFoldersRead, uidScope)), routing.Wrap(hs.GetFolderByUID)) + folderUidRoute.Get("/counts", authorize(accesscontrol.EvalPermission(dashboards.ActionFoldersRead, uidScope)), routing.Wrap(hs.GetFolderDescendantCounts)) }) } }) @@ -747,6 +747,29 @@ func (fk8s *folderK8sHandler) getFolders(c *contextmodel.ReqContext) { c.JSON(http.StatusOK, hits) } +func (fk8s *folderK8sHandler) countFolderContent(c *contextmodel.ReqContext) { + client, ok := fk8s.getClient(c) + if !ok { + return + } + + uid := web.Params(c.Req)[":uid"] + + counts, err := client.Get(c.Req.Context(), uid, v1.GetOptions{}, "counts") + if err != nil { + fk8s.writeError(c, err) + return + } + + out, err := toFolderLegacyCounts(counts) + if err != nil { + fk8s.writeError(c, err) + return + } + + c.JSON(http.StatusOK, out) +} + func (fk8s *folderK8sHandler) getFolder(c *contextmodel.ReqContext) { client, ok := fk8s.getClient(c) if !ok { @@ -988,7 +1011,7 @@ func (fk8s *folderK8sHandler) getFolderACMetadata(c *contextmodel.ReqContext, f return nil, nil } - folderIDs, err := fk8s.getParents(f) + folderIDs, err := getParents(f) if err != nil { return nil, err } @@ -1004,7 +1027,7 @@ func (fk8s *folderK8sHandler) getFolderACMetadata(c *contextmodel.ReqContext, f return metadata, nil } -func (fk8s *folderK8sHandler) getParents(f *folder.Folder) (map[string]bool, error) { +func getParents(f *folder.Folder) (map[string]bool, error) { folderIDs := map[string]bool{f.UID: true} if (f.UID == accesscontrol.GeneralFolderUID) || (f.UID == folder.SharedWithMeFolderUID) { return folderIDs, nil @@ -1022,3 +1045,24 @@ func (fk8s *folderK8sHandler) getParents(f *folder.Folder) (map[string]bool, err return folderIDs, nil } + +func toFolderLegacyCounts(u *unstructured.Unstructured) (*folder.DescendantCounts, error) { + ds, err := folderalpha1.UnstructuredToDescendantCounts(u) + if err != nil { + return nil, err + } + + var out = make(folder.DescendantCounts) + for _, v := range ds.Counts { + // if stats come from unified storage, we will use them + if v.Group != "sql-fallback" { + out[v.Resource] = v.Count + continue + } + // if stats are from single tenant DB and they are not in unified storage, we will use them + if _, ok := out[v.Resource]; !ok { + out[v.Resource] = v.Count + } + } + return &out, nil +} diff --git a/pkg/api/folder_test.go b/pkg/api/folder_test.go index 58f4ac2a54a..60508e75f3f 100644 --- a/pkg/api/folder_test.go +++ b/pkg/api/folder_test.go @@ -13,6 +13,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" clientrest "k8s.io/client-go/rest" "github.com/grafana/grafana/pkg/api/dtos" @@ -747,3 +748,118 @@ func TestUpdateFolderLegacyAndUnifiedStorage(t *testing.T) { } }) } + +func TestToFolderCounts(t *testing.T) { + var tests = []struct { + name string + input *unstructured.Unstructured + expected *folder.DescendantCounts + expectError bool + }{ + { + name: "with only counts from unified storage", + input: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "folder.grafana.app/v0alpha1", + "counts": []interface{}{ + map[string]interface{}{ + "group": "alpha", + "resource": "folders", + "count": int64(1), + }, + map[string]interface{}{ + "group": "alpha", + "resource": "dashboards", + "count": int64(3), + }, + map[string]interface{}{ + "group": "alpha", + "resource": "alertRules", + "count": int64(0), + }, + }, + }, + }, + expected: &folder.DescendantCounts{ + "folders": 1, + "dashboards": 3, + "alertRules": 0, + }, + }, + { + name: "with counts from both storages", + input: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "folder.grafana.app/v0alpha1", + "counts": []interface{}{ + map[string]interface{}{ + "group": "alpha", + "resource": "folders", + "count": int64(1), + }, + map[string]interface{}{ + "group": "alpha", + "resource": "dashboards", + "count": int64(3), + }, + map[string]interface{}{ + "group": "sql-fallback", + "resource": "folders", + "count": int64(0), + }, + }, + }, + }, + expected: &folder.DescendantCounts{ + "folders": 1, + "dashboards": 3, + }, + }, + { + name: "it uses the values from sql-fallaback if not found in unified storage", + input: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "folder.grafana.app/v0alpha1", + "counts": []interface{}{ + map[string]interface{}{ + "group": "alpha", + "resource": "dashboards", + "count": int64(3), + }, + map[string]interface{}{ + "group": "sql-fallback", + "resource": "folders", + "count": int64(2), + }, + }, + }, + }, + expected: &folder.DescendantCounts{ + "folders": 2, + "dashboards": 3, + }, + }, + { + name: "malformed input", + input: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "folder.grafana.app/v0alpha1", + "counts": map[string]interface{}{}, + }, + }, + expectError: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + actual, err := toFolderLegacyCounts(tc.input) + if tc.expectError { + require.Error(t, err) + return + } + require.NoError(t, err) + require.Equal(t, tc.expected, actual) + }) + } +} diff --git a/pkg/apis/folder/v0alpha1/types.go b/pkg/apis/folder/v0alpha1/types.go index 5c83b81fa5b..c0bbb12ba40 100644 --- a/pkg/apis/folder/v0alpha1/types.go +++ b/pkg/apis/folder/v0alpha1/types.go @@ -2,6 +2,8 @@ package v0alpha1 import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" ) // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object @@ -76,3 +78,9 @@ type ResourceStats struct { Resource string `json:"resource"` Count int64 `json:"count"` } + +func UnstructuredToDescendantCounts(obj *unstructured.Unstructured) (*DescendantCounts, error) { + var res DescendantCounts + err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &res) + return &res, err +} diff --git a/pkg/registry/apis/folders/register.go b/pkg/registry/apis/folders/register.go index a79e2c8f32c..f4f36f26d9c 100644 --- a/pkg/registry/apis/folders/register.go +++ b/pkg/registry/apis/folders/register.go @@ -128,7 +128,7 @@ func (b *FolderAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.API storage[resourceInfo.StoragePath()] = legacyStore storage[resourceInfo.StoragePath("parents")] = &subParentsREST{b.folderSvc} storage[resourceInfo.StoragePath("access")] = &subAccessREST{b.folderSvc} - storage[resourceInfo.StoragePath("count")] = &subCountREST{searcher: b.searcher} + storage[resourceInfo.StoragePath("counts")] = &subCountREST{searcher: b.searcher} // enable dual writer if optsGetter != nil && dualWriteBuilder != nil { diff --git a/pkg/tests/apis/folder/folders_test.go b/pkg/tests/apis/folder/folders_test.go index 9893a4e63d2..c1a0aab9046 100644 --- a/pkg/tests/apis/folder/folders_test.go +++ b/pkg/tests/apis/folder/folders_test.go @@ -93,7 +93,7 @@ func TestIntegrationFoldersApp(t *testing.T) { ] }, { - "name": "folders/count", + "name": "folders/counts", "singularName": "", "namespaced": true, "kind": "DescendantCounts", From 8b0cd9dbb92f07f13975c7cfe67f838ae3799451 Mon Sep 17 00:00:00 2001 From: Todd Treece <360020+toddtreece@users.noreply.github.com> Date: Mon, 16 Dec 2024 08:18:43 -0500 Subject: [PATCH 23/38] K8s: Increment generation in generic strategy (#97946) --------- Co-authored-by: Ryan McKinley --- pkg/apiserver/registry/generic/strategy.go | 47 +++++- .../registry/generic/strategy_test.go | 134 ++++++++++++++++++ pkg/tests/apis/helper.go | 11 +- 3 files changed, 185 insertions(+), 7 deletions(-) create mode 100644 pkg/apiserver/registry/generic/strategy_test.go diff --git a/pkg/apiserver/registry/generic/strategy.go b/pkg/apiserver/registry/generic/strategy.go index 2628292fbee..6cb5dd918fd 100644 --- a/pkg/apiserver/registry/generic/strategy.go +++ b/pkg/apiserver/registry/generic/strategy.go @@ -4,6 +4,7 @@ import ( "context" "github.com/grafana/grafana/pkg/apimachinery/utils" + apiequality "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" @@ -41,15 +42,29 @@ func (g *genericStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.S return fields } -func (g *genericStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {} - -func (g *genericStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { - oldMeta, err := utils.MetaAccessor(old) +func (g *genericStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) { + meta, err := utils.MetaAccessor(obj) if err != nil { return } + meta.SetGeneration(1) + objCopy := obj.DeepCopyObject() + err = runtime.SetZeroValue(objCopy) + if err != nil { + return + } + metaCopy, err := utils.MetaAccessor(objCopy) + if err != nil { + return + } + status, err := metaCopy.GetStatus() + if err == nil { + _ = meta.SetStatus(status) + } +} - status, err := oldMeta.GetStatus() +func (g *genericStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { + oldMeta, err := utils.MetaAccessor(old) if err != nil { return } @@ -59,7 +74,27 @@ func (g *genericStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime return } - _ = newMeta.SetStatus(status) + // update shouldn't change the status + status, err := oldMeta.GetStatus() + if err != nil { + _ = newMeta.SetStatus(nil) + } else { + _ = newMeta.SetStatus(status) + } + + spec, err := newMeta.GetSpec() + if err != nil { + return + } + + oldSpec, err := oldMeta.GetSpec() + if err != nil { + return + } + + if !apiequality.Semantic.DeepEqual(spec, oldSpec) { + newMeta.SetGeneration(oldMeta.GetGeneration() + 1) + } } func (g *genericStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { diff --git a/pkg/apiserver/registry/generic/strategy_test.go b/pkg/apiserver/registry/generic/strategy_test.go new file mode 100644 index 00000000000..969332305a2 --- /dev/null +++ b/pkg/apiserver/registry/generic/strategy_test.go @@ -0,0 +1,134 @@ +package generic_test + +import ( + "context" + "testing" + + "github.com/grafana/grafana/pkg/apiserver/registry/generic" + "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apiserver/pkg/apis/example" +) + +func TestPrepareForUpdate(t *testing.T) { + ctx := context.TODO() + gv := schema.GroupVersion{Group: "test", Version: "v1"} + strategy := generic.NewStrategy(runtime.NewScheme(), gv) + + oldObj := &example.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + Generation: 1, + }, + Spec: example.PodSpec{ + NodeSelector: map[string]string{"foo": "bar"}, + }, + Status: example.PodStatus{ + Phase: example.PodPhase("Running"), + }, + } + + testCases := []struct { + name string + newObj *example.Pod + oldObj *example.Pod + expectedGen int64 + expectedObj *example.Pod + }{ + { + name: "ignore status updates", + newObj: &example.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + Generation: 1, + }, + Spec: example.PodSpec{ + NodeSelector: map[string]string{"foo": "bar"}, + }, + Status: example.PodStatus{ + Phase: example.PodPhase("Stopped"), + }, + }, + oldObj: oldObj.DeepCopy(), + expectedGen: 2, + expectedObj: &example.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + Generation: 1, + }, + Spec: example.PodSpec{ + NodeSelector: map[string]string{"foo": "bar"}, + }, + Status: example.PodStatus{ + Phase: example.PodPhase("Running"), + }, + }, + }, + { + name: "increment generation if spec changes", + newObj: &example.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + Generation: 1, + }, + Spec: example.PodSpec{ + NodeSelector: map[string]string{"foo": "baz"}, + }, + Status: example.PodStatus{ + Phase: example.PodPhase("Running"), + }, + }, + oldObj: oldObj.DeepCopy(), + expectedGen: 2, + expectedObj: &example.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + Generation: 2, + }, + Spec: example.PodSpec{ + NodeSelector: map[string]string{"foo": "baz"}, + }, + Status: example.PodStatus{ + Phase: example.PodPhase("Running"), + }, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + strategy.PrepareForUpdate(ctx, tc.newObj, tc.oldObj) + require.Equal(t, tc.expectedObj, tc.newObj) + }) + } +} + +func TestPrepareForCreate(t *testing.T) { + ctx := context.TODO() + gv := schema.GroupVersion{Group: "test", Version: "v1"} + strategy := generic.NewStrategy(runtime.NewScheme(), gv) + + obj := &example.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + }, + Spec: example.PodSpec{ + NodeSelector: map[string]string{"foo": "bar"}, + }, + Status: example.PodStatus{ + Phase: example.PodPhase("Running"), + }, + } + + strategy.PrepareForCreate(ctx, obj) + require.Equal(t, int64(1), obj.Generation) + require.Equal(t, example.PodStatus{}, obj.Status) +} diff --git a/pkg/tests/apis/helper.go b/pkg/tests/apis/helper.go index dd4c8e8c03c..0e2685e432b 100644 --- a/pkg/tests/apis/helper.go +++ b/pkg/tests/apis/helper.go @@ -216,6 +216,9 @@ func (c *K8sResourceClient) sanitizeObject(v *unstructured.Unstructured, replace meta, ok := copy["metadata"].(map[string]any) require.True(c.t, ok) + // remove generation + delete(meta, "generation") + replaceMeta = append(replaceMeta, "creationTimestamp", "resourceVersion", "uid") for _, key := range replaceMeta { old, ok := meta[key] @@ -403,12 +406,18 @@ func DoRequest[T any](c *K8sTestHelper, params RequestParams, result *T) K8sResp // Read local JSON or YAML file into a resource func (c *K8sTestHelper) LoadYAMLOrJSONFile(fpath string) *unstructured.Unstructured { c.t.Helper() + return c.LoadYAMLOrJSON(string(c.LoadFile(fpath))) +} + +// Read local file into a byte slice. Does not need to be a resource. +func (c *K8sTestHelper) LoadFile(fpath string) []byte { + c.t.Helper() //nolint:gosec raw, err := os.ReadFile(fpath) require.NoError(c.t, err) require.NotEmpty(c.t, raw) - return c.LoadYAMLOrJSON(string(raw)) + return raw } // Read local JSON or YAML file into a resource From 7601bcbb5deccd3589a132cb9cb438f9ff654686 Mon Sep 17 00:00:00 2001 From: jcolladokuri Date: Mon, 16 Dec 2024 05:47:21 -0800 Subject: [PATCH 24/38] [Azure Monitor]: Remove Angular panels from Azure OOB dashboards (#97975) updates azure monitor OOB dashboards to no longer include angular panesl --- .../azuremonitor/dashboards/adx.json | 6336 ++++++++--------- .../azuremonitor/dashboards/keyvault.json | 2153 +++--- .../azuremonitor/dashboards/storage.json | 1506 ++-- 3 files changed, 5101 insertions(+), 4894 deletions(-) diff --git a/public/app/plugins/datasource/azuremonitor/dashboards/adx.json b/public/app/plugins/datasource/azuremonitor/dashboards/adx.json index db6ebc0998c..0a579f29068 100644 --- a/public/app/plugins/datasource/azuremonitor/dashboards/adx.json +++ b/public/app/plugins/datasource/azuremonitor/dashboards/adx.json @@ -1,22 +1,18 @@ { + "__inputs": [], + "__elements": {}, "__requires": [ { "type": "grafana", "id": "grafana", "name": "Grafana", - "version": "7.4.3" + "version": "10.4.7" }, { "type": "datasource", "id": "grafana-azure-monitor-datasource", "name": "Azure Monitor", - "version": "0.3.0" - }, - { - "type": "panel", - "id": "graph", - "name": "Graph", - "version": "" + "version": "1.0.0" }, { "type": "panel", @@ -29,18 +25,42 @@ "id": "table", "name": "Table", "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" } ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "The dashboard provides insights of Azure Data Explorer Cluster Resource overview, key mettrics, usage, tables, cache and ingestion.", "editable": true, - "gnetId": null, + "fiscalYearStartMonth": 0, "graphTooltip": 0, "id": null, - "iteration": 1622241391232, "links": [], "panels": [ { "collapsed": false, - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "gridPos": { "h": 1, "w": 24, @@ -49,18 +69,29 @@ }, "id": 6, "panels": [], + "targets": [ + { + "datasource": { + "uid": "$ds" + }, + "refId": "A" + } + ], "title": "Overview", "type": "row" }, { - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, - "custom": {}, "mappings": [], + "noValue": "-", "thresholds": { "mode": "absolute", "steps": [ @@ -79,7 +110,7 @@ }, "gridPos": { "h": 5, - "w": 3, + "w": 4, "x": 0, "y": 1 }, @@ -94,34 +125,29 @@ "fields": "", "values": false }, + "showPercentChange": false, "text": {}, - "textMode": "auto" + "textMode": "auto", + "wideLayout": true }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n //the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "657b3e91-7c0b-438b-86a5-f769445e237d" - }, "azureMonitor": { "aggOptions": ["Average"], "aggregation": "Average", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [], "metricDefinition": "$ns", "metricName": "KeepAlive", "metricNamespace": "Microsoft.Kusto/clusters", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -163,29 +189,29 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "uid": "$ds" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "timeFrom": null, - "timeShift": null, "title": "Keep Alive (Avg)", "type": "stat" }, { - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, - "custom": {}, "mappings": [], + "noValue": "-", "thresholds": { "mode": "absolute", "steps": [ @@ -204,8 +230,8 @@ }, "gridPos": { "h": 5, - "w": 3, - "x": 3, + "w": 4, + "x": 4, "y": 1 }, "id": 12, @@ -219,34 +245,29 @@ "fields": "", "values": false }, + "showPercentChange": false, "text": {}, - "textMode": "auto" + "textMode": "auto", + "wideLayout": true }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "657b3e91-7c0b-438b-86a5-f769445e237d" - }, "azureMonitor": { "aggOptions": ["Average", "Maximum", "Minimum"], "aggregation": "Average", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [], "metricDefinition": "$ns", "metricName": "CPU", "metricNamespace": "Microsoft.Kusto/clusters", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -288,29 +309,29 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "uid": "$ds" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "timeFrom": null, - "timeShift": null, "title": "CPU (Avg)", "type": "stat" }, { - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, - "custom": {}, "mappings": [], + "noValue": "-", "thresholds": { "mode": "absolute", "steps": [ @@ -329,8 +350,8 @@ }, "gridPos": { "h": 5, - "w": 3, - "x": 6, + "w": 4, + "x": 8, "y": 1 }, "id": 13, @@ -344,34 +365,29 @@ "fields": "", "values": false }, + "showPercentChange": false, "text": {}, - "textMode": "auto" + "textMode": "auto", + "wideLayout": true }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "657b3e91-7c0b-438b-86a5-f769445e237d" - }, "azureMonitor": { "aggOptions": ["Average", "Maximum", "Minimum"], "aggregation": "Average", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [], "metricDefinition": "$ns", "metricName": "IngestionUtilization", "metricNamespace": "Microsoft.Kusto/clusters", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -413,29 +429,29 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "uid": "$ds" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "timeFrom": null, - "timeShift": null, "title": "Ingestion Utilization (Avg) ", "type": "stat" }, { - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, - "custom": {}, "mappings": [], + "noValue": "-", "thresholds": { "mode": "absolute", "steps": [ @@ -454,8 +470,8 @@ }, "gridPos": { "h": 5, - "w": 3, - "x": 9, + "w": 4, + "x": 12, "y": 1 }, "id": 14, @@ -469,34 +485,29 @@ "fields": "", "values": false }, + "showPercentChange": false, "text": {}, - "textMode": "auto" + "textMode": "auto", + "wideLayout": true }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "657b3e91-7c0b-438b-86a5-f769445e237d" - }, "azureMonitor": { "aggOptions": ["Average", "Maximum", "Minimum"], "aggregation": "Average", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [], "metricDefinition": "$ns", "metricName": "IngestionLatencyInSeconds", "metricNamespace": "Microsoft.Kusto/clusters", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -538,29 +549,29 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "uid": "$ds" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "timeFrom": null, - "timeShift": null, "title": "Ingestion Latency (Avg) ", "type": "stat" }, { - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, - "custom": {}, "mappings": [], + "noValue": "-", "thresholds": { "mode": "absolute", "steps": [ @@ -579,8 +590,8 @@ }, "gridPos": { "h": 5, - "w": 3, - "x": 12, + "w": 4, + "x": 16, "y": 1 }, "id": 15, @@ -594,34 +605,29 @@ "fields": "", "values": false }, + "showPercentChange": false, "text": {}, - "textMode": "auto" + "textMode": "auto", + "wideLayout": true }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "657b3e91-7c0b-438b-86a5-f769445e237d" - }, "azureMonitor": { "aggOptions": ["Average", "Maximum", "Minimum"], "aggregation": "Average", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [], "metricDefinition": "$ns", "metricName": "CacheUtilization", "metricNamespace": "Microsoft.Kusto/clusters", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -663,29 +669,29 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "uid": "$ds" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "timeFrom": null, - "timeShift": null, "title": "Cache Utilization (Avg)", "type": "stat" }, { - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, - "custom": {}, "mappings": [], + "noValue": "-", "thresholds": { "mode": "absolute", "steps": [ @@ -704,8 +710,8 @@ }, "gridPos": { "h": 5, - "w": 3, - "x": 15, + "w": 4, + "x": 20, "y": 1 }, "id": 16, @@ -719,27 +725,18 @@ "fields": "", "values": false }, + "showPercentChange": false, "text": {}, - "textMode": "auto" + "textMode": "auto", + "wideLayout": true }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "657b3e91-7c0b-438b-86a5-f769445e237d" - }, "azureMonitor": { "aggOptions": ["Total"], "aggregation": "Total", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [ { @@ -750,8 +747,12 @@ "metricDefinition": "$ns", "metricName": "IngestionResult", "metricNamespace": "Microsoft.Kusto/clusters", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -793,22 +794,22 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "uid": "$ds" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "timeFrom": null, - "timeShift": null, "title": "Succeeded Ingestions (#)", "type": "stat" }, { - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "description": "The aggregated usage in the cluster, out of the total used CPU and memory. To see more details, go to the Usage tab.", "fieldConfig": { "defaults": { @@ -816,8 +817,12 @@ "mode": "thresholds" }, "custom": { - "align": null, - "filterable": false + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false }, "mappings": [], "thresholds": { @@ -835,179 +840,140 @@ }, "id": 17, "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": ["sum"], + "show": false + }, "showHeader": true }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, "azureLogAnalytics": { + "dashboardTime": false, "query": "let system_databases = dynamic(['KustoMonitoringPersistentDatabase', '$systemdb']); \r\nlet system_users = dynamic(['AAD app id=b753584e-c468-4503-852a-374280ce7a62', 'KustoServiceBuiltInPrincipal']); // b753584e-c468-4503-852a-374280ce7a62 is KustoRunner\r\nlet system_cluster_management_applications = dynamic(['Kusto.WinSvc.CM.Svc']); // Kusto Cluster Management\r\nlet CommandTable = ADXCommand \r\n | where TimeGenerated > datetime(2020-09-09T09:30:00Z) \r\n | where LastUpdatedOn > ago(7d)\r\n | where DatabaseName !in (system_databases) and User !in (system_users) and ApplicationName !in (system_cluster_management_applications)\r\n | where ((false == \"false\" and ApplicationName != 'Kusto.WinSvc.DM.Svc') or false == \"true\")\r\n | extend MemoryPeak = tolong(ResourceUtilization.MemoryPeak) \r\n | parse _ResourceId with * \"providers/microsoft.kusto/clusters/\" cluster_name\r\n | project-away ResourceUtilization;\r\nlet QueryTable = ADXQuery\r\n | where LastUpdatedOn > ago(7d)\r\n | where DatabaseName !in (system_databases) and User !in (system_users) and ApplicationName !in (system_cluster_management_applications)\r\n | where ((false == \"false\" and ApplicationName != 'Kusto.WinSvc.DM.Svc') or false == \"true\")\r\n | extend MemoryPeak = tolong(MemoryPeak)\r\n | parse _ResourceId with * \"providers/microsoft.kusto/clusters/\" cluster_name\r\n | extend CommandType = 'Query';\r\nlet dataset_commands_queries = CommandTable\r\n | union (QueryTable)\r\n | project CommandType, DatabaseName, StartedOn, LastUpdatedOn, Duration, State, FailureReason, RootActivityId, User, ApplicationName, Principal, TotalCPU, MemoryPeak, CorrelationId, cluster_name;\r\nlet dataset = dataset_commands_queries\r\n | where cluster_name == 'mitulktest'\r\n //| where totimespan(TotalCPU) > totimespan(0)\r\n | summarize TotalCPU=max(TotalCPU) \r\n , MemoryPeak=max(MemoryPeak)\r\n by User, ApplicationName, CorrelationId \r\n;\r\nlet totalCPU = toscalar(dataset\r\n | summarize sum((totimespan(TotalCPU) / 1s)));\r\nlet totalMemory = toscalar(dataset\r\n | summarize sum(MemoryPeak));\r\nlet topMemory = \r\n dataset\r\n | top-nested 10000 of User with others=\"Others\" by sum(MemoryPeak), top-nested 10000 of ApplicationName with others=\"Others\" by sum(MemoryPeak)\r\n | extend PercentOfTotalClusterMemoryUsed = aggregated_ApplicationName / toreal(totalMemory)\r\n;\r\nlet topCpu = \r\n dataset\r\n | top-nested 10000 of User with others=\"Others\" by sum(totimespan(TotalCPU) / 1s), top-nested 10000 of ApplicationName with others=\"Others\" by sum(totimespan(TotalCPU) / 1s)\r\n | extend PercentOfTotalClusterCpuUsed = aggregated_ApplicationName / toreal(totalCPU)\r\n;\r\ntopMemory\r\n| join kind = fullouter(topCpu) on User, ApplicationName\r\n| extend BothPercentages = PercentOfTotalClusterMemoryUsed + PercentOfTotalClusterCpuUsed\r\n| top 10 by BothPercentages desc\r\n| extend User = case(ApplicationName == \"Kusto.WinSvc.DM.Svc\", strcat(\"Kusto Data Management \", \"(\", User, \")\"),\r\n ApplicationName == \"KustoQueryRunner\", strcat(\"Kusto Query Runner \", \"(\", User, \")\"),\r\n User == \"AAD app id=e0331ea9-83fc-4409-a17d-6375364c3280\", \"DataMap Agent 001 (app id: e0331ea9-83fc-4409-a17d-6375364c3280)\", // Used for internal MS clusters \r\n User)\r\n| extend PercentOfTotalClusterMemoryUsed_display = iff(isnan(PercentOfTotalClusterMemoryUsed * 100), toreal(0), PercentOfTotalClusterMemoryUsed * 100)\r\n| extend PercentOfTotalClusterCpuUsed_display = iff(isnan(PercentOfTotalClusterCpuUsed * 100), toreal(0), PercentOfTotalClusterCpuUsed * 100)\r\n| where not (ApplicationName == \"Others\" and PercentOfTotalClusterMemoryUsed_display == 0 and PercentOfTotalClusterCpuUsed_display == 0)\r\n| project User, ApplicationName, PercentOfTotalClusterMemoryUsed_display, PercentOfTotalClusterCpuUsed_display", - "resultFormat": "time_series", - "workspace": "$ws" - }, - "azureMonitor": { - "aggOptions": [], - "dimensionFilter": "*", - "dimensionFilters": [], - "metricDefinition": "select", - "metricName": "select", - "metricNamespace": "select", - "resourceGroup": "select", - "resourceName": "select", - "timeGrain": "auto", - "timeGrains": [], - "top": "10" - }, - "insightsAnalytics": { - "query": "", + "resources": ["$ws"], "resultFormat": "time_series" }, + "datasource": { + "uid": "$ds" + }, "queryType": "Azure Log Analytics", "refId": "A", "subscription": "$sub" } ], - "timeFrom": null, - "timeShift": null, "title": "Top resource consumers", - "transparent": true, "type": "table" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "description": "Over a sliding timeline window. Not affected by the time range parameter", "fieldConfig": { "defaults": { - "color": {}, - "custom": {}, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 3, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], "thresholds": { "mode": "absolute", - "steps": [] - } + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 9, "w": 12, "x": 12, "y": 6 }, - "hiddenSeries": false, "id": 2, - "legend": { - "avg": true, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 3, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["mean"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, "azureLogAnalytics": { + "dashboardTime": false, "query": "let system_databases = dynamic(['KustoMonitoringPersistentDatabase', '$systemdb']); \r\nlet system_users = dynamic(['AAD app id=b753584e-c468-4503-852a-374280ce7a62', 'KustoServiceBuiltInPrincipal']); // b753584e-c468-4503-852a-374280ce7a62 is Kusto Query Runner\r\nlet system_cluster_management_applications = dynamic(['Kusto.WinSvc.CM.Svc']); // Kusto Cluster Management\r\nlet CommandTable = ADXCommand\r\n | extend MemoryPeak = tolong(ResourceUtilization.MemoryPeak) \r\n | where DatabaseName !in (system_databases) and User !in (system_users) and ApplicationName !in (system_cluster_management_applications)\r\n | where ApplicationName != 'Kusto.WinSvc.DM.Svc'\r\n | parse _ResourceId with * \"providers/microsoft.kusto/clusters/\" cluster_name\r\n | project-away ResourceUtilization;\r\nlet QueryTable = ADXQuery\r\n | where DatabaseName !in (system_databases) and User !in (system_users) and ApplicationName !in (system_cluster_management_applications)\r\n | where ApplicationName != 'Kusto.WinSvc.DM.Svc'\r\n | extend MemoryPeak = tolong(MemoryPeak)\r\n | parse _ResourceId with * \"providers/microsoft.kusto/clusters/\" cluster_name\r\n | extend CommandType = 'Query';\r\nlet dataset_commands_queries = CommandTable\r\n | union (QueryTable)\r\n | project CommandType, DatabaseName, StartedOn, LastUpdatedOn, Duration, State,\r\n FailureReason, RootActivityId, User,\r\n ApplicationName,\r\n Principal,\r\n TotalCPU,\r\n MemoryPeak,\r\n CorrelationId,\r\n cluster_name;\r\nlet raw = dataset_commands_queries\r\n | where LastUpdatedOn > ago(7d)\r\n | where cluster_name == 'mitulktest'\r\n | where StartedOn > ago(365d)\r\n;\r\nraw\r\n| evaluate activity_engagement(User, StartedOn, 1d, 7d)\r\n| join kind = inner (\r\n raw\r\n | evaluate activity_engagement(User, StartedOn, 1d, 30d)\r\n )\r\n on StartedOn\r\n| project StartedOn, Daily=dcount_activities_inner, Weekly=dcount_activities_outer, Monthly = dcount_activities_outer1 \r\n| where StartedOn > ago(90d)\r\n| project Daily, StartedOn, Weekly, Monthly\r\n| sort by StartedOn asc\r\n", - "resultFormat": "time_series", - "workspace": "$ws" - }, - "azureMonitor": { - "aggOptions": [], - "dimensionFilter": "*", - "dimensionFilters": [], - "metricDefinition": "select", - "metricName": "select", - "metricNamespace": "select", - "resourceGroup": "select", - "resourceName": "select", - "timeGrain": "auto", - "timeGrains": [], - "top": "10" - }, - "insightsAnalytics": { - "query": "", + "resources": ["$ws"], "resultFormat": "time_series" }, + "datasource": { + "uid": "$ds" + }, "queryType": "Azure Log Analytics", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Unique user count", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { "collapsed": false, - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "gridPos": { "h": 1, "w": 24, @@ -1016,84 +982,114 @@ }, "id": 19, "panels": [], + "targets": [ + { + "datasource": { + "uid": "$ds" + }, + "refId": "A" + } + ], "title": "Key Metrics", "type": "row" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { - "color": {}, - "custom": {}, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], "thresholds": { "mode": "absolute", - "steps": [] - } + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 10, "w": 6, "x": 0, "y": 16 }, - "hiddenSeries": false, "id": 20, - "legend": { - "avg": true, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["mean"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "657b3e91-7c0b-438b-86a5-f769445e237d" - }, "azureMonitor": { "aggOptions": ["Average"], "aggregation": "Average", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [], "metricDefinition": "$ns", "metricName": "KeepAlive", "metricNamespace": "Microsoft.Kusto/clusters", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -1135,131 +1131,114 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "uid": "$ds" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Keep Alive", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { - "color": {}, - "custom": {}, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], "thresholds": { "mode": "absolute", - "steps": [] - } + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 10, "w": 6, "x": 6, "y": 16 }, - "hiddenSeries": false, "id": 21, - "legend": { - "avg": true, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["mean"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "657b3e91-7c0b-438b-86a5-f769445e237d" - }, "azureMonitor": { "aggOptions": ["Average", "Maximum", "Minimum"], "aggregation": "Average", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [], "metricDefinition": "$ns", "metricName": "CPU", "metricNamespace": "Microsoft.Kusto/clusters", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -1301,131 +1280,114 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "uid": "$ds" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "CPU", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "percent", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { - "color": {}, - "custom": {}, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], "thresholds": { "mode": "absolute", - "steps": [] - } + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 10, "w": 6, "x": 12, "y": 16 }, - "hiddenSeries": false, "id": 22, - "legend": { - "avg": true, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["mean"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "657b3e91-7c0b-438b-86a5-f769445e237d" - }, "azureMonitor": { "aggOptions": ["Average", "Maximum", "Minimum"], "aggregation": "Average", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [], "metricDefinition": "$ns", "metricName": "CacheUtilization", "metricNamespace": "Microsoft.Kusto/clusters", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -1467,131 +1429,114 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "uid": "$ds" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Cache Utilization", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "percent", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { - "color": {}, - "custom": {}, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], "thresholds": { "mode": "absolute", - "steps": [] - } + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 10, "w": 6, "x": 18, "y": 16 }, - "hiddenSeries": false, "id": 23, - "legend": { - "avg": true, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["mean"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "657b3e91-7c0b-438b-86a5-f769445e237d" - }, "azureMonitor": { "aggOptions": ["Average", "Maximum", "Minimum"], "aggregation": "Average", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [], "metricDefinition": "$ns", "metricName": "InstanceCount", "metricNamespace": "Microsoft.Kusto/clusters", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -1633,131 +1578,114 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "uid": "$ds" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Instance Count", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { - "color": {}, - "custom": {}, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], "thresholds": { "mode": "absolute", - "steps": [] - } + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 10, "w": 6, "x": 0, "y": 26 }, - "hiddenSeries": false, "id": 24, - "legend": { - "avg": true, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["mean"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "657b3e91-7c0b-438b-86a5-f769445e237d" - }, "azureMonitor": { "aggOptions": ["Average", "Maximum", "Minimum"], "aggregation": "Average", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [], "metricDefinition": "$ns", "metricName": "TotalNumberOfConcurrentQueries", "metricNamespace": "Microsoft.Kusto/clusters", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -1799,124 +1727,103 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "uid": "$ds" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Concurrent Queries", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { - "color": {}, - "custom": {}, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], "thresholds": { "mode": "absolute", - "steps": [] - } + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 10, "w": 6, "x": 6, "y": 26 }, - "hiddenSeries": false, "id": 25, - "legend": { - "avg": true, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["mean"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "657b3e91-7c0b-438b-86a5-f769445e237d" - }, "azureMonitor": { "aggOptions": ["Average", "Maximum", "Minimum", "Total"], "aggregation": "Average", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [ { @@ -1927,8 +1834,12 @@ "metricDefinition": "$ns", "metricName": "QueryDuration", "metricNamespace": "Microsoft.Kusto/clusters", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -1970,124 +1881,103 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "uid": "$ds" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Query Duration", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "ms", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { - "color": {}, - "custom": {}, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], "thresholds": { "mode": "absolute", - "steps": [] - } + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 10, "w": 6, "x": 12, "y": 26 }, - "hiddenSeries": false, "id": 26, - "legend": { - "avg": true, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["mean"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "657b3e91-7c0b-438b-86a5-f769445e237d" - }, "azureMonitor": { "aggOptions": ["Average", "Maximum", "Minimum", "Total"], "aggregation": "Total", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [ { @@ -2098,8 +1988,12 @@ "metricDefinition": "$ns", "metricName": "TotalNumberOfThrottledCommands", "metricNamespace": "Microsoft.Kusto/clusters", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -2141,131 +2035,114 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "uid": "$ds" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Throttled Commands", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "ms", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { - "color": {}, - "custom": {}, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], "thresholds": { "mode": "absolute", - "steps": [] - } + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 10, "w": 6, "x": 18, "y": 26 }, - "hiddenSeries": false, "id": 27, - "legend": { - "avg": true, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["mean"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "657b3e91-7c0b-438b-86a5-f769445e237d" - }, "azureMonitor": { "aggOptions": ["Average", "Maximum", "Minimum", "Total"], "aggregation": "Maximum", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [], "metricDefinition": "$ns", "metricName": "TotalNumberOfThrottledQueries", "metricNamespace": "Microsoft.Kusto/clusters", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -2307,131 +2184,114 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "uid": "$ds" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Throttled Queries", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { - "color": {}, - "custom": {}, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], "thresholds": { "mode": "absolute", - "steps": [] - } + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 10, "w": 6, "x": 0, "y": 36 }, - "hiddenSeries": false, "id": 28, - "legend": { - "avg": true, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["mean"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "657b3e91-7c0b-438b-86a5-f769445e237d" - }, "azureMonitor": { "aggOptions": ["Average", "Maximum", "Minimum"], "aggregation": "Average", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [], "metricDefinition": "$ns", "metricName": "IngestionUtilization", "metricNamespace": "Microsoft.Kusto/clusters", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -2473,131 +2333,114 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "uid": "$ds" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Ingestion Utilization", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "percent", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { - "color": {}, - "custom": {}, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], "thresholds": { "mode": "absolute", - "steps": [] - } + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 10, "w": 6, "x": 6, "y": 36 }, - "hiddenSeries": false, "id": 29, - "legend": { - "avg": true, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["mean"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "657b3e91-7c0b-438b-86a5-f769445e237d" - }, "azureMonitor": { "aggOptions": ["Average", "Maximum", "Minimum"], "aggregation": "Average", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [], "metricDefinition": "$ns", "metricName": "IngestionLatencyInSeconds", "metricNamespace": "Microsoft.Kusto/clusters", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -2639,124 +2482,103 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "uid": "$ds" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Ingestion Latency", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "s", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { - "color": {}, - "custom": {}, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], "thresholds": { "mode": "absolute", - "steps": [] - } + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 10, "w": 6, "x": 12, "y": 36 }, - "hiddenSeries": false, "id": 30, - "legend": { - "avg": true, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["mean"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "657b3e91-7c0b-438b-86a5-f769445e237d" - }, "azureMonitor": { "aggOptions": ["Total"], "aggregation": "Total", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [ { @@ -2767,8 +2589,12 @@ "metricDefinition": "$ns", "metricName": "IngestionResult", "metricNamespace": "Microsoft.Kusto/clusters", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -2810,124 +2636,103 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "uid": "$ds" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Ingestion Result", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { - "color": {}, - "custom": {}, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], "thresholds": { "mode": "absolute", - "steps": [] - } + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 10, "w": 6, "x": 18, "y": 36 }, - "hiddenSeries": false, "id": 31, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["sum"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "657b3e91-7c0b-438b-86a5-f769445e237d" - }, "azureMonitor": { "aggOptions": ["Total", "Maximum"], "aggregation": "Total", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [ { @@ -2938,8 +2743,12 @@ "metricDefinition": "$ns", "metricName": "IngestionVolumeInMB", "metricNamespace": "Microsoft.Kusto/clusters", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -2981,131 +2790,114 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "uid": "$ds" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Ingestion Volume", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { - "color": {}, - "custom": {}, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], "thresholds": { "mode": "absolute", - "steps": [] - } + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 10, "w": 6, "x": 0, "y": 46 }, - "hiddenSeries": false, "id": 32, - "legend": { - "avg": true, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["mean"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "657b3e91-7c0b-438b-86a5-f769445e237d" - }, "azureMonitor": { "aggOptions": ["Average", "Minimum", "Maximum"], "aggregation": "Average", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [], "metricDefinition": "$ns", "metricName": "StreamingIngestDataRate", "metricNamespace": "Microsoft.Kusto/clusters", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -3147,131 +2939,114 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "uid": "$ds" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Streaming Ingest Data Rate", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { - "color": {}, - "custom": {}, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], "thresholds": { "mode": "absolute", - "steps": [] - } + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 10, "w": 6, "x": 6, "y": 46 }, - "hiddenSeries": false, "id": 33, - "legend": { - "avg": true, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["mean"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "657b3e91-7c0b-438b-86a5-f769445e237d" - }, "azureMonitor": { "aggOptions": ["Average", "Minimum", "Maximum"], "aggregation": "Average", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [], "metricDefinition": "$ns", "metricName": "StreamingIngestDuration", "metricNamespace": "Microsoft.Kusto/clusters", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -3313,124 +3088,252 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "uid": "$ds" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Streaming Ingest Duration", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "ms", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { - "color": {}, - "custom": {}, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], "thresholds": { "mode": "absolute", - "steps": [] - } + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 10, "w": 6, "x": 12, "y": 46 }, - "hiddenSeries": false, - "id": 35, - "legend": { - "avg": true, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", + "id": 34, "options": { - "alertThreshold": true + "legend": { + "calcs": ["mean"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" + "azureMonitor": { + "aggOptions": ["None", "Average", "Minimum", "Maximum", "Total", "Count"], + "aggregation": "None", + "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], + "dimensionFilters": [], + "dimensions": [], + "metricDefinition": "$ns", + "metricName": "SteamingIngestRequestRate", + "metricNamespace": "Microsoft.Kusto/clusters", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], + "timeGrain": "auto", + "timeGrains": [ + { + "text": "auto", + "value": "auto" + }, + { + "text": "1 minute", + "value": "PT1M" + }, + { + "text": "5 minutes", + "value": "PT5M" + }, + { + "text": "15 minutes", + "value": "PT15M" + }, + { + "text": "30 minutes", + "value": "PT30M" + }, + { + "text": "1 hour", + "value": "PT1H" + }, + { + "text": "6 hours", + "value": "PT6H" + }, + { + "text": "12 hours", + "value": "PT12H" + }, + { + "text": "1 day", + "value": "P1D" + } + ], + "top": "10" }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "657b3e91-7c0b-438b-86a5-f769445e237d" + "datasource": { + "uid": "$ds" }, + "queryType": "Azure Monitor", + "refId": "A", + "subscription": "$sub" + } + ], + "title": "Streaming Ingest Request Rate", + "type": "timeseries" + }, + { + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 6, + "x": 18, + "y": 46 + }, + "id": 35, + "options": { + "legend": { + "calcs": ["mean"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.4.7", + "targets": [ + { "azureMonitor": { "aggOptions": ["Average"], "aggregation": "Average", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [ { @@ -3441,8 +3344,12 @@ "metricDefinition": "$ns", "metricName": "StreamingIngestResults", "metricNamespace": "Microsoft.Kusto/clusters", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -3484,124 +3391,103 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "uid": "$ds" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Streaming Ingest Result", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { - "color": {}, - "custom": {}, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], "thresholds": { "mode": "absolute", - "steps": [] - } + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 9, "w": 12, "x": 0, "y": 56 }, - "hiddenSeries": false, "id": 36, - "legend": { - "avg": true, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["mean"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "657b3e91-7c0b-438b-86a5-f769445e237d" - }, "azureMonitor": { "aggOptions": ["Total", "Average", "Minimum", "Maximum"], "aggregation": "Total", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [ { @@ -3616,8 +3502,12 @@ "metricDefinition": "$ns", "metricName": "EventsProcessed", "metricNamespace": "Microsoft.Kusto/clusters", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -3659,124 +3549,103 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "uid": "$ds" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Events Processed", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { - "color": {}, - "custom": {}, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], "thresholds": { "mode": "absolute", - "steps": [] - } + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 9, "w": 12, "x": 12, "y": 56 }, - "hiddenSeries": false, "id": 37, - "legend": { - "avg": true, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["mean"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "657b3e91-7c0b-438b-86a5-f769445e237d" - }, "azureMonitor": { "aggOptions": ["Average"], "aggregation": "Average", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [ { @@ -3791,8 +3660,12 @@ "metricDefinition": "$ns", "metricName": "DiscoveryLatency", "metricNamespace": "Microsoft.Kusto/clusters", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -3834,59 +3707,22 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "uid": "$ds" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Discovery Latency", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { "collapsed": false, - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "gridPos": { "h": 1, "w": 24, @@ -3895,19 +3731,34 @@ }, "id": 40, "panels": [], + "targets": [ + { + "datasource": { + "uid": "$ds" + }, + "refId": "A" + } + ], "title": "Usage", "type": "row" }, { - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, "custom": { - "align": null, - "filterable": false + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false }, "mappings": [], "thresholds": { @@ -3925,9 +3776,16 @@ }, "id": 43, "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": ["sum"], + "show": false + }, "showHeader": true }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { "appInsights": { @@ -3936,9 +3794,10 @@ "timeGrain": "auto" }, "azureLogAnalytics": { + "dashboardTime": false, "query": "let system_databases = dynamic(['KustoMonitoringPersistentDatabase', '$systemdb']); \r\nlet system_users = dynamic(['AAD app id=b753584e-c468-4503-852a-374280ce7a62', 'KustoServiceBuiltInPrincipal']); // b753584e-c468-4503-852a-374280ce7a62 is KustoRunner\r\nlet system_cluster_management_applications = dynamic(['Kusto.WinSvc.CM.Svc']); // Kusto Cluster Management\r\nlet CommandTable = ADXCommand \r\n | where TimeGenerated > datetime(2020-09-09T09:30:00Z) \r\n | where LastUpdatedOn > ago(7d)\r\n | where DatabaseName !in (system_databases) and User !in (system_users) and ApplicationName !in (system_cluster_management_applications)\r\n | where ((false == \"false\" and ApplicationName != 'Kusto.WinSvc.DM.Svc') or false == \"true\")\r\n | extend MemoryPeak = tolong(ResourceUtilization.MemoryPeak) \r\n | parse _ResourceId with * \"providers/microsoft.kusto/clusters/\" cluster_name\r\n | project-away ResourceUtilization;\r\nlet QueryTable = ADXQuery\r\n | where LastUpdatedOn > ago(7d)\r\n | where DatabaseName !in (system_databases) and User !in (system_users) and ApplicationName !in (system_cluster_management_applications)\r\n | where ((false == \"false\" and ApplicationName != 'Kusto.WinSvc.DM.Svc') or false == \"true\")\r\n | extend MemoryPeak = tolong(MemoryPeak)\r\n | parse _ResourceId with * \"providers/microsoft.kusto/clusters/\" cluster_name\r\n | extend CommandType = 'Query';\r\nlet dataset_commands_queries = CommandTable\r\n | union (QueryTable)\r\n | project CommandType, DatabaseName, StartedOn, LastUpdatedOn, Duration, State, FailureReason, RootActivityId, User, ApplicationName, Principal, TotalCPU, MemoryPeak, CorrelationId, cluster_name;\r\nlet dataset = dataset_commands_queries\r\n | where cluster_name == 'mitulktest'\r\n //| where totimespan(TotalCPU) > totimespan(0)\r\n | summarize TotalCPU=max(TotalCPU) \r\n , MemoryPeak=max(MemoryPeak)\r\n by User, ApplicationName, CorrelationId \r\n;\r\nlet totalCPU = toscalar(dataset\r\n | summarize sum((totimespan(TotalCPU) / 1s)));\r\nlet totalMemory = toscalar(dataset\r\n | summarize sum(MemoryPeak));\r\nlet topMemory = \r\n dataset\r\n | top-nested 10000 of User with others=\"Others\" by sum(MemoryPeak), top-nested 10000 of ApplicationName with others=\"Others\" by sum(MemoryPeak)\r\n | extend PercentOfTotalClusterMemoryUsed = aggregated_ApplicationName / toreal(totalMemory)\r\n;\r\nlet topCpu = \r\n dataset\r\n | top-nested 10000 of User with others=\"Others\" by sum(totimespan(TotalCPU) / 1s), top-nested 10000 of ApplicationName with others=\"Others\" by sum(totimespan(TotalCPU) / 1s)\r\n | extend PercentOfTotalClusterCpuUsed = aggregated_ApplicationName / toreal(totalCPU)\r\n;\r\ntopMemory\r\n| join kind = fullouter(topCpu) on User, ApplicationName\r\n| extend BothPercentages = PercentOfTotalClusterMemoryUsed + PercentOfTotalClusterCpuUsed\r\n| top 10 by BothPercentages desc\r\n| extend User = case(ApplicationName == \"Kusto.WinSvc.DM.Svc\", strcat(\"Kusto Data Management \", \"(\", User, \")\"),\r\n ApplicationName == \"KustoQueryRunner\", strcat(\"Kusto Query Runner \", \"(\", User, \")\"),\r\n User == \"AAD app id=e0331ea9-83fc-4409-a17d-6375364c3280\", \"DataMap Agent 001 (app id: e0331ea9-83fc-4409-a17d-6375364c3280)\", // Used for internal MS clusters \r\n User)\r\n| extend PercentOfTotalClusterMemoryUsed_display = iff(isnan(PercentOfTotalClusterMemoryUsed * 100), toreal(0), PercentOfTotalClusterMemoryUsed * 100)\r\n| extend PercentOfTotalClusterCpuUsed_display = iff(isnan(PercentOfTotalClusterCpuUsed * 100), toreal(0), PercentOfTotalClusterCpuUsed * 100)\r\n| where not (ApplicationName == \"Others\" and PercentOfTotalClusterMemoryUsed_display == 0 and PercentOfTotalClusterCpuUsed_display == 0)\r\n| project User, ApplicationName, PercentOfTotalClusterMemoryUsed_display, PercentOfTotalClusterCpuUsed_display", - "resultFormat": "time_series", - "workspace": "$ws" + "resources": ["$ws"], + "resultFormat": "time_series" }, "azureMonitor": { "aggOptions": ["Average"], @@ -3959,8 +3818,12 @@ "metricDefinition": "$ns", "metricName": "DiscoveryLatency", "metricNamespace": "Microsoft.Kusto/clusters", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -4002,31 +3865,35 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "uid": "$ds" }, "queryType": "Azure Log Analytics", "refId": "A", "subscription": "$sub" } ], - "timeFrom": null, - "timeShift": null, "title": "Top resource consumers (within the CPU and memory consumption of the cluster)", "transparent": true, "type": "table" }, { - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, "custom": { - "align": null, - "filterable": false + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false }, "mappings": [], "thresholds": { @@ -4044,9 +3911,16 @@ }, "id": 44, "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": ["sum"], + "show": false + }, "showHeader": true }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { "appInsights": { @@ -4055,9 +3929,10 @@ "timeGrain": "auto" }, "azureLogAnalytics": { + "dashboardTime": false, "query": "let system_databases = dynamic(['KustoMonitoringPersistentDatabase', '$systemdb']); \r\nlet system_users = dynamic(['AAD app id=b753584e-c468-4503-852a-374280ce7a62', 'KustoServiceBuiltInPrincipal']); // b753584e-c468-4503-852a-374280ce7a62 is Kusto Query Runner\r\nlet system_cluster_management_applications = dynamic(['Kusto.WinSvc.CM.Svc']); // Kusto Cluster Management\r\nlet CommandTable = ADXCommand\r\n | extend MemoryPeak = tolong(ResourceUtilization.MemoryPeak)\r\n | where LastUpdatedOn > ago(7d)\r\n | where DatabaseName !in (system_databases) and User !in (system_users) and ApplicationName !in (system_cluster_management_applications)\r\n | where ((false == \"false\" and ApplicationName != 'Kusto.WinSvc.DM.Svc') or false == \"true\")\r\n | parse _ResourceId with * \"providers/microsoft.kusto/clusters/\" cluster_name\r\n | project-away ResourceUtilization;\r\nlet QueryTable = ADXQuery\r\n | where LastUpdatedOn > ago(7d)\r\n | where DatabaseName !in (system_databases) and User !in (system_users) and ApplicationName !in (system_cluster_management_applications)\r\n | where ((false == \"false\" and ApplicationName != 'Kusto.WinSvc.DM.Svc') or false == \"true\")\r\n | extend MemoryPeak = tolong(MemoryPeak)\r\n | parse _ResourceId with * \"providers/microsoft.kusto/clusters/\" cluster_name\r\n | extend CommandType = 'Query';\r\nlet dataset_commands_queries = CommandTable\r\n | union (QueryTable)\r\n | project CommandType, DatabaseName, StartedOn, LastUpdatedOn, Duration, State,\r\n FailureReason, RootActivityId, User, ApplicationName, Principal, TotalCPU, MemoryPeak, CorrelationId, cluster_name;\r\nlet dataset = dataset_commands_queries\r\n | where cluster_name == 'mitulktest'\r\n | where CommandType != 'TableSetOrAppend'\r\n | summarize Count=count() by User, ApplicationName\r\n | project User, ApplicationName, Count\r\n | extend User = case(ApplicationName == \"Kusto.WinSvc.DM.Svc\", strcat(\"Kusto Data Management \", \"(\", User, \")\"),\r\n User == \"AAD app id=e0331ea9-83fc-4409-a17d-6375364c3280\", \"DataMap Agent 001 (app id: e0331ea9-83fc-4409-a17d-6375364c3280)\", // Used for internal MS clusters\r\n User)\r\n | top 10 by Count;\r\n//| order by Count desc\r\n//
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "$ws" - }, "azureMonitor": { "aggOptions": ["None", "Average", "Minimum", "Maximum", "Total", "Count"], "aggregation": "Average", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [ { @@ -133,8 +153,12 @@ "metricDefinition": "Microsoft.KeyVault/vaults", "metricName": "Availability", "metricNamespace": "Microsoft.KeyVault/vaults", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -176,30 +200,19 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" }, { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "$ws" - }, "azureMonitor": { "aggOptions": ["None", "Average", "Minimum", "Maximum", "Total", "Count"], "aggregation": "Count", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [ { @@ -222,8 +235,12 @@ "metricDefinition": "Microsoft.KeyVault/vaults", "metricName": "ServiceApiResult", "metricNamespace": "Microsoft.KeyVault/vaults", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "P1D", "timeGrains": [ { @@ -265,31 +282,20 @@ ], "top": "10" }, - "hide": false, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" }, + "hide": false, "queryType": "Azure Monitor", "refId": "B", - "subscription": "f7152080-b4e8-47ee-9c85-7f1d0e6b72dc" + "subscription": "$sub" }, { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "$ws" - }, "azureMonitor": { "aggOptions": ["None", "Average", "Minimum", "Maximum", "Total", "Count"], "aggregation": "Average", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [ { @@ -312,8 +318,12 @@ "metricDefinition": "Microsoft.KeyVault/vaults", "metricName": "ServiceApiLatency", "metricNamespace": "Microsoft.KeyVault/vaults", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "P1D", "timeGrains": [ { @@ -355,82 +365,104 @@ ], "top": "10" }, - "hide": false, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" }, + "hide": false, "queryType": "Azure Monitor", "refId": "C", - "subscription": "f7152080-b4e8-47ee-9c85-7f1d0e6b72dc" + "subscription": "$sub" } ], "title": "Availability, Requests and Latency", "type": "stat" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" + }, "fieldConfig": { "defaults": { - "custom": {} + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 8, "w": 6, "x": 0, "y": 8 }, - "hiddenSeries": false, "id": 11, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["sum"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "$ws" - }, "azureMonitor": { "aggOptions": ["None", "Average", "Minimum", "Maximum", "Total", "Count"], "aggregation": "Count", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [ { @@ -445,8 +477,12 @@ "metricDefinition": "Microsoft.KeyVault/vaults", "metricName": "ServiceApiHit", "metricNamespace": "Microsoft.KeyVault/vaults", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -488,125 +524,104 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" }, "queryType": "Azure Monitor", "refId": "A", - "subscription": "f7152080-b4e8-47ee-9c85-7f1d0e6b72dc" + "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Transactions Over Time", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" + }, "fieldConfig": { "defaults": { - "color": {}, - "custom": {}, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], "thresholds": { "mode": "absolute", - "steps": [] + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] }, "unit": "ms" }, "overrides": [] }, - "fill": 0, - "fillGradient": 0, "gridPos": { "h": 8, "w": 6, "x": 6, "y": 8 }, - "hiddenSeries": false, "id": 13, - "legend": { - "avg": true, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "connected", "options": { - "alertThreshold": true + "legend": { + "calcs": ["mean"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "$ws" - }, "azureMonitor": { "aggOptions": ["None", "Average", "Minimum", "Maximum", "Total", "Count"], "aggregation": "Average", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [ { @@ -629,8 +644,12 @@ "metricDefinition": "Microsoft.KeyVault/vaults", "metricName": "ServiceApiLatency", "metricNamespace": "Microsoft.KeyVault/vaults", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -672,119 +691,104 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Overall Latency", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "ms", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" + }, "fieldConfig": { "defaults": { - "custom": {} + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 8, "w": 6, "x": 12, "y": 8 }, - "hiddenSeries": false, "id": 15, - "legend": { - "avg": true, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["mean"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "$ws" - }, "azureMonitor": { "aggOptions": ["None", "Average", "Minimum", "Maximum", "Total", "Count"], "aggregation": "Average", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [ { @@ -807,8 +811,12 @@ "metricDefinition": "Microsoft.KeyVault/vaults", "metricName": "Availability", "metricNamespace": "Microsoft.KeyVault/vaults", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -850,119 +858,104 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Availability", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "percent", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" + }, "fieldConfig": { "defaults": { - "custom": {} + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 8, "w": 6, "x": 18, "y": 8 }, - "hiddenSeries": false, "id": 17, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["sum"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "$ws" - }, "azureMonitor": { "aggOptions": ["None", "Average", "Minimum", "Maximum", "Total", "Count"], "aggregation": "Count", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [ { @@ -977,8 +970,12 @@ "metricDefinition": "Microsoft.KeyVault/vaults", "metricName": "ServiceApiHit", "metricNamespace": "Microsoft.KeyVault/vaults", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -1020,59 +1017,23 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Request Types over Time", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { "collapsed": false, - "datasource": "$ds", + "datasource": { + "uid": "${ds}" + }, "gridPos": { "h": 1, "w": 24, @@ -1081,76 +1042,107 @@ }, "id": 23, "panels": [], + "targets": [ + { + "datasource": { + "uid": "${ds}" + }, + "refId": "A" + } + ], "title": "Failures", "type": "row" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" + }, "fieldConfig": { "defaults": { - "custom": {} + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 8, "w": 6, "x": 0, "y": 17 }, - "hiddenSeries": false, "id": 2, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["sum"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "$ws" - }, "azureMonitor": { "aggOptions": ["None", "Average", "Minimum", "Maximum", "Total", "Count"], "aggregation": "Count", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [ { "dimension": "StatusCodeClass", - "filter": "2xx", + "filters": ["2xx"], "operator": "eq" } ], @@ -1175,8 +1167,12 @@ "metricDefinition": "Microsoft.KeyVault/vaults", "metricName": "ServiceApiResult", "metricNamespace": "Microsoft.KeyVault/vaults", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -1218,123 +1214,108 @@ ], "top": "" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Successes (2xx)", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" + }, "fieldConfig": { "defaults": { - "custom": {} + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 8, "w": 6, "x": 6, "y": 17 }, - "hiddenSeries": false, "id": 7, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["sum"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "$ws" - }, "azureMonitor": { "aggOptions": ["None", "Average", "Minimum", "Maximum", "Total", "Count"], "aggregation": "Count", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [ { "dimension": "StatusCodeClass", - "filter": "4xx", + "filters": ["4xx"], "operator": "eq" } ], @@ -1359,8 +1340,12 @@ "metricDefinition": "Microsoft.KeyVault/vaults", "metricName": "ServiceApiResult", "metricNamespace": "Microsoft.KeyVault/vaults", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -1402,123 +1387,108 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Failures (4xx)", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" + }, "fieldConfig": { "defaults": { - "custom": {} + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 8, "w": 6, "x": 12, "y": 17 }, - "hiddenSeries": false, "id": 6, - "legend": { - "avg": true, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["mean"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "$ws" - }, "azureMonitor": { "aggOptions": ["None", "Average", "Minimum", "Maximum", "Total", "Count"], "aggregation": "Count", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [ { "dimension": "StatusCode", - "filter": "429", + "filters": ["429"], "operator": "eq" } ], @@ -1543,8 +1513,12 @@ "metricDefinition": "Microsoft.KeyVault/vaults", "metricName": "ServiceApiResult", "metricNamespace": "Microsoft.KeyVault/vaults", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -1586,123 +1560,108 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Throttling (429)", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" + }, "fieldConfig": { "defaults": { - "custom": {} + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 8, "w": 6, "x": 18, "y": 17 }, - "hiddenSeries": false, "id": 4, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["sum"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "$ws" - }, "azureMonitor": { "aggOptions": ["None", "Average", "Minimum", "Maximum", "Total", "Count"], "aggregation": "Count", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [ { "dimension": "StatusCode", - "filter": "401", + "filters": ["401"], "operator": "eq" } ], @@ -1727,8 +1686,12 @@ "metricDefinition": "Microsoft.KeyVault/vaults", "metricName": "ServiceApiResult", "metricNamespace": "Microsoft.KeyVault/vaults", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -1770,34 +1733,23 @@ ], "top": "10" }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" }, "queryType": "Azure Monitor", "refId": "A", "subscription": "$sub" }, { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, - "azureLogAnalytics": { - "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", - "resultFormat": "time_series", - "workspace": "$ws" - }, "azureMonitor": { "aggOptions": ["None", "Average", "Minimum", "Maximum", "Total", "Count"], "aggregation": "Count", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [ { "dimension": "StatusCode", - "filter": "403", + "filters": ["403"], "operator": "eq" } ], @@ -1822,8 +1774,12 @@ "metricDefinition": "Microsoft.KeyVault/vaults", "metricName": "ServiceApiResult", "metricNamespace": "Microsoft.KeyVault/vaults", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -1865,60 +1821,24 @@ ], "top": "10" }, - "hide": false, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" }, + "hide": false, "queryType": "Azure Monitor", "refId": "B", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Authentication Errors (401 & 403)", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { "collapsed": false, - "datasource": "$ds", + "datasource": { + "uid": "${ds}" + }, "gridPos": { "h": 1, "w": 24, @@ -1927,17 +1847,27 @@ }, "id": 21, "panels": [], + "targets": [ + { + "datasource": { + "uid": "${ds}" + }, + "refId": "A" + } + ], "title": "Operations", "type": "row" }, { - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" + }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, - "custom": {}, "mappings": [], "thresholds": { "mode": "absolute", @@ -1948,7 +1878,7 @@ }, "gridPos": { "h": 5, - "w": 3, + "w": 4, "x": 0, "y": 26 }, @@ -1963,184 +1893,142 @@ "fields": "", "values": false }, + "showPercentChange": false, "text": {}, - "textMode": "auto" + "textMode": "auto", + "wideLayout": true }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, "azureLogAnalytics": { "query": "let rawData = AzureDiagnostics \r\n // Ignore Authentication operations with a 401. This is normal when using Key Vault SDK, first an unauthenticated request is done then the response is used for authentication.\r\n | where Category == \"AuditEvent\" and not (OperationName == \"Authentication\" and httpStatusCode_d == 401)\r\n | where OperationName in ('SecretGet', 'VaultGet') or '*' in ('SecretGet', 'VaultGet')\r\n // Create ResultStatus with all the 'success' results bucked as 'Success'\r\n // Certain operations like StorageAccountAutoSyncKey have no ResultSignature, for now set to 'Success' as well\r\n | extend ResultStatus = case (ResultSignature == \"\", \"Success\",\r\n ResultSignature == \"OK\", \"Success\",\r\n ResultSignature == \"Accepted\", \"Success\",\r\n ResultSignature); \r\nrawData \r\n| make-series Trend = count() default = 0 on TimeGenerated from ago(1d) to now() step 30m by ResultStatus\r\n| join kind = inner (rawData\n | where $__timeFilter(TimeGenerated)\r\n | summarize Count = count() by ResultStatus\r\n )\r\n on ResultStatus\n \r\n\r\n| project ResultStatus, Count, Trend\r\n| order by Count desc;\r", "resultFormat": "table", "workspace": "$ws" }, - "azureMonitor": { - "aggOptions": [], - "dimensionFilter": "*", - "dimensionFilters": [], - "metricDefinition": "select", - "metricName": "select", - "metricNamespace": "select", - "resourceGroup": "select", - "resourceName": "select", - "timeGrain": "auto", - "timeGrains": [], - "top": "10" - }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" }, "queryType": "Azure Log Analytics", "refId": "A", "subscription": "$sub" } ], - "timeFrom": null, - "timeShift": null, "title": "Success Operations", "type": "stat" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" + }, "fieldConfig": { "defaults": { - "color": {}, - "custom": {}, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "points", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 6, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "always", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, "thresholds": { "mode": "absolute", - "steps": [] + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] }, "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 5, - "w": 7, - "x": 3, + "w": 8, + "x": 4, "y": 26 }, - "hiddenSeries": false, "id": 35, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": false, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": true, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, "azureLogAnalytics": { + "dashboardTime": false, "query": "let rawData = AzureDiagnostics \r\n // Ignore Authentication operations with a 401. This is normal when using Key Vault SDK, first an unauthenticated request is done then the response is used for authentication.\r\n | where Category == \"AuditEvent\" and not (OperationName == \"Authentication\" and httpStatusCode_d == 401)\r\n | where OperationName in ('SecretGet', 'VaultGet') or '*' in ('SecretGet', 'VaultGet')\r\n // Create ResultStatus with all the 'success' results bucked as 'Success'\r\n // Certain operations like StorageAccountAutoSyncKey have no ResultSignature, for now set to 'Success' as well\r\n | extend ResultStatus = case (ResultSignature == \"\", \"Success\",\r\n ResultSignature == \"OK\", \"Success\",\r\n ResultSignature == \"Accepted\", \"Success\",\r\n ResultSignature); \r\nrawData\n| where $__timeFilter(TimeGenerated)\n| extend resultCount = iif(ResultStatus == \"Success\", 1, 0)\n| summarize count(resultCount) by bin(TimeGenerated, 30m)\n| sort by TimeGenerated;\n\r\r\n\r", - "resultFormat": "table", - "workspace": "$ws" + "resources": ["$ws"], + "resultFormat": "table" }, - "azureMonitor": { - "aggOptions": [], - "dimensionFilter": "*", - "dimensionFilters": [], - "metricDefinition": "select", - "metricName": "select", - "metricNamespace": "select", - "resourceGroup": "select", - "resourceName": "select", - "timeGrain": "auto", - "timeGrains": [], - "top": "10" - }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" }, "queryType": "Azure Log Analytics", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Success Operations Counts", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" + }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, - "custom": {}, "mappings": [], "thresholds": { "mode": "absolute", @@ -2151,8 +2039,8 @@ }, "gridPos": { "h": 5, - "w": 3, - "x": 10, + "w": 4, + "x": 12, "y": 26 }, "id": 26, @@ -2166,186 +2054,149 @@ "fields": "", "values": true }, + "showPercentChange": false, "text": {}, - "textMode": "value" + "textMode": "value", + "wideLayout": true }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, "azureLogAnalytics": { "query": "let rawData = AzureDiagnostics \r\n // Ignore Authentication operations with a 401. This is normal when using Key Vault SDK, first an unauthenticated request is done then the response is used for authentication.\r\n | where Category == \"AuditEvent\" and not (OperationName == \"Authentication\" and httpStatusCode_d == 401)\r\n | where OperationName in ('SecretGet', 'VaultGet') or '*' in ('SecretGet', 'VaultGet')\r; \r\nrawData \r\n| make-series Trend = count() default = 0 on TimeGenerated from ago(1d) to now() step 30m by ResultSignature \n| join kind = inner (rawData\n | where $__timeFilter(TimeGenerated)\r\n | summarize Count = count() by ResultSignature \n )\r\n on ResultSignature \n\r\n\r\n| project ResultSignature , Count, Trend\r\n| order by Count desc;", "resultFormat": "table", "workspace": "$ws" }, - "azureMonitor": { - "aggOptions": [], - "dimensionFilter": "*", - "dimensionFilters": [], - "metricDefinition": "select", - "metricName": "select", - "metricNamespace": "select", - "resourceGroup": "select", - "resourceName": "select", - "timeGrain": "auto", - "timeGrains": [], - "top": "10" - }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" }, "queryType": "Azure Log Analytics", "refId": "A", "subscription": "$sub" } ], - "timeFrom": null, - "timeShift": null, "title": "All Operations", "type": "stat" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" + }, "fieldConfig": { "defaults": { - "color": {}, - "custom": {}, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "points", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 6, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "always", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, "thresholds": { "mode": "absolute", - "steps": [] + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] }, "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 5, - "w": 7, - "x": 13, + "w": 8, + "x": 16, "y": 26 }, - "hiddenSeries": false, "id": 36, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": false, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": true, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, "azureLogAnalytics": { + "dashboardTime": false, "query": "let rawData = AzureDiagnostics \r\n // Ignore Authentication operations with a 401. This is normal when using Key Vault SDK, first an unauthenticated request is done then the response is used for authentication.\r\n | where Category == \"AuditEvent\" and not (OperationName == \"Authentication\" and httpStatusCode_d == 401)\r\n | where OperationName in ('SecretGet', 'VaultGet') or '*' in ('SecretGet', 'VaultGet')\r; \r\nrawData\n| where $__timeFilter(TimeGenerated)\n| summarize count(ResultSignature ) by bin(TimeGenerated, 30m)\n| sort by TimeGenerated;\n\r\r\n\r", - "resultFormat": "table", - "workspace": "$ws" + "resources": ["$ws"], + "resultFormat": "table" }, - "azureMonitor": { - "aggOptions": [], - "dimensionFilter": "*", - "dimensionFilters": [], - "metricDefinition": "select", - "metricName": "select", - "metricNamespace": "select", - "resourceGroup": "select", - "resourceName": "select", - "timeGrain": "auto", - "timeGrains": [], - "top": "10" - }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" }, "queryType": "Azure Log Analytics", "refId": "A", "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "All Operations Counts", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" + }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, "custom": { - "align": null, - "filterable": false + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false }, "mappings": [], "thresholds": { @@ -2372,37 +2223,26 @@ }, "id": 28, "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": ["sum"], + "show": false + }, "showHeader": true }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, "azureLogAnalytics": { "query": "let data = AzureDiagnostics \r\n | where TimeGenerated > ago(1d)\r\n // Ignore Authentication operations with a 401. This is normal when using Key Vault SDK, first an unauthenticated request is done then the response is used for authentication.\r\n | where Category == \"AuditEvent\" and not (OperationName == \"Authentication\" and httpStatusCode_d == 401)\r\n | where OperationName in ('SecretGet', 'VaultGet') or '*' in ('SecretGet', 'VaultGet')\r\n // Create ResultStatus with all the 'success' results bucked as 'Success'\r\n // Certain operations like StorageAccountAutoSyncKey have no ResultSignature, for now set to 'Success' as well\r\n | extend ResultStatus = case (ResultSignature == \"\", \"Success\",\r\n ResultSignature == \"OK\", \"Success\",\r\n ResultSignature == \"Accepted\", \"Success\",\r\n ResultSignature)\r\n | where ResultStatus == 'All' or 'All' == 'All';\r\ndata\r\n// Data aggregated to the OperationName\r\n| summarize OperationCount = count(), SuccessCount = countif(ResultStatus == \"Success\"), FailureCount = countif(ResultStatus != \"Success\"), PDurationMs = percentile(DurationMs, 99) by Resource, OperationName\r\n| join kind=inner (data\r\n | make-series Trend = count() default = 0 on TimeGenerated from ago(1d) to now() step 30m by OperationName\r\n | project-away TimeGenerated)\r\n on OperationName\r\n| order by OperationCount desc\r\n| project Name = strcat('⚡ ', OperationName), Id = strcat(Resource, '/', OperationName), ['Operation count'] = OperationCount, ['Operation count trend'] = Trend, ['Success count'] = SuccessCount, ['Failure count'] = FailureCount, ['p99 Duration'] = PDurationMs", "resultFormat": "time_series", "workspace": "$ws" }, - "azureMonitor": { - "aggOptions": [], - "dimensionFilter": "*", - "dimensionFilters": [], - "metricDefinition": "select", - "metricName": "select", - "metricNamespace": "select", - "resourceGroup": "select", - "resourceName": "select", - "timeGrain": "auto", - "timeGrains": [], - "top": "10" - }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" }, "queryType": "Azure Log Analytics", "refId": "A", @@ -2413,15 +2253,22 @@ "type": "table" }, { - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" + }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, "custom": { - "align": null, - "filterable": false + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false }, "mappings": [], "thresholds": { @@ -2497,38 +2344,27 @@ }, "id": 30, "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": ["sum"], + "show": false + }, "showHeader": true, "sortBy": [] }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { - "appInsights": { - "dimension": [], - "metricName": "select", - "timeGrain": "auto" - }, "azureLogAnalytics": { "query": "let gridRowSelected = dynamic({\"Id\": \"*\"});\r\nlet resourceName = split(gridRowSelected.Id, \"/\")[0];\r\nlet operationName = split(gridRowSelected.Id, \"/\")[1];\r\nAzureDiagnostics \r\n| where TimeGenerated > ago(1d)\r\n// Ignore Authentication operations with a 401. This is normal when using Key Vault SDK, first an unauthenticated request is done then the response is used for authentication.\r\n| where Category == \"AuditEvent\" and not (OperationName == \"Authentication\" and httpStatusCode_d == 401)\r\n| where OperationName in ('SecretGet', 'VaultGet') or '*' in ('SecretGet', 'VaultGet')\r\n| where resourceName == \"*\" or Resource == resourceName\r\n| where operationName == \"\" or OperationName == operationName\r\n// Create ResultStatus with all the 'success' results bucked as 'Success'\r\n// Certain operations like StorageAccountAutoSyncKey have no ResultSignature, for now set to 'Success' as well\r\n| extend ResultStatus = case (ResultSignature == \"\", \"Success\",\r\n ResultSignature == \"OK\", \"Success\",\r\n ResultSignature == \"Accepted\", \"Success\",\r\n ResultSignature)\r\n| where ResultStatus == 'All' or 'All' == 'All'\r\n| extend p = pack_all()\r\n| mv-apply p on \r\n ( \r\n extend key = tostring(bag_keys(p)[0])\r\n | where isnotempty(p[key]) and isnotnull(p[key])\r\n | where key !in (\"SourceSystem\", \"Type\")\r\n | summarize make_bag(p)\r\n )\r\n| project Time=TimeGenerated, Operation=OperationName, Result=ResultSignature, Duration = DurationMs, [\"Details\"]=bag_p\r\n| sort by Time desc", "resultFormat": "time_series", "workspace": "$ws" }, - "azureMonitor": { - "aggOptions": [], - "dimensionFilter": "*", - "dimensionFilters": [], - "metricDefinition": "select", - "metricName": "select", - "metricNamespace": "select", - "resourceGroup": "select", - "resourceName": "select", - "timeGrain": "auto", - "timeGrains": [], - "top": "10" - }, - "insightsAnalytics": { - "query": "", - "resultFormat": "time_series" + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" }, "queryType": "Azure Log Analytics", "refId": "A", @@ -2540,17 +2376,19 @@ } ], "refresh": false, - "schemaVersion": 27, + "schemaVersion": 39, "tags": [], "templating": { "list": [ { - "current": {}, - "description": null, - "error": null, + "current": { + "selected": false, + "text": "Azure Monitor", + "value": "azure-monitor-oob" + }, "hide": 0, "includeAll": false, - "label": "Data Source", + "label": "Datasource", "multi": false, "name": "ds", "options": [], @@ -2562,56 +2400,31 @@ "type": "datasource" }, { - "allValue": null, "current": {}, - "datasource": "$ds", - "definition": "subscriptions()", - "description": null, - "error": null, + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" + }, + "definition": "", "hide": 0, "includeAll": false, - "label": "subscription", + "label": "Subscription", "multi": false, "name": "sub", "options": [], - "query": "subscriptions()", - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "sort": 5, - "tagValuesQuery": "", - "tags": [], - "tagsQuery": "", - "type": "query", - "useTags": false - }, - { - "allValue": null, - "current": {}, - "datasource": "$ds", - "definition": "", - "description": null, - "error": null, - "hide": 0, - "includeAll": false, - "label": "Resource Group", - "multi": false, - "name": "rg", - "options": [], "query": { - "azureResourceGraph": { - "query": "resources\r\n| where [\"type\"] =~ \"Microsoft.KeyVault/vaults\"\r\n| distinct resourceGroup" + "grafanaTemplateVariableFn": { + "kind": "SubscriptionsQuery", + "rawQuery": "subscriptions()" }, - "queryType": "Azure Resource Graph", - "refId": "A", - "subscriptions": ["$sub"] + "queryType": "Azure Subscriptions", + "refId": "A" }, "refresh": 1, "regex": "", "skipUrlSync": false, "sort": 5, "tagValuesQuery": "", - "tags": [], "tagsQuery": "", "type": "query", "useTags": false @@ -2623,40 +2436,72 @@ "uid": "${ds}" }, "definition": "", - "hide": 2, + "hide": 0, "includeAll": false, - "label": "Namespace", + "label": "Resource Group", "multi": false, - "name": "ns", + "name": "rg", "options": [], "query": { - "azureResourceGraph": { - "query": "resources\r\n| where [\"type\"] =~ \"Microsoft.KeyVault/vaults\"\r\n| distinct [\"type\"]" + "grafanaTemplateVariableFn": { + "kind": "ResourceGroupsQuery", + "rawQuery": "ResourceGroups($sub)", + "subscription": "$sub" }, - "queryType": "Azure Resource Graph", + "queryType": "Azure Resource Groups", "refId": "A", - "subscriptions": ["$sub"] + "subscription": "$sub" }, "refresh": 1, "regex": "", "skipUrlSync": false, "sort": 5, - "type": "query" + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "hide": 2, + "label": "Namespace", + "name": "ns", + "query": "Microsoft.KeyVault/vaults", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "Microsoft.KeyVault/vaults", + "text": "Microsoft.KeyVault/vaults", + "selected": false + }, + "options": [ + { + "value": "Microsoft.KeyVault/vaults", + "text": "Microsoft.KeyVault/vaults", + "selected": false + } + ] }, { - "allValue": null, "current": {}, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" + }, "definition": "", - "description": null, - "error": null, "hide": 0, "includeAll": false, - "label": null, + "label": "Resource", "multi": false, "name": "resource", "options": [], "query": { + "grafanaTemplateVariableFn": { + "kind": "ResourceNamesQuery", + "metricNamespace": "$ns", + "rawQuery": "ResourceNames($sub, $rg, $ns)", + "resourceGroup": "$rg", + "subscription": "$sub" + }, "namespace": "$ns", "queryType": "Azure Resource Names", "refId": "A", @@ -2668,31 +2513,38 @@ "skipUrlSync": false, "sort": 5, "tagValuesQuery": "", - "tags": [], "tagsQuery": "", "type": "query", "useTags": false }, { - "allValue": null, "current": {}, - "datasource": "$ds", - "definition": "Workspaces($sub)", - "description": null, - "error": null, + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${ds}" + }, + "definition": "", "hide": 0, "includeAll": false, "label": "Workspace", "multi": false, "name": "ws", "options": [], - "query": "Workspaces($sub)", + "query": { + "grafanaTemplateVariableFn": { + "kind": "WorkspacesQuery", + "rawQuery": "Workspaces($sub)", + "subscription": "$sub" + }, + "queryType": "Azure Workspaces", + "refId": "A", + "subscription": "$sub" + }, "refresh": 1, "regex": "", "skipUrlSync": false, "sort": 5, "tagValuesQuery": "", - "tags": [], "tagsQuery": "", "type": "query", "useTags": false @@ -2705,7 +2557,8 @@ }, "timepicker": {}, "timezone": "", - "title": "Azure / Insights / Key vaults", + "title": "Azure / Insights / Key Vaults", "uid": "tQZAMYrMk", - "version": 42 + "version": 43, + "weekStart": "" } diff --git a/public/app/plugins/datasource/azuremonitor/dashboards/storage.json b/public/app/plugins/datasource/azuremonitor/dashboards/storage.json index fcdf9e7c8d6..397327665ed 100644 --- a/public/app/plugins/datasource/azuremonitor/dashboards/storage.json +++ b/public/app/plugins/datasource/azuremonitor/dashboards/storage.json @@ -1,4 +1,6 @@ { + "__inputs": [], + "__elements": {}, "__requires": [ { "type": "panel", @@ -10,19 +12,13 @@ "type": "grafana", "id": "grafana", "name": "Grafana", - "version": "7.4.3" + "version": "10.4.7" }, { "type": "datasource", "id": "grafana-azure-monitor-datasource", "name": "Azure Monitor", - "version": "0.3.0" - }, - { - "type": "panel", - "id": "graph", - "name": "Graph", - "version": "" + "version": "1.0.0" }, { "type": "panel", @@ -44,23 +40,36 @@ } ], "annotations": { - "list": [] + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] }, "editable": true, - "gnetId": null, + "fiscalYearStartMonth": 0, "graphTooltip": 0, "id": null, - "iteration": 1620257813794, "links": [], "panels": [ { - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, - "custom": {}, "mappings": [], "thresholds": { "mode": "percentage", @@ -80,12 +89,14 @@ }, "gridPos": { "h": 4, - "w": 3, + "w": 4, "x": 0, - "y": 1 + "y": 0 }, "id": 7, "options": { + "minVizHeight": 75, + "minVizWidth": 75, "orientation": "auto", "reduceOptions": { "calcs": ["lastNotNull"], @@ -94,9 +105,10 @@ }, "showThresholdLabels": false, "showThresholdMarkers": false, + "sizing": "auto", "text": {} }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { "appInsights": { @@ -176,6 +188,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "insightsAnalytics": { "query": "", "resultFormat": "time_series" @@ -185,21 +200,20 @@ "subscription": "$sub" } ], - "timeFrom": null, - "timeShift": null, "title": "Availability", "transparent": true, "type": "gauge" }, { - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "fixedColor": "blue", "mode": "fixed" }, - "custom": {}, "mappings": [], "thresholds": { "mode": "absolute", @@ -215,9 +229,9 @@ }, "gridPos": { "h": 4, - "w": 3, - "x": 3, - "y": 1 + "w": 4, + "x": 4, + "y": 0 }, "id": 6, "options": { @@ -230,10 +244,12 @@ "fields": "", "values": false }, + "showPercentChange": false, "text": {}, - "textMode": "value_and_name" + "textMode": "value_and_name", + "wideLayout": true }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { "appInsights": { @@ -316,6 +332,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "insightsAnalytics": { "query": "", "resultFormat": "time_series" @@ -325,19 +344,19 @@ "subscription": "$sub" } ], - "title": "", "transparent": true, "type": "stat" }, { - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "fixedColor": "purple", "mode": "fixed" }, - "custom": {}, "mappings": [], "thresholds": { "mode": "absolute", @@ -353,9 +372,9 @@ }, "gridPos": { "h": 4, - "w": 3, - "x": 6, - "y": 1 + "w": 4, + "x": 8, + "y": 0 }, "id": 8, "options": { @@ -368,10 +387,12 @@ "fields": "", "values": false }, + "showPercentChange": false, "text": {}, - "textMode": "value_and_name" + "textMode": "value_and_name", + "wideLayout": true }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { "appInsights": { @@ -450,6 +471,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "insightsAnalytics": { "query": "", "resultFormat": "time_series" @@ -459,19 +483,19 @@ "subscription": "$sub" } ], - "title": "", "transparent": true, "type": "stat" }, { - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "fixedColor": "purple", "mode": "fixed" }, - "custom": {}, "mappings": [], "thresholds": { "mode": "absolute", @@ -487,9 +511,9 @@ }, "gridPos": { "h": 4, - "w": 3, - "x": 9, - "y": 1 + "w": 4, + "x": 12, + "y": 0 }, "id": 9, "options": { @@ -502,10 +526,12 @@ "fields": "", "values": false }, + "showPercentChange": false, "text": {}, - "textMode": "value_and_name" + "textMode": "value_and_name", + "wideLayout": true }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { "appInsights": { @@ -584,6 +610,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "insightsAnalytics": { "query": "", "resultFormat": "time_series" @@ -593,19 +622,19 @@ "subscription": "$sub" } ], - "title": "", "transparent": true, "type": "stat" }, { - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "fixedColor": "blue", "mode": "fixed" }, - "custom": {}, "mappings": [], "thresholds": { "mode": "absolute", @@ -621,9 +650,9 @@ }, "gridPos": { "h": 4, - "w": 3, - "x": 12, - "y": 1 + "w": 4, + "x": 16, + "y": 0 }, "id": 10, "options": { @@ -636,10 +665,12 @@ "fields": "", "values": false }, + "showPercentChange": false, "text": {}, - "textMode": "value_and_name" + "textMode": "value_and_name", + "wideLayout": true }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { "appInsights": { @@ -718,6 +749,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "insightsAnalytics": { "query": "", "resultFormat": "time_series" @@ -727,19 +761,19 @@ "subscription": "$sub" } ], - "title": "", "transparent": true, "type": "stat" }, { - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "fixedColor": "blue", "mode": "fixed" }, - "custom": {}, "mappings": [], "thresholds": { "mode": "absolute", @@ -755,9 +789,9 @@ }, "gridPos": { "h": 4, - "w": 3, - "x": 15, - "y": 1 + "w": 4, + "x": 20, + "y": 0 }, "id": 11, "options": { @@ -770,10 +804,12 @@ "fields": "", "values": false }, + "showPercentChange": false, "text": {}, - "textMode": "value_and_name" + "textMode": "value_and_name", + "wideLayout": true }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { "appInsights": { @@ -852,6 +888,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "insightsAnalytics": { "query": "", "resultFormat": "time_series" @@ -861,62 +900,89 @@ "subscription": "$sub" } ], - "title": "", "transparent": true, "type": "stat" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { - "color": {}, - "custom": {}, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], "thresholds": { "mode": "absolute", - "steps": [] + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] }, "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 9, "w": 12, "x": 0, - "y": 5 + "y": 4 }, - "hiddenSeries": false, "id": 2, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null as zero", "options": { - "alertThreshold": true + "legend": { + "calcs": ["sum"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { "appInsights": { @@ -925,6 +991,7 @@ "timeGrain": "auto" }, "azureLogAnalytics": { + "dashboardTime": false, "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", "resultFormat": "time_series", "workspace": "00000000-0000-0000-0000-000000000000" @@ -934,7 +1001,6 @@ "aggregation": "Total", "alias": "Table transactions", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [ { @@ -957,8 +1023,12 @@ "metricDefinition": "$ns/tableServices", "metricName": "Transactions", "metricNamespace": "Microsoft.Storage/storageAccounts/tableServices", - "resourceGroup": "$rg", - "resourceName": "$resource/default", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource/default" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -1000,6 +1070,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "insightsAnalytics": { "query": "", "resultFormat": "time_series" @@ -1015,6 +1088,7 @@ "timeGrain": "auto" }, "azureLogAnalytics": { + "dashboardTime": false, "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", "resultFormat": "time_series", "workspace": "00000000-0000-0000-0000-000000000000" @@ -1024,7 +1098,6 @@ "aggregation": "Total", "alias": "Blob transactions", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [ { @@ -1047,8 +1120,12 @@ "metricDefinition": "$ns/blobServices", "metricName": "Transactions", "metricNamespace": "Microsoft.Storage/storageAccounts/blobServices", - "resourceGroup": "$rg", - "resourceName": "$resource/default", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource/default" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -1090,6 +1167,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -1106,6 +1186,7 @@ "timeGrain": "auto" }, "azureLogAnalytics": { + "dashboardTime": false, "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", "resultFormat": "time_series", "workspace": "00000000-0000-0000-0000-000000000000" @@ -1115,7 +1196,6 @@ "aggregation": "Total", "alias": "File transactions", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [ { @@ -1142,8 +1222,12 @@ "metricDefinition": "$ns/fileServices", "metricName": "Transactions", "metricNamespace": "Microsoft.Storage/storageAccounts/fileServices", - "resourceGroup": "$rg", - "resourceName": "$resource/default", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource/default" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -1185,6 +1269,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -1201,6 +1288,7 @@ "timeGrain": "auto" }, "azureLogAnalytics": { + "dashboardTime": false, "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", "resultFormat": "time_series", "workspace": "00000000-0000-0000-0000-000000000000" @@ -1210,7 +1298,6 @@ "aggregation": "Total", "alias": "Queue transactions", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [ { @@ -1233,8 +1320,12 @@ "metricDefinition": "$ns/queueServices", "metricName": "Transactions", "metricNamespace": "Microsoft.Storage/storageAccounts/queueServices", - "resourceGroup": "$rg", - "resourceName": "$resource/default", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource/default" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -1276,6 +1367,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -1286,102 +1380,89 @@ "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Transactions by storage type", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "transformations": [], - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { - "color": {}, - "custom": {}, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], "thresholds": { "mode": "absolute", - "steps": [] + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] }, "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 9, "w": 12, "x": 12, - "y": 5 + "y": 4 }, - "hiddenSeries": false, "id": 14, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["sum"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { "appInsights": { @@ -1390,6 +1471,7 @@ "timeGrain": "auto" }, "azureLogAnalytics": { + "dashboardTime": false, "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", "resultFormat": "time_series", "workspace": "00000000-0000-0000-0000-000000000000" @@ -1399,7 +1481,6 @@ "aggregation": "Total", "alias": "", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [ { "dimension": "ApiName", @@ -1428,8 +1509,12 @@ "metricDefinition": "$ns", "metricName": "Transactions", "metricNamespace": "Microsoft.Storage/storageAccounts", - "resourceGroup": "$rg", - "resourceName": "$resource", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -1471,6 +1556,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "insightsAnalytics": { "query": "", "resultFormat": "time_series" @@ -1480,56 +1568,22 @@ "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Transactions by API Name", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "transformations": [], - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -1539,8 +1593,10 @@ "hideFrom": { "graph": false, "legend": false, - "tooltip": false + "tooltip": false, + "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -1548,7 +1604,14 @@ "type": "linear" }, "showPoints": "never", - "spanNulls": true + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } }, "mappings": [], "thresholds": { @@ -1572,17 +1635,19 @@ "h": 9, "w": 12, "x": 0, - "y": 14 + "y": 13 }, "id": 13, "options": { "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, - "tooltipOptions": { - "mode": "multi" + "tooltip": { + "mode": "multi", + "sort": "none" } }, "pluginVersion": "7.4.3", @@ -1624,6 +1689,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "insightsAnalytics": { "query": "", "resultFormat": "time_series" @@ -1678,6 +1746,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -1729,6 +1800,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -1775,6 +1849,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -1785,20 +1862,22 @@ "subscription": "$sub" } ], - "timeFrom": null, - "timeShift": null, "title": "Capacity by storage type", - "transformations": [], "type": "timeseries" }, { - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -1808,8 +1887,10 @@ "hideFrom": { "graph": false, "legend": false, - "tooltip": false + "tooltip": false, + "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineStyle": { "fill": "solid" @@ -1820,7 +1901,14 @@ "type": "linear" }, "showPoints": "never", - "spanNulls": true + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } }, "mappings": [], "thresholds": { @@ -1840,17 +1928,19 @@ "h": 9, "w": 12, "x": 12, - "y": 14 + "y": 13 }, "id": 12, "options": { "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, - "tooltipOptions": { - "mode": "single" + "tooltip": { + "mode": "single", + "sort": "none" } }, "pluginVersion": "7.4.3", @@ -1933,6 +2023,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "insightsAnalytics": { "query": "", "resultFormat": "time_series" @@ -2019,6 +2112,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -2110,6 +2206,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -2197,6 +2296,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -2207,34 +2309,42 @@ "subscription": "$sub" } ], - "timeFrom": null, - "timeShift": null, "title": "Availability by storage type", - "transformations": [], "type": "timeseries" }, { "collapsed": false, - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "gridPos": { "h": 1, "w": 24, "x": 0, - "y": 23 + "y": 22 }, "id": 52, "panels": [], + "targets": [ + { + "datasource": { + "uid": "$ds" + }, + "refId": "A" + } + ], "title": "Failures", "type": "row" }, { - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, - "custom": {}, "mappings": [], "thresholds": { "mode": "absolute", @@ -2284,7 +2394,7 @@ "h": 6, "w": 6, "x": 0, - "y": 24 + "y": 23 }, "id": 16, "options": { @@ -2297,10 +2407,12 @@ "fields": "", "values": false }, + "showPercentChange": false, "text": {}, - "textMode": "auto" + "textMode": "auto", + "wideLayout": true }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { "appInsights": { @@ -2389,6 +2501,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "insightsAnalytics": { "query": "", "resultFormat": "time_series" @@ -2398,13 +2513,12 @@ "subscription": "$sub" } ], - "timeFrom": null, - "timeShift": null, - "title": "", "type": "stat" }, { - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { @@ -2412,6 +2526,9 @@ "mode": "fixed" }, "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -2421,8 +2538,10 @@ "hideFrom": { "graph": false, "legend": false, - "tooltip": false + "tooltip": false, + "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -2430,7 +2549,14 @@ "type": "linear" }, "showPoints": "never", - "spanNulls": true + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } }, "mappings": [], "thresholds": { @@ -2466,17 +2592,19 @@ "h": 6, "w": 18, "x": 6, - "y": 24 + "y": 23 }, "id": 18, "options": { "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, - "tooltipOptions": { - "mode": "single" + "tooltip": { + "mode": "single", + "sort": "none" } }, "pluginVersion": "7.4.3", @@ -2569,6 +2697,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "insightsAnalytics": { "query": "", "resultFormat": "time_series" @@ -2578,21 +2709,24 @@ "subscription": "$sub" } ], - "timeFrom": null, - "timeShift": null, - "title": "", "type": "timeseries" }, { - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, "custom": { - "align": null, - "filterable": false + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false }, "mappings": [], "thresholds": { @@ -2613,8 +2747,11 @@ }, "properties": [ { - "id": "custom.displayMode", - "value": "basic" + "id": "custom.cellOptions", + "value": { + "mode": "basic", + "type": "gauge" + } } ] } @@ -2624,13 +2761,20 @@ "h": 8, "w": 12, "x": 0, - "y": 30 + "y": 29 }, "id": 20, "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": ["sum"], + "show": false + }, "showHeader": false }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { "appInsights": { @@ -2725,6 +2869,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "insightsAnalytics": { "query": "", "resultFormat": "time_series" @@ -2746,15 +2893,21 @@ "type": "table" }, { - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, "custom": { - "align": null, - "filterable": false + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false }, "mappings": [], "thresholds": { @@ -2775,8 +2928,11 @@ }, "properties": [ { - "id": "custom.displayMode", - "value": "basic" + "id": "custom.cellOptions", + "value": { + "mode": "basic", + "type": "gauge" + } } ] } @@ -2786,13 +2942,20 @@ "h": 8, "w": 12, "x": 12, - "y": 30 + "y": 29 }, "id": 22, "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": ["sum"], + "show": false + }, "showHeader": false }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { "appInsights": { @@ -2891,6 +3054,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "insightsAnalytics": { "query": "", "resultFormat": "time_series" @@ -2912,15 +3078,21 @@ "type": "table" }, { - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, "custom": { - "align": null, - "filterable": false + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false }, "mappings": [], "thresholds": { @@ -2941,8 +3113,11 @@ }, "properties": [ { - "id": "custom.displayMode", - "value": "basic" + "id": "custom.cellOptions", + "value": { + "mode": "basic", + "type": "gauge" + } } ] } @@ -2952,13 +3127,20 @@ "h": 8, "w": 12, "x": 0, - "y": 38 + "y": 37 }, "id": 24, "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": ["sum"], + "show": false + }, "showHeader": false }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { "appInsights": { @@ -3053,6 +3235,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "insightsAnalytics": { "query": "", "resultFormat": "time_series" @@ -3074,15 +3259,21 @@ "type": "table" }, { - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, "custom": { - "align": null, - "filterable": false + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false }, "mappings": [], "thresholds": { @@ -3103,8 +3294,11 @@ }, "properties": [ { - "id": "custom.displayMode", - "value": "basic" + "id": "custom.cellOptions", + "value": { + "mode": "basic", + "type": "gauge" + } } ] } @@ -3114,13 +3308,20 @@ "h": 8, "w": 12, "x": 12, - "y": 38 + "y": 37 }, "id": 26, "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": ["sum"], + "show": false + }, "showHeader": false }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { "appInsights": { @@ -3215,6 +3416,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "insightsAnalytics": { "query": "", "resultFormat": "time_series" @@ -3237,26 +3441,37 @@ }, { "collapsed": false, - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "gridPos": { "h": 1, "w": 24, "x": 0, - "y": 46 + "y": 45 }, "id": 50, "panels": [], + "targets": [ + { + "datasource": { + "uid": "$ds" + }, + "refId": "A" + } + ], "title": "Performance", "type": "row" }, { - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, - "custom": {}, "mappings": [], "thresholds": { "mode": "absolute", @@ -3290,7 +3505,7 @@ "h": 6, "w": 6, "x": 0, - "y": 47 + "y": 46 }, "id": 28, "options": { @@ -3303,10 +3518,12 @@ "fields": "", "values": false }, + "showPercentChange": false, "text": {}, - "textMode": "auto" + "textMode": "auto", + "wideLayout": true }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { "appInsights": { @@ -3385,6 +3602,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "insightsAnalytics": { "query": "", "resultFormat": "time_series" @@ -3470,6 +3690,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -3480,17 +3703,21 @@ "subscription": "$sub" } ], - "title": "", "type": "stat" }, { - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -3500,8 +3727,10 @@ "hideFrom": { "graph": false, "legend": false, - "tooltip": false + "tooltip": false, + "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -3509,7 +3738,14 @@ "type": "linear" }, "showPoints": "auto", - "spanNulls": false + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } }, "mappings": [], "thresholds": { @@ -3544,17 +3780,19 @@ "h": 6, "w": 18, "x": 6, - "y": 47 + "y": 46 }, "id": 30, "options": { "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, - "tooltipOptions": { - "mode": "single" + "tooltip": { + "mode": "single", + "sort": "none" } }, "pluginVersion": "7.4.3", @@ -3636,6 +3874,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "insightsAnalytics": { "query": "", "resultFormat": "time_series" @@ -3721,6 +3962,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -3731,19 +3975,24 @@ "subscription": "$sub" } ], - "title": "", "type": "timeseries" }, { - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, "custom": { - "align": null, - "filterable": false + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false }, "mappings": [], "thresholds": { @@ -3765,8 +4014,11 @@ }, "properties": [ { - "id": "custom.displayMode", - "value": "lcd-gauge" + "id": "custom.cellOptions", + "value": { + "mode": "lcd", + "type": "gauge" + } }, { "id": "color", @@ -3783,8 +4035,11 @@ }, "properties": [ { - "id": "custom.displayMode", - "value": "gradient-gauge" + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } }, { "id": "color", @@ -3802,8 +4057,11 @@ }, "properties": [ { - "id": "custom.displayMode", - "value": "gradient-gauge" + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } }, { "id": "color", @@ -3832,13 +4090,20 @@ "h": 11, "w": 24, "x": 0, - "y": 53 + "y": 52 }, "id": 32, "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": ["sum"], + "show": false + }, "showHeader": true }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { "appInsights": { @@ -3923,6 +4188,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "insightsAnalytics": { "query": "", "resultFormat": "time_series" @@ -4014,6 +4282,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -4024,7 +4295,6 @@ "subscription": "$sub" } ], - "title": "", "transformations": [ { "id": "reduce", @@ -4051,27 +4321,38 @@ }, { "collapsed": false, - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "gridPos": { "h": 1, "w": 24, "x": 0, - "y": 64 + "y": 63 }, "id": 48, "panels": [], + "targets": [ + { + "datasource": { + "uid": "$ds" + }, + "refId": "A" + } + ], "title": "Availability", "type": "row" }, { - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "description": "The data comes from Storage metrics. It measures the availability of requests on Storage accounts.", "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, - "custom": {}, "mappings": [], "thresholds": { "mode": "percentage", @@ -4093,10 +4374,12 @@ "h": 8, "w": 24, "x": 0, - "y": 65 + "y": 64 }, "id": 34, "options": { + "minVizHeight": 75, + "minVizWidth": 75, "orientation": "auto", "reduceOptions": { "calcs": ["lastNotNull"], @@ -4105,9 +4388,10 @@ }, "showThresholdLabels": false, "showThresholdMarkers": false, + "sizing": "auto", "text": {} }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { "appInsights": { @@ -4187,6 +4471,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "insightsAnalytics": { "query": "", "resultFormat": "time_series" @@ -4273,6 +4560,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -4360,6 +4650,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -4451,6 +4744,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -4538,6 +4834,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -4548,19 +4847,24 @@ "subscription": "$sub" } ], - "title": "", "type": "gauge" }, { - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, "custom": { - "align": null, - "filterable": false + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false }, "mappings": [], "thresholds": { @@ -4580,8 +4884,11 @@ "value": "percent" }, { - "id": "custom.displayMode", - "value": "color-background" + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "color-background" + } }, { "id": "color", @@ -4597,14 +4904,21 @@ "h": 8, "w": 12, "x": 0, - "y": 73 + "y": 72 }, "id": 36, "maxDataPoints": 1, "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": ["sum"], + "show": false + }, "showHeader": false }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { "appInsights": { @@ -4690,6 +5004,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "insightsAnalytics": { "query": "", "resultFormat": "time_series" @@ -4782,6 +5099,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -4879,6 +5199,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -4972,6 +5295,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -4982,8 +5308,6 @@ "subscription": "$sub" } ], - "timeFrom": null, - "timeShift": null, "title": "Availability by API name", "transformations": [ { @@ -4998,57 +5322,85 @@ "type": "table" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { - "color": {}, - "custom": {}, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], "thresholds": { "mode": "absolute", - "steps": [] + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] }, "unit": "percent" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 8, "w": 12, "x": 12, - "y": 73 + "y": 72 }, - "hiddenSeries": false, "id": 38, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": ["sum"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { "appInsights": { @@ -5057,6 +5409,7 @@ "timeGrain": "auto" }, "azureLogAnalytics": { + "dashboardTime": false, "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", "resultFormat": "time_series", "workspace": "00000000-0000-0000-0000-000000000000" @@ -5066,7 +5419,6 @@ "aggregation": "Average", "alias": "Blob Availability", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [ { @@ -5085,8 +5437,12 @@ "metricDefinition": "$ns/blobServices", "metricName": "Availability", "metricNamespace": "Microsoft.Storage/storageAccounts/blobServices", - "resourceGroup": "$rg", - "resourceName": "$resource/default", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource/default" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -5128,6 +5484,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "insightsAnalytics": { "query": "", "resultFormat": "time_series" @@ -5143,6 +5502,7 @@ "timeGrain": "auto" }, "azureLogAnalytics": { + "dashboardTime": false, "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", "resultFormat": "time_series", "workspace": "00000000-0000-0000-0000-000000000000" @@ -5152,7 +5512,6 @@ "aggregation": "Average", "alias": "Table Availability", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [ { @@ -5171,8 +5530,12 @@ "metricDefinition": "$ns/tableServices", "metricName": "Availability", "metricNamespace": "Microsoft.Storage/storageAccounts/tableServices", - "resourceGroup": "$rg", - "resourceName": "$resource/default", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource/default" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -5214,6 +5577,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -5230,6 +5596,7 @@ "timeGrain": "auto" }, "azureLogAnalytics": { + "dashboardTime": false, "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", "resultFormat": "time_series", "workspace": "00000000-0000-0000-0000-000000000000" @@ -5239,7 +5606,6 @@ "aggregation": "Average", "alias": "File Availability", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [ { @@ -5262,8 +5628,12 @@ "metricDefinition": "$ns/fileServices", "metricName": "Availability", "metricNamespace": "Microsoft.Storage/storageAccounts/fileServices", - "resourceGroup": "$rg", - "resourceName": "$resource/default", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource/default" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -5305,6 +5675,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -5321,6 +5694,7 @@ "timeGrain": "auto" }, "azureLogAnalytics": { + "dashboardTime": false, "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", "resultFormat": "time_series", "workspace": "00000000-0000-0000-0000-000000000000" @@ -5330,7 +5704,6 @@ "aggregation": "Average", "alias": "Queue Availability", "allowedTimeGrainsMs": [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [ { @@ -5349,8 +5722,12 @@ "metricDefinition": "$ns/queueServices", "metricName": "Availability", "metricNamespace": "Microsoft.Storage/storageAccounts/queueServices", - "resourceGroup": "$rg", - "resourceName": "$resource/default", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource/default" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -5392,6 +5769,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -5402,70 +5782,42 @@ "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Availability Trend", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "transformations": [], - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "percent", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { "collapsed": false, - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "gridPos": { "h": 1, "w": 24, "x": 0, - "y": 81 + "y": 80 }, "id": 46, "panels": [], + "targets": [ + { + "datasource": { + "uid": "$ds" + }, + "refId": "A" + } + ], "title": "Capacity", "type": "row" }, { - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, - "custom": {}, "mappings": [], "thresholds": { "mode": "absolute", @@ -5483,7 +5835,7 @@ "h": 8, "w": 24, "x": 0, - "y": 82 + "y": 81 }, "id": 40, "options": { @@ -5496,10 +5848,12 @@ "fields": "", "values": false }, + "showPercentChange": false, "text": {}, - "textMode": "auto" + "textMode": "auto", + "wideLayout": true }, - "pluginVersion": "7.4.3", + "pluginVersion": "10.4.7", "targets": [ { "appInsights": { @@ -5538,6 +5892,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "insightsAnalytics": { "query": "", "resultFormat": "time_series" @@ -5592,6 +5949,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -5638,6 +5998,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -5689,6 +6052,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -5735,6 +6101,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -5745,61 +6114,88 @@ "subscription": "$sub" } ], - "title": "", "type": "stat" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$ds", + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "$ds" + }, "fieldConfig": { "defaults": { - "color": {}, - "custom": {}, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "always", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], "thresholds": { "mode": "absolute", - "steps": [] + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] }, "unit": "decbytes" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 8, "w": 12, "x": 0, - "y": 90 + "y": 89 }, - "hiddenSeries": false, "id": 42, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.4.3", - "pointradius": 1, - "points": true, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.7", "targets": [ { "appInsights": { @@ -5808,6 +6204,7 @@ "timeGrain": "auto" }, "azureLogAnalytics": { + "dashboardTime": false, "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", "resultFormat": "time_series", "workspace": "00000000-0000-0000-0000-000000000000" @@ -5817,7 +6214,6 @@ "aggregation": "Average", "alias": "Blob Capacity", "allowedTimeGrainsMs": [3600000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [ { @@ -5832,8 +6228,12 @@ "metricDefinition": "$ns/blobServices", "metricName": "BlobCapacity", "metricNamespace": "Microsoft.Storage/storageAccounts/blobServices", - "resourceGroup": "$rg", - "resourceName": "$resource/default", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource/default" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -5847,6 +6247,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -5863,6 +6266,7 @@ "timeGrain": "auto" }, "azureLogAnalytics": { + "dashboardTime": false, "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", "resultFormat": "time_series", "workspace": "00000000-0000-0000-0000-000000000000" @@ -5872,14 +6276,17 @@ "aggregation": "Average", "alias": "Table Capacity", "allowedTimeGrainsMs": [3600000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [], "metricDefinition": "$ns/tableServices", "metricName": "TableCapacity", "metricNamespace": "Microsoft.Storage/storageAccounts/tableServices", - "resourceGroup": "$rg", - "resourceName": "$resource/default", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource/default" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -5893,6 +6300,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -5909,6 +6319,7 @@ "timeGrain": "auto" }, "azureLogAnalytics": { + "dashboardTime": false, "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", "resultFormat": "time_series", "workspace": "00000000-0000-0000-0000-000000000000" @@ -5918,7 +6329,6 @@ "aggregation": "Average", "alias": "File Capacity", "allowedTimeGrainsMs": [3600000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [ { @@ -5929,8 +6339,12 @@ "metricDefinition": "$ns/fileServices", "metricName": "FileCapacity", "metricNamespace": "Microsoft.Storage/storageAccounts/fileServices", - "resourceGroup": "$rg", - "resourceName": "$resource/default", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource/default" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -5944,6 +6358,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -5960,6 +6377,7 @@ "timeGrain": "auto" }, "azureLogAnalytics": { + "dashboardTime": false, "query": "//change this example to create your own time series query\n
//the table to query (e.g. Usage, Heartbeat, Perf)\n| where $__timeFilter(TimeGenerated) //this is a macro used to show the full chart’s time range, choose the datetime column here\n| summarize count() by , bin(TimeGenerated, $__interval) //change “group by column” to a column in your table, such as “Computer”. The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.\n| order by TimeGenerated asc", "resultFormat": "time_series", "workspace": "00000000-0000-0000-0000-000000000000" @@ -5969,14 +6387,17 @@ "aggregation": "Average", "alias": "Queue Capacity", "allowedTimeGrainsMs": [3600000], - "dimensionFilter": "*", "dimensionFilters": [], "dimensions": [], "metricDefinition": "$ns/queueServices", "metricName": "QueueCapacity", "metricNamespace": "Microsoft.Storage/storageAccounts/queueServices", - "resourceGroup": "$rg", - "resourceName": "$resource/default", + "resources": [ + { + "resourceGroup": "$rg", + "resourceName": "$resource/default" + } + ], "timeGrain": "auto", "timeGrains": [ { @@ -5990,6 +6411,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -6000,55 +6424,22 @@ "subscription": "$sub" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Storage capacity", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -6058,8 +6449,10 @@ "hideFrom": { "graph": false, "legend": false, - "tooltip": false + "tooltip": false, + "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 4, @@ -6067,7 +6460,14 @@ "type": "linear" }, "showPoints": "always", - "spanNulls": true + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } }, "mappings": [], "thresholds": { @@ -6091,17 +6491,19 @@ "h": 8, "w": 12, "x": 12, - "y": 90 + "y": 89 }, "id": 44, "options": { "legend": { "calcs": ["mean"], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, - "tooltipOptions": { - "mode": "single" + "tooltip": { + "mode": "single", + "sort": "none" } }, "pluginVersion": "7.4.3", @@ -6152,6 +6554,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -6198,6 +6603,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -6249,6 +6657,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -6295,6 +6706,9 @@ ], "top": "10" }, + "datasource": { + "uid": "$ds" + }, "hide": false, "insightsAnalytics": { "query": "", @@ -6305,21 +6719,21 @@ "subscription": "$sub" } ], - "timeFrom": null, - "timeShift": null, "title": "Storage count", "type": "timeseries" } ], "refresh": false, - "schemaVersion": 27, + "schemaVersion": 39, "tags": [], "templating": { "list": [ { - "current": {}, - "description": null, - "error": null, + "current": { + "selected": false, + "text": "Azure Monitor", + "value": "azure-monitor-oob" + }, "hide": 0, "includeAll": false, "label": "Data Source", @@ -6334,25 +6748,30 @@ "type": "datasource" }, { - "allValue": null, "current": {}, - "datasource": "$ds", - "definition": "subscriptions()", - "description": null, - "error": null, + "datasource": { + "uid": "$ds" + }, + "definition": "", "hide": 0, "includeAll": false, "label": "Subscription", "multi": false, "name": "sub", "options": [], - "query": "subscriptions()", + "query": { + "grafanaTemplateVariableFn": { + "kind": "SubscriptionsQuery", + "rawQuery": "subscriptions()" + }, + "queryType": "Azure Subscriptions", + "refId": "A" + }, "refresh": 2, "regex": "", "skipUrlSync": false, "sort": 5, "tagValuesQuery": "", - "tags": [], "tagsQuery": "", "type": "query", "useTags": false @@ -6385,12 +6804,11 @@ "type": "query" }, { - "allValue": null, "current": {}, - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "definition": "", - "description": null, - "error": null, "hide": 0, "includeAll": false, "label": "Resource Group", @@ -6410,18 +6828,16 @@ "skipUrlSync": false, "sort": 5, "tagValuesQuery": "", - "tags": [], "tagsQuery": "", "type": "query", "useTags": false }, { - "allValue": null, "current": {}, - "datasource": "$ds", + "datasource": { + "uid": "$ds" + }, "definition": "", - "description": null, - "error": null, "hide": 0, "includeAll": false, "label": "Resource", @@ -6440,7 +6856,6 @@ "skipUrlSync": false, "sort": 5, "tagValuesQuery": "", - "tags": [], "tagsQuery": "", "type": "query", "useTags": false @@ -6455,5 +6870,6 @@ "timezone": "", "title": "Azure / Insights / Storage Accounts", "uid": "3n2E8CrGk", - "version": 29 + "version": 29, + "weekStart": "" } From 95dea152b68235814d170bddeee6274f7c6c9e88 Mon Sep 17 00:00:00 2001 From: Andres Martinez Gotor Date: Mon, 16 Dec 2024 14:51:04 +0100 Subject: [PATCH 25/38] Plugins Admin: Avoid disabling auto-enabled apps (#97800) --- packages/grafana-data/src/types/plugin.ts | 1 + pkg/api/dtos/plugins.go | 1 + pkg/api/frontendsettings.go | 1 + pkg/api/plugins.go | 7 +- pkg/api/plugins_test.go | 40 ++++++++ .../pluginsettings/models.go | 1 + .../plugins/plugin_provisioner.go | 10 ++ .../plugins/plugin_provisioner_test.go | 37 ++++++- .../GetStartedWithApp.test.tsx | 98 +++++++++++++++++++ .../GetStartedWithApp.tsx | 4 +- 10 files changed, 196 insertions(+), 4 deletions(-) create mode 100644 public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithApp.test.tsx diff --git a/packages/grafana-data/src/types/plugin.ts b/packages/grafana-data/src/types/plugin.ts index 1f64879d317..ebb3da684f6 100644 --- a/packages/grafana-data/src/types/plugin.ts +++ b/packages/grafana-data/src/types/plugin.ts @@ -86,6 +86,7 @@ export interface PluginMeta { secureJsonData?: KeyValue; secureJsonFields?: KeyValue; enabled?: boolean; + autoEnabled?: boolean; defaultNavUrl?: string; hasUpdate?: boolean; enterprise?: boolean; diff --git a/pkg/api/dtos/plugins.go b/pkg/api/dtos/plugins.go index 703178e7000..b2773a70f0e 100644 --- a/pkg/api/dtos/plugins.go +++ b/pkg/api/dtos/plugins.go @@ -12,6 +12,7 @@ type PluginSetting struct { Id string `json:"id"` Enabled bool `json:"enabled"` Pinned bool `json:"pinned"` + AutoEnabled bool `json:"autoEnabled"` Module string `json:"module"` BaseUrl string `json:"baseUrl"` Info plugins.Info `json:"info"` diff --git a/pkg/api/frontendsettings.go b/pkg/api/frontendsettings.go index d9fe3b73822..2d45da7017d 100644 --- a/pkg/api/frontendsettings.go +++ b/pkg/api/frontendsettings.go @@ -721,6 +721,7 @@ func (hs *HTTPServer) pluginSettings(ctx context.Context, orgID int64) (map[stri OrgID: orgID, Enabled: plugin.AutoEnabled, Pinned: plugin.AutoEnabled, + AutoEnabled: plugin.AutoEnabled, PluginVersion: plugin.Info.Version, } diff --git a/pkg/api/plugins.go b/pkg/api/plugins.go index fffadca6a2d..23178dc700a 100644 --- a/pkg/api/plugins.go +++ b/pkg/api/plugins.go @@ -216,6 +216,7 @@ func (hs *HTTPServer) GetPluginSettingByID(c *contextmodel.ReqContext) response. if plugin.IsApp() { dto.Enabled = plugin.AutoEnabled dto.Pinned = plugin.AutoEnabled + dto.AutoEnabled = plugin.AutoEnabled } ps, err := hs.PluginSettings.GetPluginSettingByPluginID(c.Req.Context(), &pluginsettings.GetByPluginIDArgs{ @@ -254,9 +255,13 @@ func (hs *HTTPServer) UpdatePluginSetting(c *contextmodel.ReqContext) response.R } pluginID := web.Params(c.Req)[":pluginId"] - if _, exists := hs.pluginStore.Plugin(c.Req.Context(), pluginID); !exists { + p, exists := hs.pluginStore.Plugin(c.Req.Context(), pluginID) + if !exists { return response.Error(http.StatusNotFound, "Plugin not installed", nil) } + if p.AutoEnabled && !cmd.Enabled { + return response.Error(http.StatusBadRequest, "Cannot disable auto-enabled plugin", nil) + } cmd.OrgId = c.SignedInUser.GetOrgID() cmd.PluginId = pluginID diff --git a/pkg/api/plugins_test.go b/pkg/api/plugins_test.go index 7cb30bd428d..c84e1fe4787 100644 --- a/pkg/api/plugins_test.go +++ b/pkg/api/plugins_test.go @@ -871,3 +871,43 @@ func Test_PluginsSettings(t *testing.T) { }) } } + +func Test_UpdatePluginSetting(t *testing.T) { + pID := "test-app" + p1 := createPlugin(plugins.JSONData{ + ID: pID, Type: "app", Name: pID, + Info: plugins.Info{ + Version: "1.0.0", + }, + AutoEnabled: true, + }, plugins.ClassExternal, plugins.NewFakeFS(), + ) + pluginRegistry := &fakes.FakePluginRegistry{ + Store: map[string]*plugins.Plugin{ + p1.ID: p1, + }, + } + + pluginSettings := pluginsettings.FakePluginSettings{Plugins: map[string]*pluginsettings.DTO{ + pID: {ID: 0, OrgID: 1, PluginID: pID, PluginVersion: "1.0.0", Enabled: true}, + }} + + t.Run("should return an error when trying to disable an auto-enabled plugin", func(t *testing.T) { + server := SetupAPITestServer(t, func(hs *HTTPServer) { + hs.Cfg = setting.NewCfg() + hs.PluginSettings = &pluginSettings + hs.pluginStore = pluginstore.New(pluginRegistry, &fakes.FakeLoader{}) + hs.pluginFileStore = filestore.ProvideService(pluginRegistry) + hs.managedPluginsService = managedplugins.NewNoop() + hs.log = log.NewNopLogger() + }) + + input := strings.NewReader(`{"enabled": false}`) + endpoint := fmt.Sprintf("/api/plugins/%s/settings", pID) + req := webtest.RequestWithSignedInUser(server.NewPostRequest(endpoint, input), userWithPermissions(1, []ac.Permission{{Action: pluginaccesscontrol.ActionWrite, Scope: "plugins:id:test-app"}})) + res, err := server.SendJSON(req) + require.NoError(t, err) + require.Equal(t, http.StatusBadRequest, res.StatusCode) + require.NoError(t, res.Body.Close()) + }) +} diff --git a/pkg/services/pluginsintegration/pluginsettings/models.go b/pkg/services/pluginsintegration/pluginsettings/models.go index 230a3faeddf..762c8c247ee 100644 --- a/pkg/services/pluginsintegration/pluginsettings/models.go +++ b/pkg/services/pluginsintegration/pluginsettings/models.go @@ -27,6 +27,7 @@ type InfoDTO struct { Enabled bool Pinned bool PluginVersion string + AutoEnabled bool } type UpdateArgs struct { diff --git a/pkg/services/provisioning/plugins/plugin_provisioner.go b/pkg/services/provisioning/plugins/plugin_provisioner.go index 83d334a573b..79a859cb360 100644 --- a/pkg/services/provisioning/plugins/plugin_provisioner.go +++ b/pkg/services/provisioning/plugins/plugin_provisioner.go @@ -19,6 +19,7 @@ func Provision(ctx context.Context, configDirectory string, pluginStore pluginst cfgProvider: newConfigReader(logger, pluginStore), pluginSettings: pluginSettings, orgService: orgService, + pluginStore: pluginStore, } return ap.applyChanges(ctx, configDirectory) } @@ -30,6 +31,7 @@ type PluginProvisioner struct { cfgProvider configReader pluginSettings pluginsettings.Service orgService org.Service + pluginStore pluginstore.Store } func (ap *PluginProvisioner) apply(ctx context.Context, cfg *pluginsAsConfig) error { @@ -45,6 +47,14 @@ func (ap *PluginProvisioner) apply(ctx context.Context, cfg *pluginsAsConfig) er app.OrgID = 1 } + p, found := ap.pluginStore.Plugin(ctx, app.PluginID) + if !found { + return errors.New("plugin not found") + } + if p.AutoEnabled && !app.Enabled { + return errors.New("plugin is auto enabled and cannot be disabled") + } + ps, err := ap.pluginSettings.GetPluginSettingByPluginID(ctx, &pluginsettings.GetByPluginIDArgs{ OrgID: app.OrgID, PluginID: app.PluginID, diff --git a/pkg/services/provisioning/plugins/plugin_provisioner_test.go b/pkg/services/provisioning/plugins/plugin_provisioner_test.go index 187762b9c28..a402cc44bd0 100644 --- a/pkg/services/provisioning/plugins/plugin_provisioner_test.go +++ b/pkg/services/provisioning/plugins/plugin_provisioner_test.go @@ -8,9 +8,11 @@ import ( "github.com/stretchr/testify/require" "github.com/grafana/grafana/pkg/infra/log" + "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/org/orgtest" "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings" + "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore" ) func TestPluginProvisioner(t *testing.T) { @@ -37,7 +39,16 @@ func TestPluginProvisioner(t *testing.T) { store := &mockStore{} orgMock := orgtest.NewOrgServiceFake() orgMock.ExpectedOrg = &org.Org{ID: 4} - ap := PluginProvisioner{log: log.New("test"), cfgProvider: reader, pluginSettings: store, orgService: orgMock} + ap := PluginProvisioner{ + log: log.New("test"), + cfgProvider: reader, + pluginSettings: store, + orgService: orgMock, + pluginStore: pluginstore.NewFakePluginStore( + pluginstore.Plugin{JSONData: plugins.JSONData{ID: "test-plugin"}}, + pluginstore.Plugin{JSONData: plugins.JSONData{ID: "test-plugin-2"}}, + ), + } err := ap.applyChanges(context.Background(), "") require.NoError(t, err) @@ -68,6 +79,30 @@ func TestPluginProvisioner(t *testing.T) { require.Equal(t, tc.ExpectedSecureJSONData, cmd.SecureJSONData) } }) + + t.Run("Should return error trying to disable an auto-enabled plugin", func(t *testing.T) { + cfg := []*pluginsAsConfig{ + { + Apps: []*appFromConfig{ + {PluginID: "test-plugin", OrgID: 2, Enabled: false}, + }, + }, + } + reader := &testConfigReader{result: cfg} + store := &mockStore{} + ap := PluginProvisioner{ + log: log.New("test"), + cfgProvider: reader, + pluginSettings: store, + pluginStore: pluginstore.NewFakePluginStore( + pluginstore.Plugin{JSONData: plugins.JSONData{ID: "test-plugin", AutoEnabled: true}}, + ), + } + + err := ap.applyChanges(context.Background(), "") + require.Error(t, err) + require.Contains(t, err.Error(), "plugin is auto enabled and cannot be disabled") + }) } type testConfigReader struct { diff --git a/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithApp.test.tsx b/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithApp.test.tsx new file mode 100644 index 00000000000..d544568c61c --- /dev/null +++ b/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithApp.test.tsx @@ -0,0 +1,98 @@ +import { render, screen } from '@testing-library/react'; + +import { PluginSignatureStatus } from '@grafana/data'; +import { contextSrv } from 'app/core/core'; + +import { usePluginConfig } from '../../hooks/usePluginConfig'; +import { CatalogPlugin } from '../../types'; + +import { GetStartedWithApp } from './GetStartedWithApp'; + +jest.mock('app/core/core', () => ({ + contextSrv: { + hasPermission: jest.fn(), + }, +})); + +jest.mock('../../api', () => ({ + updatePluginSettings: jest.fn(), +})); + +jest.mock('../../hooks/usePluginConfig', () => ({ + usePluginConfig: jest.fn(), +})); + +const mockPlugin: CatalogPlugin = { + id: 'test-plugin', + name: 'Test Plugin', + description: 'Test Plugin Description', + downloads: 0, + hasUpdate: false, + info: { + logos: { + large: 'https://grafana.com/assets/img/brand/grafana_icon.svg', + small: 'https://grafana.com/assets/img/brand/grafana_icon.svg', + }, + keywords: [], + }, + isDev: false, + isCore: false, + isEnterprise: false, + isInstalled: false, + isDisabled: false, + isDeprecated: false, + isManaged: false, + isPreinstalled: { found: false, withVersion: false }, + isPublished: false, + orgName: 'Test Org', + signature: PluginSignatureStatus.valid, + popularity: 0, + publishedAt: '2021-01-01', + updatedAt: '2021-01-01', +}; + +describe('GetStartedWithApp', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('renders null if pluginConfig is not available', () => { + (usePluginConfig as jest.Mock).mockReturnValue({ value: null }); + (contextSrv.hasPermission as jest.Mock).mockReturnValue(true); + + const { container } = render(); + expect(container.firstChild).toBeNull(); + }); + + it('renders null if user does not have permission', () => { + (usePluginConfig as jest.Mock).mockReturnValue({ value: { meta: {} } }); + (contextSrv.hasPermission as jest.Mock).mockReturnValue(false); + + const { container } = render(); + expect(container.firstChild).toBeNull(); + }); + + it('renders enable button if plugin is not enabled', () => { + (usePluginConfig as jest.Mock).mockReturnValue({ value: { meta: { enabled: false } } }); + (contextSrv.hasPermission as jest.Mock).mockReturnValue(true); + + render(); + expect(screen.getByText('Enable')).toBeInTheDocument(); + }); + + it('renders disable button if plugin is enabled and not autoEnabled', () => { + (usePluginConfig as jest.Mock).mockReturnValue({ value: { meta: { enabled: true, autoEnabled: false } } }); + (contextSrv.hasPermission as jest.Mock).mockReturnValue(true); + + render(); + expect(screen.getByText('Disable')).toBeInTheDocument(); + }); + + it('does not render disable button if plugin is enabled and autoEnabled', () => { + (usePluginConfig as jest.Mock).mockReturnValue({ value: { meta: { enabled: true, autoEnabled: true } } }); + (contextSrv.hasPermission as jest.Mock).mockReturnValue(true); + + render(); + expect(screen.queryByText('Disable')).not.toBeInTheDocument(); + }); +}); diff --git a/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithApp.tsx b/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithApp.tsx index bdb80b54d4f..4ca6080d7c7 100644 --- a/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithApp.tsx +++ b/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithApp.tsx @@ -25,7 +25,7 @@ export function GetStartedWithApp({ plugin }: Props): React.ReactElement | null return null; } - const { enabled, jsonData } = pluginConfig?.meta; + const { enabled, autoEnabled, jsonData } = pluginConfig?.meta; const enable = () => { reportInteraction('plugins_detail_enable_clicked', { @@ -63,7 +63,7 @@ export function GetStartedWithApp({ plugin }: Props): React.ReactElement | null )} - {enabled && ( + {enabled && !autoEnabled && ( From 3aca9269824bfa86d2246af6507fd9d609422847 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 14:00:10 +0000 Subject: [PATCH 26/38] Update dependency @rsdoctor/webpack-plugin to v0.4.12 (#98030) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 123 +++++++++++++++++++++++++----------------------------- 1 file changed, 58 insertions(+), 65 deletions(-) diff --git a/yarn.lock b/yarn.lock index ca23238a094..7cf99e56be9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6783,22 +6783,22 @@ __metadata: languageName: node linkType: hard -"@rsdoctor/client@npm:0.4.11": - version: 0.4.11 - resolution: "@rsdoctor/client@npm:0.4.11" - checksum: 10/fc59005c40dfb11582b16e74de768ef5fe73a0e06db472908b9568db870380554db3b87867e3bf33ce0251e2f351c1249d0181c7e575eeef3c64c64592f9b179 +"@rsdoctor/client@npm:0.4.12": + version: 0.4.12 + resolution: "@rsdoctor/client@npm:0.4.12" + checksum: 10/04ae4f8de34fdf5cec5b9db2072e646f3327a7ba7ca4a96942961fa26129e715db92c28ca68bf0f6c5149ccbfb9b73aa2d2984242bf8d35bc54f827e2ccae84e languageName: node linkType: hard -"@rsdoctor/core@npm:0.4.11": - version: 0.4.11 - resolution: "@rsdoctor/core@npm:0.4.11" +"@rsdoctor/core@npm:0.4.12": + version: 0.4.12 + resolution: "@rsdoctor/core@npm:0.4.12" dependencies: - "@rsdoctor/graph": "npm:0.4.11" - "@rsdoctor/sdk": "npm:0.4.11" - "@rsdoctor/types": "npm:0.4.11" - "@rsdoctor/utils": "npm:0.4.11" - axios: "npm:^1.7.8" + "@rsdoctor/graph": "npm:0.4.12" + "@rsdoctor/sdk": "npm:0.4.12" + "@rsdoctor/types": "npm:0.4.12" + "@rsdoctor/utils": "npm:0.4.12" + axios: "npm:^1.7.9" enhanced-resolve: "npm:5.12.0" filesize: "npm:^10.1.6" fs-extra: "npm:^11.1.1" @@ -6807,31 +6807,31 @@ __metadata: semver: "npm:^7.6.3" source-map: "npm:^0.7.4" webpack-bundle-analyzer: "npm:^4.10.2" - checksum: 10/b32242191ab4a202a997ffe290b3b62361942e052fe39803f2f458eb17b127516084c0b80705e4645edcf36a839f4e60f76a79c19f0068824bd32e9013b10788 + checksum: 10/d77252288cec3ad9cd6389fb772125fcbdca669c0186a540a9270f2c3ac01b0620d188595e952a3683b0af4e4eef2c8816b0af71a2d87667eef7f2e47484a4b3 languageName: node linkType: hard -"@rsdoctor/graph@npm:0.4.11": - version: 0.4.11 - resolution: "@rsdoctor/graph@npm:0.4.11" +"@rsdoctor/graph@npm:0.4.12": + version: 0.4.12 + resolution: "@rsdoctor/graph@npm:0.4.12" dependencies: - "@rsdoctor/types": "npm:0.4.11" - "@rsdoctor/utils": "npm:0.4.11" + "@rsdoctor/types": "npm:0.4.12" + "@rsdoctor/utils": "npm:0.4.12" lodash: "npm:^4.17.21" - socket.io: "npm:4.7.2" + socket.io: "npm:4.8.1" source-map: "npm:^0.7.4" - checksum: 10/ba828662d7b4889aeb806c14f88a9321e9d10a7a6e568675a65afcf3d6013958526ee023a430946315d4899dce853e2e014876c2a63fe1f9e3dd24de6564f7b4 + checksum: 10/53cb9dd4c8507cf22ee6088e4fc1b5d26fb2090dee1570fd1964659d854bab33ed7ca73862a84a256280a85aa076c5e18953830af2127fb583d5eaa5274a934d languageName: node linkType: hard -"@rsdoctor/sdk@npm:0.4.11": - version: 0.4.11 - resolution: "@rsdoctor/sdk@npm:0.4.11" +"@rsdoctor/sdk@npm:0.4.12": + version: 0.4.12 + resolution: "@rsdoctor/sdk@npm:0.4.12" dependencies: - "@rsdoctor/client": "npm:0.4.11" - "@rsdoctor/graph": "npm:0.4.11" - "@rsdoctor/types": "npm:0.4.11" - "@rsdoctor/utils": "npm:0.4.11" + "@rsdoctor/client": "npm:0.4.12" + "@rsdoctor/graph": "npm:0.4.12" + "@rsdoctor/types": "npm:0.4.12" + "@rsdoctor/utils": "npm:0.4.12" "@types/fs-extra": "npm:^11.0.4" body-parser: "npm:1.20.3" cors: "npm:2.8.5" @@ -6841,16 +6841,16 @@ __metadata: lodash: "npm:^4.17.21" open: "npm:^8.4.2" serve-static: "npm:1.16.2" - socket.io: "npm:4.7.2" + socket.io: "npm:4.8.1" source-map: "npm:^0.7.4" tapable: "npm:2.2.1" - checksum: 10/b66424c5fc61cbfd52d95c8dc5393715f73653a2d9b7acc04c825ed100b3185c9afe02dfc9450587454430e40a2cc21aa20225ae1b7927e43445d3440d599b47 + checksum: 10/a0f20c0410e44fd9f7428fee39c45abf493144e73aa910d9c8f34760461d36d1144856c9ea3078afee2282817acb8bffb82bad9ec8443279dde5bf14875df495 languageName: node linkType: hard -"@rsdoctor/types@npm:0.4.11": - version: 0.4.11 - resolution: "@rsdoctor/types@npm:0.4.11" +"@rsdoctor/types@npm:0.4.12": + version: 0.4.12 + resolution: "@rsdoctor/types@npm:0.4.12" dependencies: "@types/connect": "npm:3.4.38" "@types/estree": "npm:1.0.5" @@ -6862,16 +6862,16 @@ __metadata: peerDependenciesMeta: "@rspack/core": optional: true - checksum: 10/d9b27f4aeb51c2b39eaeef9e1fdf3080aa13b1a98a54767f464f3d8ef08a91309263372909ce62980c49886868a33bf712d8dc8f9e13b511a3b84eb840b498d3 + checksum: 10/41cbfd7eb36999e79eed49ebc49e5665c5c8c68070f2981558cdf110fdcc60d97b2e653ead5c12cf9ebcef8b7de98b42bc20cf15258a42a3f2ae5a7b75aa8379 languageName: node linkType: hard -"@rsdoctor/utils@npm:0.4.11": - version: 0.4.11 - resolution: "@rsdoctor/utils@npm:0.4.11" +"@rsdoctor/utils@npm:0.4.12": + version: 0.4.12 + resolution: "@rsdoctor/utils@npm:0.4.12" dependencies: "@babel/code-frame": "npm:7.25.7" - "@rsdoctor/types": "npm:0.4.11" + "@rsdoctor/types": "npm:0.4.12" "@types/estree": "npm:1.0.5" acorn: "npm:^8.10.0" acorn-import-assertions: "npm:1.9.0" @@ -6888,24 +6888,24 @@ __metadata: lodash: "npm:^4.17.21" rslog: "npm:^1.2.3" strip-ansi: "npm:^6.0.1" - checksum: 10/dbeb86402f162a136ea6f95a8ef53f6f46ce39262d6a796cb0d642fbede15a81a7ed73fc9a48aa88bf39ca01bd277e42990b7cd2480159fd2a472205b1e5d05d + checksum: 10/f0640c4cabacbf0c65cb2c2bc36791c9f07c9e4ea7917636f5480c193043a7f16cf276734a91bcd9309ec3389987e586e3a557e99266d758affdb76a2efb6a5a languageName: node linkType: hard "@rsdoctor/webpack-plugin@npm:^0.4.6": - version: 0.4.11 - resolution: "@rsdoctor/webpack-plugin@npm:0.4.11" + version: 0.4.12 + resolution: "@rsdoctor/webpack-plugin@npm:0.4.12" dependencies: - "@rsdoctor/core": "npm:0.4.11" - "@rsdoctor/graph": "npm:0.4.11" - "@rsdoctor/sdk": "npm:0.4.11" - "@rsdoctor/types": "npm:0.4.11" - "@rsdoctor/utils": "npm:0.4.11" + "@rsdoctor/core": "npm:0.4.12" + "@rsdoctor/graph": "npm:0.4.12" + "@rsdoctor/sdk": "npm:0.4.12" + "@rsdoctor/types": "npm:0.4.12" + "@rsdoctor/utils": "npm:0.4.12" fs-extra: "npm:^11.1.1" lodash: "npm:^4.17.21" peerDependencies: webpack: 5.x - checksum: 10/c5c64d6731142fc0a5b0395434c7ac0dc13f743671a83d2a33bb88914f95438750cef5a47c923fc2dfb66f1258b8bd26c101f90c84895fd5f1cc9b2c789a888b + checksum: 10/e2bfc961f39bfa27e60ada29cccf2734db59062d78007cedaec3c794f8c39864c6f0e487879f565fcad100ec970d3e320c5927315fc2ed00d55a00924891b6f3 languageName: node linkType: hard @@ -11459,7 +11459,7 @@ __metadata: languageName: node linkType: hard -"axios@npm:^1.4.0, axios@npm:^1.7.4, axios@npm:^1.7.8": +"axios@npm:^1.4.0, axios@npm:^1.7.4, axios@npm:^1.7.9": version: 1.7.9 resolution: "axios@npm:1.7.9" dependencies: @@ -13162,20 +13162,13 @@ __metadata: languageName: node linkType: hard -"cookie@npm:^0.7.2": +"cookie@npm:^0.7.2, cookie@npm:~0.7.2": version: 0.7.2 resolution: "cookie@npm:0.7.2" checksum: 10/24b286c556420d4ba4e9bc09120c9d3db7d28ace2bd0f8ccee82422ce42322f73c8312441271e5eefafbead725980e5996cc02766dbb89a90ac7f5636ede608f languageName: node linkType: hard -"cookie@npm:~0.4.1": - version: 0.4.2 - resolution: "cookie@npm:0.4.2" - checksum: 10/2e1de9fdedca54881eab3c0477aeb067f281f3155d9cfee9d28dfb252210d09e85e9d175c0a60689661feb9e35e588515352f2456bc1f8e8db4267e05fd70137 - languageName: node - linkType: hard - "copy-to-clipboard@npm:^3.3.1": version: 3.3.1 resolution: "copy-to-clipboard@npm:3.3.1" @@ -15049,21 +15042,21 @@ __metadata: languageName: node linkType: hard -"engine.io@npm:~6.5.2": - version: 6.5.5 - resolution: "engine.io@npm:6.5.5" +"engine.io@npm:~6.6.0": + version: 6.6.2 + resolution: "engine.io@npm:6.6.2" dependencies: "@types/cookie": "npm:^0.4.1" "@types/cors": "npm:^2.8.12" "@types/node": "npm:>=10.0.0" accepts: "npm:~1.3.4" base64id: "npm:2.0.0" - cookie: "npm:~0.4.1" + cookie: "npm:~0.7.2" cors: "npm:~2.8.5" debug: "npm:~4.3.1" engine.io-parser: "npm:~5.2.1" ws: "npm:~8.17.1" - checksum: 10/df8562e5249cf122efad77b909fe804b36ac5769676f963c997d4d18c91e014c68bb40661ff92f641b978baa0297be4000c2f3c3d1ce237cd1771952ccc5f38a + checksum: 10/381c0a715362bebf32c95f0e4247899b53ff9f8c0074b03f88748cf17635a02948ea3eca27905df37130bc963747c0d286acc78c757e6fc085fe8b8e17d76e01 languageName: node linkType: hard @@ -27741,18 +27734,18 @@ __metadata: languageName: node linkType: hard -"socket.io@npm:4.7.2": - version: 4.7.2 - resolution: "socket.io@npm:4.7.2" +"socket.io@npm:4.8.1": + version: 4.8.1 + resolution: "socket.io@npm:4.8.1" dependencies: accepts: "npm:~1.3.4" base64id: "npm:~2.0.0" cors: "npm:~2.8.5" debug: "npm:~4.3.2" - engine.io: "npm:~6.5.2" + engine.io: "npm:~6.6.0" socket.io-adapter: "npm:~2.5.2" socket.io-parser: "npm:~4.2.4" - checksum: 10/03f2d196975f531fb068e31fb001ff4662e8acd1a6a4ddd8bb0359411aea3309d9764c0d2759dabd8fc96cf9840b2c4cdc70a473fa0e8f2b762ab619550de8e1 + checksum: 10/b9b362b7f63fc7ebb58482b8a3ade6c971da7783b7611dfeebaa8b02be23cb948137ec218491ccda8be57e434e97d65b64edf1e9811e5245b23a888d41636f4a languageName: node linkType: hard From 863f865c7fb29a5a9a833baca127f2d0a866a3ab Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 14:00:43 +0000 Subject: [PATCH 27/38] Update dependency react-hook-form to v7.54.1 (#98031) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 7cf99e56be9..44481829d03 100644 --- a/yarn.lock +++ b/yarn.lock @@ -25431,11 +25431,11 @@ __metadata: linkType: hard "react-hook-form@npm:^7.49.2": - version: 7.53.2 - resolution: "react-hook-form@npm:7.53.2" + version: 7.54.1 + resolution: "react-hook-form@npm:7.54.1" peerDependencies: react: ^16.8.0 || ^17 || ^18 || ^19 - checksum: 10/172589ac5871bd41717e8c6bc4c825d149db88eb02e356a8fef4115615a56b21bf66ad16954575b1d6302ed265b8780f1975a2730d5aa10a53e412b56d9f72ca + checksum: 10/64060da8960a50584002bd5549f59dcb4d9c9b223b21ced1096a539ac520a3d9b65a8eb08c62d7f00b751f421ac133e3f82f23e01292dd2775d93f85791fd2f3 languageName: node linkType: hard From 7ed1058af1bff8f143f0c2ef06baee250313ecf2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 16:21:12 +0200 Subject: [PATCH 28/38] Update dependency react-redux to v9.2.0 (#98036) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 35 +++++++++++++++++++++-------------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index c90a496be52..a90e72efada 100644 --- a/package.json +++ b/package.json @@ -379,7 +379,7 @@ "react-inlinesvg": "4.1.5", "react-loading-skeleton": "3.5.0", "react-moveable": "0.56.0", - "react-redux": "9.1.2", + "react-redux": "9.2.0", "react-resizable": "3.0.5", "react-responsive-carousel": "^3.2.23", "react-router": "5.3.3", diff --git a/yarn.lock b/yarn.lock index 44481829d03..1b3fe741162 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9998,6 +9998,13 @@ __metadata: languageName: node linkType: hard +"@types/use-sync-external-store@npm:^0.0.6": + version: 0.0.6 + resolution: "@types/use-sync-external-store@npm:0.0.6" + checksum: 10/a95ce330668501ad9b1c5b7f2b14872ad201e552a0e567787b8f1588b22c7040c7c3d80f142cbb9f92d13c4ea41c46af57a20f2af4edf27f224d352abcfe4049 + languageName: node + linkType: hard + "@types/uuid@npm:9.0.8, @types/uuid@npm:^9.0.1": version: 9.0.8 resolution: "@types/uuid@npm:9.0.8" @@ -17810,7 +17817,7 @@ __metadata: react-inlinesvg: "npm:4.1.5" react-loading-skeleton: "npm:3.5.0" react-moveable: "npm:0.56.0" - react-redux: "npm:9.1.2" + react-redux: "npm:9.2.0" react-refresh: "npm:0.14.0" react-resizable: "npm:3.0.5" react-responsive-carousel: "npm:^3.2.23" @@ -25606,22 +25613,22 @@ __metadata: languageName: node linkType: hard -"react-redux@npm:9.1.2, react-redux@npm:^9.1.2": - version: 9.1.2 - resolution: "react-redux@npm:9.1.2" +"react-redux@npm:9.2.0, react-redux@npm:^9.1.2": + version: 9.2.0 + resolution: "react-redux@npm:9.2.0" dependencies: - "@types/use-sync-external-store": "npm:^0.0.3" - use-sync-external-store: "npm:^1.0.0" + "@types/use-sync-external-store": "npm:^0.0.6" + use-sync-external-store: "npm:^1.4.0" peerDependencies: - "@types/react": ^18.2.25 - react: ^18.0 + "@types/react": ^18.2.25 || ^19 + react: ^18.0 || ^19 redux: ^5.0.0 peerDependenciesMeta: "@types/react": optional: true redux: optional: true - checksum: 10/319b3286f538da7e609ca90fc6762ffae007c5cf75e525a25237ac2feaee63d9cf76fe766817de1fc8f27e7bde825ca409c463037d26dd8e57c435d383f80c50 + checksum: 10/b3d2f89f469169475ab0a9f8914d54a336ac9bc6a31af6e8dcfe9901e6fe2cfd8c1a3f6ce7a2f7f3e0928a93fbab833b668804155715598b7f2ad89927d3ff50 languageName: node linkType: hard @@ -30034,12 +30041,12 @@ __metadata: languageName: node linkType: hard -"use-sync-external-store@npm:^1.0.0": - version: 1.2.0 - resolution: "use-sync-external-store@npm:1.2.0" +"use-sync-external-store@npm:^1.0.0, use-sync-external-store@npm:^1.4.0": + version: 1.4.0 + resolution: "use-sync-external-store@npm:1.4.0" peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 10/a676216affc203876bd47981103f201f28c2731361bb186367e12d287a7566763213a8816910c6eb88265eccd4c230426eb783d64c373c4a180905be8820ed8e + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + checksum: 10/08bf581a8a2effaefc355e9d18ed025d436230f4cc973db2f593166df357cf63e47b9097b6e5089b594758bde322e1737754ad64905e030d70f8ff7ee671fd01 languageName: node linkType: hard From 22a9770ec5a7d10d6ae8699297363dcf3f7a6f6b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 14:30:19 +0000 Subject: [PATCH 29/38] Update dependency react-select to v5.9.0 (#98037) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- .../grafana-o11y-ds-frontend/package.json | 2 +- packages/grafana-prometheus/package.json | 2 +- packages/grafana-sql/package.json | 2 +- packages/grafana-ui/package.json | 2 +- .../datasource/azuremonitor/package.json | 2 +- .../datasource/cloud-monitoring/package.json | 2 +- .../grafana-testdata-datasource/package.json | 2 +- .../plugins/datasource/jaeger/package.json | 2 +- .../app/plugins/datasource/tempo/package.json | 2 +- .../plugins/datasource/zipkin/package.json | 2 +- yarn.lock | 46 +++++++++---------- 12 files changed, 34 insertions(+), 34 deletions(-) diff --git a/package.json b/package.json index a90e72efada..6648a018c8a 100644 --- a/package.json +++ b/package.json @@ -385,7 +385,7 @@ "react-router": "5.3.3", "react-router-dom": "5.3.3", "react-router-dom-v5-compat": "^6.26.1", - "react-select": "5.8.3", + "react-select": "5.9.0", "react-split-pane": "0.1.92", "react-table": "7.8.0", "react-transition-group": "4.4.5", diff --git a/packages/grafana-o11y-ds-frontend/package.json b/packages/grafana-o11y-ds-frontend/package.json index 5ed582407ac..e836b93831d 100644 --- a/packages/grafana-o11y-ds-frontend/package.json +++ b/packages/grafana-o11y-ds-frontend/package.json @@ -24,7 +24,7 @@ "@grafana/runtime": "11.5.0-pre", "@grafana/schema": "11.5.0-pre", "@grafana/ui": "11.5.0-pre", - "react-select": "5.8.3", + "react-select": "5.9.0", "react-use": "17.5.1", "rxjs": "7.8.1", "tslib": "2.7.0" diff --git a/packages/grafana-prometheus/package.json b/packages/grafana-prometheus/package.json index 8059b2414ca..ac7a8604e74 100644 --- a/packages/grafana-prometheus/package.json +++ b/packages/grafana-prometheus/package.json @@ -65,7 +65,7 @@ "pluralize": "8.0.0", "prismjs": "1.29.0", "react-highlight-words": "0.20.0", - "react-select": "5.8.3", + "react-select": "5.9.0", "react-use": "17.5.1", "react-window": "1.8.10", "rxjs": "7.8.1", diff --git a/packages/grafana-sql/package.json b/packages/grafana-sql/package.json index ec6d205bb9b..f62a7fbeba6 100644 --- a/packages/grafana-sql/package.json +++ b/packages/grafana-sql/package.json @@ -25,7 +25,7 @@ "lodash": "4.17.21", "react": "18.2.0", "react-dom": "18.2.0", - "react-select": "5.8.3", + "react-select": "5.9.0", "react-use": "17.5.1", "react-virtualized-auto-sizer": "1.0.24", "rxjs": "7.8.1", diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index 39377eb2920..2d38e1d7974 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -98,7 +98,7 @@ "react-inlinesvg": "4.1.5", "react-loading-skeleton": "3.5.0", "react-router-dom-v5-compat": "^6.26.1", - "react-select": "5.8.3", + "react-select": "5.9.0", "react-table": "7.8.0", "react-transition-group": "4.4.5", "react-use": "17.5.1", diff --git a/public/app/plugins/datasource/azuremonitor/package.json b/public/app/plugins/datasource/azuremonitor/package.json index 5b64d889c2e..ec9a243185f 100644 --- a/public/app/plugins/datasource/azuremonitor/package.json +++ b/public/app/plugins/datasource/azuremonitor/package.json @@ -19,7 +19,7 @@ "prismjs": "1.29.0", "react": "18.2.0", "react-dom": "18.2.0", - "react-select": "5.8.3", + "react-select": "5.9.0", "react-use": "17.5.1", "rxjs": "7.8.1", "tslib": "2.7.0" diff --git a/public/app/plugins/datasource/cloud-monitoring/package.json b/public/app/plugins/datasource/cloud-monitoring/package.json index 38e28e721cb..0f6dc9dbe6c 100644 --- a/public/app/plugins/datasource/cloud-monitoring/package.json +++ b/public/app/plugins/datasource/cloud-monitoring/package.json @@ -20,7 +20,7 @@ "prismjs": "1.29.0", "react": "18.2.0", "react-dom": "18.2.0", - "react-select": "5.8.3", + "react-select": "5.9.0", "react-use": "17.5.1", "rxjs": "7.8.1", "tslib": "2.7.0" diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/package.json b/public/app/plugins/datasource/grafana-testdata-datasource/package.json index 8949bd929fe..aa35c05c523 100644 --- a/public/app/plugins/datasource/grafana-testdata-datasource/package.json +++ b/public/app/plugins/datasource/grafana-testdata-datasource/package.json @@ -15,7 +15,7 @@ "micro-memoize": "^4.1.2", "react": "18.2.0", "react-dom": "18.2.0", - "react-select": "5.8.3", + "react-select": "5.9.0", "react-use": "17.5.1", "rxjs": "7.8.1", "tslib": "2.7.0", diff --git a/public/app/plugins/datasource/jaeger/package.json b/public/app/plugins/datasource/jaeger/package.json index f71ebe4bc38..9d2289c4539 100644 --- a/public/app/plugins/datasource/jaeger/package.json +++ b/public/app/plugins/datasource/jaeger/package.json @@ -15,7 +15,7 @@ "logfmt": "^1.3.2", "react": "18.2.0", "react-dom": "18.2.0", - "react-select": "5.8.3", + "react-select": "5.9.0", "react-window": "1.8.10", "rxjs": "7.8.1", "stream-browserify": "3.0.0", diff --git a/public/app/plugins/datasource/tempo/package.json b/public/app/plugins/datasource/tempo/package.json index 47e76e535fe..657872288db 100644 --- a/public/app/plugins/datasource/tempo/package.json +++ b/public/app/plugins/datasource/tempo/package.json @@ -29,7 +29,7 @@ "prismjs": "1.29.0", "react": "18.2.0", "react-dom": "18.2.0", - "react-select": "5.8.3", + "react-select": "5.9.0", "react-use": "17.5.1", "rxjs": "7.8.1", "semver": "7.6.3", diff --git a/public/app/plugins/datasource/zipkin/package.json b/public/app/plugins/datasource/zipkin/package.json index e141e55e569..3886ac17b12 100644 --- a/public/app/plugins/datasource/zipkin/package.json +++ b/public/app/plugins/datasource/zipkin/package.json @@ -14,7 +14,7 @@ "lodash": "4.17.21", "react": "18.2.0", "react-dom": "18.2.0", - "react-select": "5.8.3", + "react-select": "5.9.0", "react-use": "17.5.1", "rxjs": "7.8.1", "tslib": "2.7.0" diff --git a/yarn.lock b/yarn.lock index 1b3fe741162..46761399da3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2829,7 +2829,7 @@ __metadata: prismjs: "npm:1.29.0" react: "npm:18.2.0" react-dom: "npm:18.2.0" - react-select: "npm:5.8.3" + react-select: "npm:5.9.0" react-select-event: "npm:5.5.1" react-use: "npm:17.5.1" rxjs: "npm:7.8.1" @@ -2940,7 +2940,7 @@ __metadata: micro-memoize: "npm:^4.1.2" react: "npm:18.2.0" react-dom: "npm:18.2.0" - react-select: "npm:5.8.3" + react-select: "npm:5.9.0" react-use: "npm:17.5.1" rxjs: "npm:7.8.1" ts-node: "npm:10.9.2" @@ -2981,7 +2981,7 @@ __metadata: logfmt: "npm:^1.3.2" react: "npm:18.2.0" react-dom: "npm:18.2.0" - react-select: "npm:5.8.3" + react-select: "npm:5.9.0" react-window: "npm:1.8.10" rxjs: "npm:7.8.1" stream-browserify: "npm:3.0.0" @@ -3123,7 +3123,7 @@ __metadata: prismjs: "npm:1.29.0" react: "npm:18.2.0" react-dom: "npm:18.2.0" - react-select: "npm:5.8.3" + react-select: "npm:5.9.0" react-select-event: "npm:5.5.1" react-test-renderer: "npm:18.2.0" react-use: "npm:17.5.1" @@ -3180,7 +3180,7 @@ __metadata: prismjs: "npm:1.29.0" react: "npm:18.2.0" react-dom: "npm:18.2.0" - react-select: "npm:5.8.3" + react-select: "npm:5.9.0" react-select-event: "npm:5.5.1" react-use: "npm:17.5.1" rxjs: "npm:7.8.1" @@ -3220,7 +3220,7 @@ __metadata: lodash: "npm:4.17.21" react: "npm:18.2.0" react-dom: "npm:18.2.0" - react-select: "npm:5.8.3" + react-select: "npm:5.9.0" react-use: "npm:17.5.1" rxjs: "npm:7.8.1" ts-node: "npm:10.9.2" @@ -3570,7 +3570,7 @@ __metadata: "@types/systemjs": "npm:6.15.1" jest: "npm:^29.6.4" react: "npm:18.2.0" - react-select: "npm:5.8.3" + react-select: "npm:5.9.0" react-use: "npm:17.5.1" rxjs: "npm:7.8.1" ts-jest: "npm:29.2.5" @@ -3701,7 +3701,7 @@ __metadata: react: "npm:18.2.0" react-dom: "npm:18.2.0" react-highlight-words: "npm:0.20.0" - react-select: "npm:5.8.3" + react-select: "npm:5.9.0" react-select-event: "npm:5.5.1" react-test-renderer: "npm:18.2.0" react-use: "npm:17.5.1" @@ -3897,7 +3897,7 @@ __metadata: lodash: "npm:4.17.21" react: "npm:18.2.0" react-dom: "npm:18.2.0" - react-select: "npm:5.8.3" + react-select: "npm:5.9.0" react-use: "npm:17.5.1" react-virtualized-auto-sizer: "npm:1.0.24" rxjs: "npm:7.8.1" @@ -4032,7 +4032,7 @@ __metadata: react-inlinesvg: "npm:4.1.5" react-loading-skeleton: "npm:3.5.0" react-router-dom-v5-compat: "npm:^6.26.1" - react-select: "npm:5.8.3" + react-select: "npm:5.9.0" react-select-event: "npm:^5.1.0" react-table: "npm:7.8.0" react-test-renderer: "npm:18.2.0" @@ -17824,7 +17824,7 @@ __metadata: react-router: "npm:5.3.3" react-router-dom: "npm:5.3.3" react-router-dom-v5-compat: "npm:^6.26.1" - react-select: "npm:5.8.3" + react-select: "npm:5.9.0" react-select-event: "npm:5.5.1" react-split-pane: "npm:0.1.92" react-table: "npm:7.8.0" @@ -25779,9 +25779,9 @@ __metadata: languageName: node linkType: hard -"react-select@npm:5.8.3": - version: 5.8.3 - resolution: "react-select@npm:5.8.3" +"react-select@npm:5.9.0": + version: 5.9.0 + resolution: "react-select@npm:5.9.0" dependencies: "@babel/runtime": "npm:^7.12.0" "@emotion/cache": "npm:^11.4.0" @@ -25791,11 +25791,11 @@ __metadata: memoize-one: "npm:^6.0.0" prop-types: "npm:^15.6.0" react-transition-group: "npm:^4.3.0" - use-isomorphic-layout-effect: "npm:^1.1.2" + use-isomorphic-layout-effect: "npm:^1.2.0" peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 10/16a4543b1d9ffbf54dd2f749cc5ff765254ad96186fbdac164c1e20e3c40a7c64b726e020050775b3d54d10b9ac6e60ff9eb7fd443010982496dad814958e5fa + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + checksum: 10/2206b6687d6584ff1426056a779d8014ef4d8c4d1d5253dea4f03b01569fdedab8ae6b683ef475ead7da5a824934008b682838d734841d9734e2a8a63b9959fd languageName: node linkType: hard @@ -30020,15 +30020,15 @@ __metadata: languageName: node linkType: hard -"use-isomorphic-layout-effect@npm:^1.1.2": - version: 1.1.2 - resolution: "use-isomorphic-layout-effect@npm:1.1.2" +"use-isomorphic-layout-effect@npm:^1.2.0": + version: 1.2.0 + resolution: "use-isomorphic-layout-effect@npm:1.2.0" peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: "@types/react": optional: true - checksum: 10/fd3787ed19f6cfbf70e2c5822d01bebbf96b00968195840d5ad61082b8e6ca7a8e2e46270c4096537d18a38ea57f4e4e9668cce5eec36fa4697ddba2ef1203fd + checksum: 10/84fc1074b4e3ee2886fde944baef4ec210453fc78861429fe50ae97be8209e492f18c059c6b2ff1a21df231d72d1638707dabca889bd9d7bee36f21c196a0d19 languageName: node linkType: hard From 1f8f9a45d76162f4ee4332a3c284333fdb765436 Mon Sep 17 00:00:00 2001 From: Alexander Akhmetov Date: Mon, 16 Dec 2024 15:30:38 +0100 Subject: [PATCH 30/38] Alerting: Add state_periodic_save_batch_size config option (#98019) * Alerting: Add state_periodic_save_batch_size config option --------- Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com> --- conf/defaults.ini | 3 + conf/sample.ini | 3 + .../set-up/performance-limitations/index.md | 4 +- pkg/services/ngalert/ngalert.go | 1 + pkg/services/ngalert/state/manager.go | 3 + pkg/services/ngalert/state/persist.go | 2 +- pkg/services/ngalert/state/persister_async.go | 6 +- pkg/services/ngalert/state/testing.go | 2 +- .../ngalert/store/instance_database.go | 109 ++++++++++---- .../ngalert/store/instance_database_test.go | 138 +++++++++++++++++- pkg/setting/setting_unified_alerting.go | 9 +- 11 files changed, 243 insertions(+), 37 deletions(-) diff --git a/conf/defaults.ini b/conf/defaults.ini index 212c57353b2..29a67d076a1 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -1354,6 +1354,9 @@ max_state_save_concurrency = 1 # The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m. state_periodic_save_interval = 5m +# If the feature flag 'alertingSaveStatePeriodic' is enabled, this is the size of the batch that is saved to the database at once. +state_periodic_save_batch_size = 1 + # Disables the smoothing of alert evaluations across their evaluation window. # Rules will evaluate in sync. disable_jitter = false diff --git a/conf/sample.ini b/conf/sample.ini index 99dfb68fdb8..d9bcd3fb70b 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -1338,6 +1338,9 @@ # The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m. ;state_periodic_save_interval = 5m +# If the feature flag 'alertingSaveStatePeriodic' is enabled, this is the size of the batch that is saved to the database at once. +;state_periodic_save_batch_size = 1 + # Disables the smoothing of alert evaluations across their evaluation window. # Rules will evaluate in sync. ;disable_jitter = false diff --git a/docs/sources/alerting/set-up/performance-limitations/index.md b/docs/sources/alerting/set-up/performance-limitations/index.md index 2d80cdd6dad..69becbad450 100644 --- a/docs/sources/alerting/set-up/performance-limitations/index.md +++ b/docs/sources/alerting/set-up/performance-limitations/index.md @@ -63,7 +63,9 @@ transition of an alert instance is saved in the database. This can be prevented by writing to the database periodically. For this the feature flag `alertingSaveStatePeriodic` needs to be enabled. By default, it saves the states every 5 minutes to the database and on each shutdown. The periodic interval -can also be configured using the `state_periodic_save_interval` configuration flag. +can also be configured using the `state_periodic_save_interval` configuration flag. During this process, Grafana deletes all existing alert instances from the +database and then writes the entire current set of instances back in batches in a single transacton. +Configure the size of each batch using the `state_periodic_save_batch_size` configuration option. The time it takes to write to the database periodically can be monitored using the `state_full_sync_duration_seconds` metric that is exposed by Grafana. diff --git a/pkg/services/ngalert/ngalert.go b/pkg/services/ngalert/ngalert.go index d423e10e5aa..e538a14c9b0 100644 --- a/pkg/services/ngalert/ngalert.go +++ b/pkg/services/ngalert/ngalert.go @@ -409,6 +409,7 @@ func (ng *AlertNG) init() error { DoNotSaveNormalState: ng.FeatureToggles.IsEnabledGlobally(featuremgmt.FlagAlertingNoNormalState), ApplyNoDataAndErrorToAllStates: ng.FeatureToggles.IsEnabledGlobally(featuremgmt.FlagAlertingNoDataErrorExecution), MaxStateSaveConcurrency: ng.Cfg.UnifiedAlerting.MaxStateSaveConcurrency, + StatePeriodicSaveBatchSize: ng.Cfg.UnifiedAlerting.StatePeriodicSaveBatchSize, RulesPerRuleGroupLimit: ng.Cfg.UnifiedAlerting.RulesPerRuleGroupLimit, Tracer: ng.tracer, Log: log.New("ngalert.state.manager"), diff --git a/pkg/services/ngalert/state/manager.go b/pkg/services/ngalert/state/manager.go index 88e8c3b6dd4..e9ee28e1387 100644 --- a/pkg/services/ngalert/state/manager.go +++ b/pkg/services/ngalert/state/manager.go @@ -71,6 +71,9 @@ type ManagerCfg struct { DoNotSaveNormalState bool // MaxStateSaveConcurrency controls the number of goroutines (per rule) that can save alert state in parallel. MaxStateSaveConcurrency int + // StatePeriodicSaveBatchSize controls the size of the alert instance batch that is saved periodically when the + // alertingSaveStatePeriodic feature flag is enabled. + StatePeriodicSaveBatchSize int // ApplyNoDataAndErrorToAllStates makes state manager to apply exceptional results (NoData and Error) // to all states when corresponding execution in the rule definition is set to either `Alerting` or `OK` ApplyNoDataAndErrorToAllStates bool diff --git a/pkg/services/ngalert/state/persist.go b/pkg/services/ngalert/state/persist.go index 5249a2f1ee5..b4157c8cb69 100644 --- a/pkg/services/ngalert/state/persist.go +++ b/pkg/services/ngalert/state/persist.go @@ -16,7 +16,7 @@ type InstanceStore interface { // SaveAlertInstancesForRule overwrites the state for the given rule. SaveAlertInstancesForRule(ctx context.Context, key models.AlertRuleKeyWithGroup, instances []models.AlertInstance) error DeleteAlertInstancesByRule(ctx context.Context, key models.AlertRuleKeyWithGroup) error - FullSync(ctx context.Context, instances []models.AlertInstance) error + FullSync(ctx context.Context, instances []models.AlertInstance, batchSize int) error } // InstanceReader provides methods to fetch alert instances. diff --git a/pkg/services/ngalert/state/persister_async.go b/pkg/services/ngalert/state/persister_async.go index cc617866202..dd741addf50 100644 --- a/pkg/services/ngalert/state/persister_async.go +++ b/pkg/services/ngalert/state/persister_async.go @@ -20,6 +20,7 @@ type AsyncStatePersister struct { log log.Logger // doNotSaveNormalState controls whether eval.Normal state is persisted to the database and returned by get methods. doNotSaveNormalState bool + batchSize int store InstanceStore ticker *clock.Ticker metrics *metrics.State @@ -31,6 +32,7 @@ func NewAsyncStatePersister(log log.Logger, ticker *clock.Ticker, cfg ManagerCfg store: cfg.InstanceStore, ticker: ticker, doNotSaveNormalState: cfg.DoNotSaveNormalState, + batchSize: cfg.StatePeriodicSaveBatchSize, metrics: cfg.Metrics, } } @@ -58,11 +60,11 @@ func (a *AsyncStatePersister) fullSync(ctx context.Context, instancesProvider Al startTime := time.Now() a.log.Debug("Full state sync start") instances := instancesProvider.GetAlertInstances(a.doNotSaveNormalState) - if err := a.store.FullSync(ctx, instances); err != nil { + if err := a.store.FullSync(ctx, instances, a.batchSize); err != nil { a.log.Error("Full state sync failed", "duration", time.Since(startTime), "instances", len(instances)) return err } - a.log.Debug("Full state sync done", "duration", time.Since(startTime), "instances", len(instances)) + a.log.Debug("Full state sync done", "duration", time.Since(startTime), "instances", len(instances), "batchSize", a.batchSize) if a.metrics != nil { a.metrics.StateFullSyncDuration.Observe(time.Since(startTime).Seconds()) } diff --git a/pkg/services/ngalert/state/testing.go b/pkg/services/ngalert/state/testing.go index ebbc1bb3fc9..c35ead621c3 100644 --- a/pkg/services/ngalert/state/testing.go +++ b/pkg/services/ngalert/state/testing.go @@ -64,7 +64,7 @@ func (f *FakeInstanceStore) DeleteAlertInstancesByRule(ctx context.Context, key return nil } -func (f *FakeInstanceStore) FullSync(ctx context.Context, instances []models.AlertInstance) error { +func (f *FakeInstanceStore) FullSync(ctx context.Context, instances []models.AlertInstance, batchSize int) error { f.mtx.Lock() defer f.mtx.Unlock() f.recordedOps = []any{} diff --git a/pkg/services/ngalert/store/instance_database.go b/pkg/services/ngalert/store/instance_database.go index 35a88c9599c..bb11d90a464 100644 --- a/pkg/services/ngalert/store/instance_database.go +++ b/pkg/services/ngalert/store/instance_database.go @@ -224,51 +224,108 @@ func (st DBstore) DeleteAlertInstancesByRule(ctx context.Context, key models.Ale }) } -func (st DBstore) FullSync(ctx context.Context, instances []models.AlertInstance) error { +// FullSync performs a full synchronization of the given alert instances to the database. +// +// This method will delete all existing alert instances and insert the given instances in a single transaction. +// +// The batchSize parameter controls how many instances are inserted per batch. Increasing batchSize can improve +// performance for large datasets, but can also increase load on the database. +func (st DBstore) FullSync(ctx context.Context, instances []models.AlertInstance, batchSize int) error { if len(instances) == 0 { return nil } + + if batchSize <= 0 { + batchSize = 1 + } + return st.SQLStore.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error { // First we delete all records from the table if _, err := sess.Exec("DELETE FROM alert_instance"); err != nil { return fmt.Errorf("failed to delete alert_instance table: %w", err) } - for _, alertInstance := range instances { - if err := models.ValidateAlertInstance(alertInstance); err != nil { - st.Logger.Warn("Failed to validate alert instance, skipping", "err", err, "rule_uid", alertInstance.RuleUID) - continue - } - labelTupleJSON, err := alertInstance.Labels.StringKey() - if err != nil { - st.Logger.Warn("Failed to generate alert instance labels key, skipping", "err", err, "rule_uid", alertInstance.RuleUID) - continue + + total := len(instances) + for start := 0; start < total; start += batchSize { + end := start + batchSize + if end > total { + end = total } - _, err = sess.Exec( - "INSERT INTO alert_instance (rule_org_id, rule_uid, labels, labels_hash, current_state, current_reason, current_state_since, current_state_end, last_eval_time, resolved_at, last_sent_at) VALUES (?,?,?,?,?,?,?,?,?,?,?)", - alertInstance.RuleOrgID, - alertInstance.RuleUID, - labelTupleJSON, - alertInstance.LabelsHash, - alertInstance.CurrentState, - alertInstance.CurrentReason, - alertInstance.CurrentStateSince.Unix(), - alertInstance.CurrentStateEnd.Unix(), - alertInstance.LastEvalTime.Unix(), - nullableTimeToUnix(alertInstance.ResolvedAt), - nullableTimeToUnix(alertInstance.LastSentAt), - ) - if err != nil { - return fmt.Errorf("failed to insert into alert_instance table: %w", err) + batch := instances[start:end] + + if err := st.insertInstancesBatch(sess, batch); err != nil { + return fmt.Errorf("failed to insert batch [%d:%d]: %w", start, end, err) } } + if err := sess.Commit(); err != nil { return fmt.Errorf("failed to commit alert_instance table: %w", err) } + return nil }) } +func (st DBstore) insertInstancesBatch(sess *sqlstore.DBSession, batch []models.AlertInstance) error { + // If the batch is empty, nothing to insert. + if len(batch) == 0 { + return nil + } + + query := strings.Builder{} + placeholders := make([]string, 0, len(batch)) + args := make([]any, 0, len(batch)*11) + + query.WriteString("INSERT INTO alert_instance ") + query.WriteString("(rule_org_id, rule_uid, labels, labels_hash, current_state, current_reason, current_state_since, current_state_end, last_eval_time, resolved_at, last_sent_at) VALUES ") + + for _, instance := range batch { + if err := models.ValidateAlertInstance(instance); err != nil { + st.Logger.Warn("Skipping invalid alert instance", "err", err, "rule_uid", instance.RuleUID) + continue + } + + labelTupleJSON, err := instance.Labels.StringKey() + if err != nil { + st.Logger.Warn("Skipping instance with invalid labels key", "err", err, "rule_uid", instance.RuleUID) + continue + } + + placeholders = append(placeholders, "(?,?,?,?,?,?,?,?,?,?,?)") + args = append(args, + instance.RuleOrgID, + instance.RuleUID, + labelTupleJSON, + instance.LabelsHash, + instance.CurrentState, + instance.CurrentReason, + instance.CurrentStateSince.Unix(), + instance.CurrentStateEnd.Unix(), + instance.LastEvalTime.Unix(), + nullableTimeToUnix(instance.ResolvedAt), + nullableTimeToUnix(instance.LastSentAt), + ) + } + + // If no valid instances were found in this batch, skip insertion. + if len(placeholders) == 0 { + return nil + } + + query.WriteString(strings.Join(placeholders, ",")) + + execArgs := make([]any, 0, len(args)+1) + execArgs = append(execArgs, query.String()) + execArgs = append(execArgs, args...) + + if _, err := sess.Exec(execArgs...); err != nil { + return fmt.Errorf("failed to insert instances: %w", err) + } + + return nil +} + // nullableTimeToUnix converts a nullable time.Time to nil, if it is nil, otherwise it converts the time.Time to a unix timestamp. func nullableTimeToUnix(t *time.Time) *int64 { if t == nil { diff --git a/pkg/services/ngalert/store/instance_database_test.go b/pkg/services/ngalert/store/instance_database_test.go index eefc5f080c0..87016b9e50a 100644 --- a/pkg/services/ngalert/store/instance_database_test.go +++ b/pkg/services/ngalert/store/instance_database_test.go @@ -297,6 +297,8 @@ func TestIntegrationAlertInstanceOperations(t *testing.T) { } func TestIntegrationFullSync(t *testing.T) { + batchSize := 1 + ctx := context.Background() _, dbstore := tests.SetupTestEnv(t, baseIntervalSeconds) @@ -310,7 +312,7 @@ func TestIntegrationFullSync(t *testing.T) { } t.Run("Should do a proper full sync", func(t *testing.T) { - err := dbstore.FullSync(ctx, instances) + err := dbstore.FullSync(ctx, instances, batchSize) require.NoError(t, err) res, err := dbstore.ListAlertInstances(ctx, &models.ListAlertInstancesQuery{ @@ -331,8 +333,9 @@ func TestIntegrationFullSync(t *testing.T) { } } }) + t.Run("Should remove non existing entries on sync", func(t *testing.T) { - err := dbstore.FullSync(ctx, instances[1:]) + err := dbstore.FullSync(ctx, instances[1:], batchSize) require.NoError(t, err) res, err := dbstore.ListAlertInstances(ctx, &models.ListAlertInstancesQuery{ @@ -346,9 +349,10 @@ func TestIntegrationFullSync(t *testing.T) { } } }) + t.Run("Should add new entries on sync", func(t *testing.T) { newRuleUID := "y" - err := dbstore.FullSync(ctx, append(instances, generateTestAlertInstance(orgID, newRuleUID))) + err := dbstore.FullSync(ctx, append(instances, generateTestAlertInstance(orgID, newRuleUID)), batchSize) require.NoError(t, err) res, err := dbstore.ListAlertInstances(ctx, &models.ListAlertInstancesQuery{ @@ -369,6 +373,134 @@ func TestIntegrationFullSync(t *testing.T) { } } }) + + t.Run("Should save all instances when batch size is bigger than 1", func(t *testing.T) { + batchSize = 2 + newRuleUID := "y" + err := dbstore.FullSync(ctx, append(instances, generateTestAlertInstance(orgID, newRuleUID)), batchSize) + require.NoError(t, err) + + res, err := dbstore.ListAlertInstances(ctx, &models.ListAlertInstancesQuery{ + RuleOrgID: orgID, + }) + require.NoError(t, err) + require.Len(t, res, len(instances)+1) + for _, ruleUID := range append(ruleUIDs, newRuleUID) { + found := false + for _, instance := range res { + if instance.RuleUID == ruleUID { + found = true + continue + } + } + if !found { + t.Errorf("Instance with RuleUID '%s' not found", ruleUID) + } + } + }) + + t.Run("Should not fail when the instances are empty", func(t *testing.T) { + // First, insert some data into the table. + initialInstances := []models.AlertInstance{ + generateTestAlertInstance(orgID, "preexisting-1"), + generateTestAlertInstance(orgID, "preexisting-2"), + } + err := dbstore.FullSync(ctx, initialInstances, 5) + require.NoError(t, err) + + // Now call FullSync with no instances. According to the code, this should return nil + // and should not delete anything in the table. + err = dbstore.FullSync(ctx, []models.AlertInstance{}, 5) + require.NoError(t, err) + + // Check that the previously inserted instances are still present. + res, err := dbstore.ListAlertInstances(ctx, &models.ListAlertInstancesQuery{ + RuleOrgID: orgID, + }) + require.NoError(t, err) + require.Len(t, res, 2, "Expected the preexisting instances to remain since empty sync does nothing") + + found1, found2 := false, false + for _, r := range res { + if r.RuleUID == "preexisting-1" { + found1 = true + } + if r.RuleUID == "preexisting-2" { + found2 = true + } + } + require.True(t, found1, "Expected preexisting-1 to remain") + require.True(t, found2, "Expected preexisting-2 to remain") + }) + + t.Run("Should handle invalid instances by skipping them", func(t *testing.T) { + // Create a batch with one valid and one invalid instance + validInstance := generateTestAlertInstance(orgID, "valid") + + invalidInstance := generateTestAlertInstance(orgID, "") + // Make the invalid instance actually invalid + invalidInstance.AlertInstanceKey.RuleUID = "" + + err := dbstore.FullSync(ctx, []models.AlertInstance{validInstance, invalidInstance}, 2) + require.NoError(t, err) + + // Only the valid instance should be saved. + res, err := dbstore.ListAlertInstances(ctx, &models.ListAlertInstancesQuery{ + RuleOrgID: orgID, + }) + require.NoError(t, err) + require.Len(t, res, 1) + require.Equal(t, "valid", res[0].RuleUID) + }) + + t.Run("Should handle batchSize larger than the number of instances", func(t *testing.T) { + // Insert a small number of instances but use a large batchSize + smallSet := []models.AlertInstance{ + generateTestAlertInstance(orgID, "batch-test1"), + generateTestAlertInstance(orgID, "batch-test2"), + } + + err := dbstore.FullSync(ctx, smallSet, 100) + require.NoError(t, err) + + res, err := dbstore.ListAlertInstances(ctx, &models.ListAlertInstancesQuery{ + RuleOrgID: orgID, + }) + require.NoError(t, err) + require.Len(t, res, len(smallSet)) + found1, found2 := false, false + for _, r := range res { + if r.RuleUID == "batch-test1" { + found1 = true + } + if r.RuleUID == "batch-test2" { + found2 = true + } + } + require.True(t, found1) + require.True(t, found2) + }) + + t.Run("Should handle a large set of instances with a moderate batchSize", func(t *testing.T) { + // Clear everything first. + err := dbstore.FullSync(ctx, []models.AlertInstance{}, 1) + require.NoError(t, err) + + largeCount := 300 + largeSet := make([]models.AlertInstance, largeCount) + for i := 0; i < largeCount; i++ { + largeSet[i] = generateTestAlertInstance(orgID, fmt.Sprintf("large-%d", i)) + } + + err = dbstore.FullSync(ctx, largeSet, 50) + require.NoError(t, err) + + res, err := dbstore.ListAlertInstances(ctx, &models.ListAlertInstancesQuery{ + RuleOrgID: orgID, + }) + require.NoError(t, err) + require.Len(t, res, largeCount) + }) } func generateTestAlertInstance(orgID int64, ruleID string) models.AlertInstance { diff --git a/pkg/setting/setting_unified_alerting.go b/pkg/setting/setting_unified_alerting.go index 1d602622c65..03bea25e0aa 100644 --- a/pkg/setting/setting_unified_alerting.go +++ b/pkg/setting/setting_unified_alerting.go @@ -114,9 +114,10 @@ type UnifiedAlertingSettings struct { RecordingRules RecordingRuleSettings // MaxStateSaveConcurrency controls the number of goroutines (per rule) that can save alert state in parallel. - MaxStateSaveConcurrency int - StatePeriodicSaveInterval time.Duration - RulesPerRuleGroupLimit int64 + MaxStateSaveConcurrency int + StatePeriodicSaveInterval time.Duration + StatePeriodicSaveBatchSize int + RulesPerRuleGroupLimit int64 // Retention period for Alertmanager notification log entries. NotificationLogRetention time.Duration @@ -457,6 +458,8 @@ func (cfg *Cfg) ReadUnifiedAlertingSettings(iniFile *ini.File) error { return err } + uaCfg.StatePeriodicSaveBatchSize = ua.Key("state_periodic_save_batch_size").MustInt(1) + uaCfg.NotificationLogRetention, err = gtime.ParseDuration(valueAsString(ua, "notification_log_retention", (5 * 24 * time.Hour).String())) if err != nil { return err From 7b24c4404df86eb5f02d733a20237a0375987668 Mon Sep 17 00:00:00 2001 From: Misi Date: Mon, 16 Dec 2024 15:59:59 +0100 Subject: [PATCH 31/38] Fix: Show organization attribute path only for GrafanaAdmins on the UI (#98002) * Show organization attribute path only for GrafanaAdmins * prettier --- public/app/features/auth-config/fields.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/features/auth-config/fields.tsx b/public/app/features/auth-config/fields.tsx index 5f81ee11bde..7214f79cfd2 100644 --- a/public/app/features/auth-config/fields.tsx +++ b/public/app/features/auth-config/fields.tsx @@ -473,7 +473,7 @@ export function fieldMap(provider: string): Record { label: 'Organization attribute path', description: 'JMESPath expression to use for organization lookup.', type: 'text', - hidden: !['generic_oauth', 'okta'].includes(provider), + hidden: !(['generic_oauth', 'okta'].includes(provider) && contextSrv.isGrafanaAdmin), }, defineAllowedGroups: { label: 'Define allowed groups', From eecfcf52c0c36ee7eaf6b549619de3e701fddc7d Mon Sep 17 00:00:00 2001 From: ismail simsek Date: Mon, 16 Dec 2024 16:00:53 +0100 Subject: [PATCH 32/38] Explore Metrics: Fix url sync for view by dropdown (#98026) fix url sync --- public/app/features/trails/DataTrail.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/public/app/features/trails/DataTrail.tsx b/public/app/features/trails/DataTrail.tsx index 547de8ee9c0..3583828cc53 100644 --- a/public/app/features/trails/DataTrail.tsx +++ b/public/app/features/trails/DataTrail.tsx @@ -33,6 +33,7 @@ import { sceneUtils, SceneVariable, SceneVariableSet, + UrlSyncContextProvider, UrlSyncManager, VariableDependencyConfig, VariableValueSelectors, @@ -668,7 +669,11 @@ export class DataTrail extends SceneObjectBase implements SceneO )} -
{topScene && }
+ {topScene && ( + +
{topScene && }
+
+ )} ); }; From 59014dc9249be87cad374071603fdfd32d6f1125 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 15:20:09 +0000 Subject: [PATCH 33/38] Update dependency @tanstack/react-virtual to v3.11.2 (#98041) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/yarn.lock b/yarn.lock index 46761399da3..d1db1b07fca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8395,21 +8395,21 @@ __metadata: linkType: hard "@tanstack/react-virtual@npm:^3.5.1, @tanstack/react-virtual@npm:^3.9.0": - version: 3.11.1 - resolution: "@tanstack/react-virtual@npm:3.11.1" + version: 3.11.2 + resolution: "@tanstack/react-virtual@npm:3.11.2" dependencies: - "@tanstack/virtual-core": "npm:3.10.9" + "@tanstack/virtual-core": "npm:3.11.2" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - checksum: 10/ccc525e048ebf48470bcc3b89a3ea652d7d92abf372f269ae0e3bd7c21a6724971e56b65da3457b481498298e6cb788fbaf04b0a52ce0e7aff2df4f254b3c5fe + checksum: 10/a1136da0ec4c2ecbd4f996d8b84f228f0b8d851b15806e01049a160ad1d9b2eef0e0a491035fe017c6f84a0e125334f69ea23b32c180df23614ea4a8eeb7490c languageName: node linkType: hard -"@tanstack/virtual-core@npm:3.10.9": - version: 3.10.9 - resolution: "@tanstack/virtual-core@npm:3.10.9" - checksum: 10/15140fc41c728ed08486eba4c9caadbdb3c594f02d3b55fddca63813bc32e8cde64faf6ca6385f9815aeeedbc441dd8c9590aca4319c16a91f39b1937ef4eac7 +"@tanstack/virtual-core@npm:3.11.2": + version: 3.11.2 + resolution: "@tanstack/virtual-core@npm:3.11.2" + checksum: 10/8433044a5c801052ba2e4cdda098cdc8e32adfd3a76ba31af7064bbdda60062fe221a3558096987baa66cd94f528855e887c282cb0f9eb99d3751457c2a62872 languageName: node linkType: hard From 2879166426208f073263d29008c1a5223df36c77 Mon Sep 17 00:00:00 2001 From: Kostas Pelelis <13784424+kpelelis@users.noreply.github.com> Date: Mon, 16 Dec 2024 17:27:29 +0200 Subject: [PATCH 34/38] Faro: Improve performance of TRACKING_URLS regex (#98022) There have been reports of faro performing poorly when the URLs generated are long (there was a 39KB one). The TRACKING_URLS we are using leading wildcard characters, leading to excessive backtracking. This commit uses a simpler regular expression, that ensures we are blocking the appropriate URLs without the performance hit. To prevent that from happening, a timed test is introduced. The timeout threshold is long enough to be hardware independent. --- .../GrafanaJavascriptAgentBackend.test.ts | 20 ++++++++++++++++--- .../GrafanaJavascriptAgentBackend.ts | 5 ++--- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/public/app/core/services/echo/backends/grafana-javascript-agent/GrafanaJavascriptAgentBackend.test.ts b/public/app/core/services/echo/backends/grafana-javascript-agent/GrafanaJavascriptAgentBackend.test.ts index ca7d940b2fc..5ee5b184736 100644 --- a/public/app/core/services/echo/backends/grafana-javascript-agent/GrafanaJavascriptAgentBackend.test.ts +++ b/public/app/core/services/echo/backends/grafana-javascript-agent/GrafanaJavascriptAgentBackend.test.ts @@ -5,7 +5,11 @@ import * as faroWebSdkModule from '@grafana/faro-web-sdk'; import { BrowserConfig, FetchTransport } from '@grafana/faro-web-sdk'; import { EchoSrvTransport } from './EchoSrvTransport'; -import { GrafanaJavascriptAgentBackend, GrafanaJavascriptAgentBackendOptions } from './GrafanaJavascriptAgentBackend'; +import { + GrafanaJavascriptAgentBackend, + GrafanaJavascriptAgentBackendOptions, + TRACKING_URLS, +} from './GrafanaJavascriptAgentBackend'; describe('GrafanaJavascriptAgentEchoBackend', () => { let mockedSetUser: jest.Mock; @@ -93,8 +97,7 @@ describe('GrafanaJavascriptAgentEchoBackend', () => { expect(initializeFaroMock.mock.calls[0][0].transports?.[0]).toBeInstanceOf(EchoSrvTransport); expect(initializeFaroMock.mock.calls[0][0].transports?.[0].getIgnoreUrls()).toEqual([ /.*\/log-grafana-javascript-agent.*/, - /.*.google-analytics.com*.*/, - /.*.googletagmanager.com*.*/, + /\.(google-analytics|googletagmanager)\.com/, /frontend-metrics/, /\/collect(?:\/[\w]*)?$/, ]); @@ -116,6 +119,17 @@ describe('GrafanaJavascriptAgentEchoBackend', () => { }); }); + test('will ensure the performance of TRACKING_URLS', async () => { + // 10e6 is based on true events + const longString = Array.from({ length: 10e6 }, () => Math.random().toString(36)[2]).join(''); + const maxExecutionTime = 500; + + const start = performance.now(); + TRACKING_URLS.some((u) => u && longString.match(u) !== null); + const end = performance.now(); + expect(end - start).toBeLessThanOrEqual(maxExecutionTime); + }); + //@FIXME - make integration test work // it('integration test with EchoSrv and GrafanaJavascriptAgent', async () => { diff --git a/public/app/core/services/echo/backends/grafana-javascript-agent/GrafanaJavascriptAgentBackend.ts b/public/app/core/services/echo/backends/grafana-javascript-agent/GrafanaJavascriptAgentBackend.ts index 4ea54e38053..2aa81fb11fc 100644 --- a/public/app/core/services/echo/backends/grafana-javascript-agent/GrafanaJavascriptAgentBackend.ts +++ b/public/app/core/services/echo/backends/grafana-javascript-agent/GrafanaJavascriptAgentBackend.ts @@ -37,9 +37,8 @@ export interface GrafanaJavascriptAgentBackendOptions extends BrowserConfig { ignoreUrls: RegExp[]; } -const TRACKING_URLS = [ - /.*.google-analytics.com*.*/, - /.*.googletagmanager.com*.*/, +export const TRACKING_URLS = [ + /\.(google-analytics|googletagmanager)\.com/, /frontend-metrics/, /\/collect(?:\/[\w]*)?$/, ]; From 17a9974b87db0df85b1422c59a28d29b1ab26d68 Mon Sep 17 00:00:00 2001 From: Bruno Abrantes Date: Mon, 16 Dec 2024 16:28:30 +0100 Subject: [PATCH 35/38] Storage: Removes integration tests for MySQL 5.7 since it is EOL (#98013) * Removes integration tests for MySQL 5.7 since it is EOL Signed-off-by: Bruno Abrantes * Remake drone.yml Signed-off-by: Bruno Abrantes --------- Signed-off-by: Bruno Abrantes --- .drone.yml | 174 +----------------- scripts/drone/events/release.star | 1 - scripts/drone/pipelines/benchmarks.star | 4 - .../drone/pipelines/integration_tests.star | 1 - scripts/drone/services/services.star | 13 -- scripts/drone/utils/images.star | 1 - 6 files changed, 1 insertion(+), 193 deletions(-) diff --git a/.drone.yml b/.drone.yml index e61e5e26c01..b9dcf35fcf1 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1021,18 +1021,6 @@ services: volumes: - name: postgres path: /var/lib/postgresql/data/pgdata -- commands: - - docker-entrypoint.sh mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci - environment: - MYSQL_DATABASE: grafana_tests - MYSQL_PASSWORD: password - MYSQL_ROOT_PASSWORD: rootpass - MYSQL_USER: grafana - image: mysql:5.7.39 - name: mysql57 - volumes: - - name: mysql57 - path: /var/lib/mysql - commands: - docker-entrypoint.sh mysqld --default-authentication-plugin=mysql_native_password environment: @@ -1161,27 +1149,6 @@ steps: POSTGRES_HOST: postgres image: golang:1.23.1-alpine name: postgres-integration-tests -- commands: - - dockerize -wait tcp://mysql57:3306 -timeout 120s - image: jwilder/dockerize:0.6.1 - name: wait-for-mysql-5.7 -- commands: - - apk add --update build-base - - apk add --update mysql-client - - cat devenv/docker/blocks/mysql_tests/setup.sql | mysql -h mysql57 -P 3306 -u root - -prootpass - - go clean -testcache - - go test -p=1 -count=1 -covermode=atomic -timeout=5m -run '^TestIntegration' $(find - ./pkg -type f -name '*_test.go' -exec grep -l '^func TestIntegration' '{}' '+' - | grep -o '\(.*\)/' | sort -u) - depends_on: - - wire-install - - wait-for-mysql-5.7 - environment: - GRAFANA_TEST_DB: mysql - MYSQL_HOST: mysql57 - image: golang:1.23.1-alpine - name: mysql-5.7-integration-tests - commands: - dockerize -wait tcp://mysql80:3306 -timeout 120s image: jwilder/dockerize:0.6.1 @@ -1274,9 +1241,6 @@ volumes: - name: postgres temp: medium: memory -- name: mysql57 - temp: - medium: memory - name: mysql80 temp: medium: memory @@ -1499,18 +1463,6 @@ services: volumes: - name: postgres path: /var/lib/postgresql/data/pgdata -- commands: - - docker-entrypoint.sh mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci - environment: - MYSQL_DATABASE: grafana_tests - MYSQL_PASSWORD: password - MYSQL_ROOT_PASSWORD: rootpass - MYSQL_USER: grafana - image: mysql:5.7.39 - name: mysql57 - volumes: - - name: mysql57 - path: /var/lib/mysql - commands: - docker-entrypoint.sh mysqld --default-authentication-plugin=mysql_native_password environment: @@ -1627,17 +1579,6 @@ steps: POSTGRES_HOST: postgres image: golang:1.23.1-alpine name: postgres-benchmark-integration-tests -- commands: - - apk add --update build-base - - if [ -z ${GO_PACKAGES} ]; then echo 'missing GO_PACKAGES'; false; fi - - go test -v -run=^$ -benchmem -timeout=1h -count=8 -bench=. ${GO_PACKAGES} - depends_on: - - wire-install - environment: - GRAFANA_TEST_DB: mysql - MYSQL_HOST: mysql57 - image: golang:1.23.1-alpine - name: mysql-5.7-benchmark-integration-tests - commands: - apk add --update build-base - if [ -z ${GO_PACKAGES} ]; then echo 'missing GO_PACKAGES'; false; fi @@ -1662,9 +1603,6 @@ volumes: - name: postgres temp: medium: memory -- name: mysql57 - temp: - medium: memory - name: mysql80 temp: medium: memory @@ -2617,18 +2555,6 @@ services: volumes: - name: postgres path: /var/lib/postgresql/data/pgdata -- commands: - - docker-entrypoint.sh mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci - environment: - MYSQL_DATABASE: grafana_tests - MYSQL_PASSWORD: password - MYSQL_ROOT_PASSWORD: rootpass - MYSQL_USER: grafana - image: mysql:5.7.39 - name: mysql57 - volumes: - - name: mysql57 - path: /var/lib/mysql - commands: - docker-entrypoint.sh mysqld --default-authentication-plugin=mysql_native_password environment: @@ -2718,27 +2644,6 @@ steps: POSTGRES_HOST: postgres image: golang:1.23.1-alpine name: postgres-integration-tests -- commands: - - dockerize -wait tcp://mysql57:3306 -timeout 120s - image: jwilder/dockerize:0.6.1 - name: wait-for-mysql-5.7 -- commands: - - apk add --update build-base - - apk add --update mysql-client - - cat devenv/docker/blocks/mysql_tests/setup.sql | mysql -h mysql57 -P 3306 -u root - -prootpass - - go clean -testcache - - go test -p=1 -count=1 -covermode=atomic -timeout=5m -run '^TestIntegration' $(find - ./pkg -type f -name '*_test.go' -exec grep -l '^func TestIntegration' '{}' '+' - | grep -o '\(.*\)/' | sort -u) - depends_on: - - wire-install - - wait-for-mysql-5.7 - environment: - GRAFANA_TEST_DB: mysql - MYSQL_HOST: mysql57 - image: golang:1.23.1-alpine - name: mysql-5.7-integration-tests - commands: - dockerize -wait tcp://mysql80:3306 -timeout 120s image: jwilder/dockerize:0.6.1 @@ -2827,9 +2732,6 @@ volumes: - name: postgres temp: medium: memory -- name: mysql57 - temp: - medium: memory - name: mysql80 temp: medium: memory @@ -3201,18 +3103,6 @@ services: volumes: - name: postgres path: /var/lib/postgresql/data/pgdata -- commands: - - docker-entrypoint.sh mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci - environment: - MYSQL_DATABASE: grafana_tests - MYSQL_PASSWORD: password - MYSQL_ROOT_PASSWORD: rootpass - MYSQL_USER: grafana - image: mysql:5.7.39 - name: mysql57 - volumes: - - name: mysql57 - path: /var/lib/mysql - commands: - docker-entrypoint.sh mysqld --default-authentication-plugin=mysql_native_password environment: @@ -3302,27 +3192,6 @@ steps: POSTGRES_HOST: postgres image: golang:1.23.1-alpine name: postgres-integration-tests -- commands: - - dockerize -wait tcp://mysql57:3306 -timeout 120s - image: jwilder/dockerize:0.6.1 - name: wait-for-mysql-5.7 -- commands: - - apk add --update build-base - - apk add --update mysql-client - - cat devenv/docker/blocks/mysql_tests/setup.sql | mysql -h mysql57 -P 3306 -u root - -prootpass - - go clean -testcache - - go test -p=1 -count=1 -covermode=atomic -timeout=5m -run '^TestIntegration' $(find - ./pkg -type f -name '*_test.go' -exec grep -l '^func TestIntegration' '{}' '+' - | grep -o '\(.*\)/' | sort -u) - depends_on: - - wire-install - - wait-for-mysql-5.7 - environment: - GRAFANA_TEST_DB: mysql - MYSQL_HOST: mysql57 - image: golang:1.23.1-alpine - name: mysql-5.7-integration-tests - commands: - dockerize -wait tcp://mysql80:3306 -timeout 120s image: jwilder/dockerize:0.6.1 @@ -3409,9 +3278,6 @@ volumes: - name: postgres temp: medium: memory -- name: mysql57 - temp: - medium: memory - name: mysql80 temp: medium: memory @@ -4954,18 +4820,6 @@ services: volumes: - name: postgres path: /var/lib/postgresql/data/pgdata -- commands: - - docker-entrypoint.sh mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci - environment: - MYSQL_DATABASE: grafana_tests - MYSQL_PASSWORD: password - MYSQL_ROOT_PASSWORD: rootpass - MYSQL_USER: grafana - image: mysql:5.7.39 - name: mysql57 - volumes: - - name: mysql57 - path: /var/lib/mysql - commands: - docker-entrypoint.sh mysqld --default-authentication-plugin=mysql_native_password environment: @@ -5048,27 +4902,6 @@ steps: POSTGRES_HOST: postgres image: golang:1.23.1-alpine name: postgres-integration-tests -- commands: - - dockerize -wait tcp://mysql57:3306 -timeout 120s - image: jwilder/dockerize:0.6.1 - name: wait-for-mysql-5.7 -- commands: - - apk add --update build-base - - apk add --update mysql-client - - cat devenv/docker/blocks/mysql_tests/setup.sql | mysql -h mysql57 -P 3306 -u root - -prootpass - - go clean -testcache - - go test -p=1 -count=1 -covermode=atomic -timeout=5m -run '^TestIntegration' $(find - ./pkg -type f -name '*_test.go' -exec grep -l '^func TestIntegration' '{}' '+' - | grep -o '\(.*\)/' | sort -u) - depends_on: - - wire-install - - wait-for-mysql-5.7 - environment: - GRAFANA_TEST_DB: mysql - MYSQL_HOST: mysql57 - image: golang:1.23.1-alpine - name: mysql-5.7-integration-tests - commands: - dockerize -wait tcp://mysql80:3306 -timeout 120s image: jwilder/dockerize:0.6.1 @@ -5150,9 +4983,6 @@ volumes: - name: postgres temp: medium: memory -- name: mysql57 - temp: - medium: memory - name: mysql80 temp: medium: memory @@ -5454,7 +5284,6 @@ steps: - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM python:3.8 - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM postgres:12.3-alpine - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM grafana/mimir-alpine:r316-55f47f8 - - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM mysql:5.7.39 - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM mysql:8.0.32 - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM redis:6.2.11-alpine - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM memcached:1.6.9-alpine @@ -5493,7 +5322,6 @@ steps: - trivy --exit-code 1 --severity HIGH,CRITICAL python:3.8 - trivy --exit-code 1 --severity HIGH,CRITICAL postgres:12.3-alpine - trivy --exit-code 1 --severity HIGH,CRITICAL grafana/mimir-alpine:r316-55f47f8 - - trivy --exit-code 1 --severity HIGH,CRITICAL mysql:5.7.39 - trivy --exit-code 1 --severity HIGH,CRITICAL mysql:8.0.32 - trivy --exit-code 1 --severity HIGH,CRITICAL redis:6.2.11-alpine - trivy --exit-code 1 --severity HIGH,CRITICAL memcached:1.6.9-alpine @@ -5751,6 +5579,6 @@ kind: secret name: gcr_credentials --- kind: signature -hmac: 08edb24b8ec53e0ce09f525cf6fdf4ea5dc67710fe64c3ea93ceaf3af42b8305 +hmac: 341dbe9d2f9c6d2ee70026e495921ea4670550729350047ec0c680094497cc44 ... diff --git a/scripts/drone/events/release.star b/scripts/drone/events/release.star index f7730176f61..8241657bc36 100644 --- a/scripts/drone/events/release.star +++ b/scripts/drone/events/release.star @@ -273,7 +273,6 @@ def integration_test_pipelines(): pipelines = [] volumes = integration_test_services_volumes() integration_test_steps = postgres_integration_tests_steps() + \ - mysql_integration_tests_steps("mysql57", "5.7") + \ mysql_integration_tests_steps("mysql80", "8.0") + \ redis_integration_tests_steps() + \ memcached_integration_tests_steps() + \ diff --git a/scripts/drone/pipelines/benchmarks.star b/scripts/drone/pipelines/benchmarks.star index b7d554b15f0..40bd49eea9e 100644 --- a/scripts/drone/pipelines/benchmarks.star +++ b/scripts/drone/pipelines/benchmarks.star @@ -66,10 +66,6 @@ def integration_benchmarks(prefix): "GRAFANA_TEST_DB": "postgres", "POSTGRES_HOST": "postgres", }) + \ - integration_benchmarks_step("mysql-5.7", { - "GRAFANA_TEST_DB": "mysql", - "MYSQL_HOST": "mysql57", - }) + \ integration_benchmarks_step("mysql-8.0", { "GRAFANA_TEST_DB": "mysql", "MYSQL_HOST": "mysql80", diff --git a/scripts/drone/pipelines/integration_tests.star b/scripts/drone/pipelines/integration_tests.star index 096b1b4b368..0fd23d427d4 100644 --- a/scripts/drone/pipelines/integration_tests.star +++ b/scripts/drone/pipelines/integration_tests.star @@ -71,7 +71,6 @@ def integration_tests(trigger, prefix, ver_mode = "pr"): # test_steps = [a, b] + [c, d] + [e, f]... test_steps = postgres_integration_tests_steps() + \ - mysql_integration_tests_steps("mysql57", "5.7") + \ mysql_integration_tests_steps("mysql80", "8.0") + \ redis_integration_tests_steps() + \ memcached_integration_tests_steps() + \ diff --git a/scripts/drone/services/services.star b/scripts/drone/services/services.star index 629f6016157..3796214a517 100644 --- a/scripts/drone/services/services.star +++ b/scripts/drone/services/services.star @@ -10,7 +10,6 @@ load( def integration_test_services_volumes(): return [ {"name": "postgres", "temp": {"medium": "memory"}}, - {"name": "mysql57", "temp": {"medium": "memory"}}, {"name": "mysql80", "temp": {"medium": "memory"}}, ] @@ -29,18 +28,6 @@ def integration_test_services(): {"name": "postgres", "path": "/var/lib/postgresql/data/pgdata"}, ], }, - { - "name": "mysql57", - "image": images["mysql5"], - "environment": { - "MYSQL_ROOT_PASSWORD": "rootpass", - "MYSQL_DATABASE": "grafana_tests", - "MYSQL_USER": "grafana", - "MYSQL_PASSWORD": "password", - }, - "volumes": [{"name": "mysql57", "path": "/var/lib/mysql"}], - "commands": ["docker-entrypoint.sh mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci"], - }, { "name": "mysql80", "image": images["mysql8"], diff --git a/scripts/drone/utils/images.star b/scripts/drone/utils/images.star index d892657f6b1..c0809849811 100644 --- a/scripts/drone/utils/images.star +++ b/scripts/drone/utils/images.star @@ -23,7 +23,6 @@ images = { "python": "python:3.8", "postgres_alpine": "postgres:12.3-alpine", "mimir": "grafana/mimir-alpine:r316-55f47f8", - "mysql5": "mysql:5.7.39", "mysql8": "mysql:8.0.32", "redis_alpine": "redis:6.2.11-alpine", "memcached_alpine": "memcached:1.6.9-alpine", From f3a47e2f8dbacc9eaef0379a8f91a1f08885f2dc Mon Sep 17 00:00:00 2001 From: Eric Leijonmarck Date: Mon, 16 Dec 2024 15:57:02 +0000 Subject: [PATCH 36/38] LBAC for datasources: Add `prometheus` as a data source and refactor to change wording from logs to logs or metrics (#98021) * Add prometheus as a datasource * update based on review --- .../data-source-management/teamlbac/_index.md | 52 ++++++++--- .../index.md | 92 +++++++++++++++++++ .../teamlbac/create-teamlbac-rules/index.md | 49 +++++----- 3 files changed, 155 insertions(+), 38 deletions(-) create mode 100644 docs/sources/administration/data-source-management/teamlbac/configure-teamlbac-for-prometheus/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 a9bc856fd81..48681fd4511 100644 --- a/docs/sources/administration/data-source-management/teamlbac/_index.md +++ b/docs/sources/administration/data-source-management/teamlbac/_index.md @@ -1,8 +1,9 @@ --- -description: Label based data access for Loki given Teams +description: Label based data access for Teams keywords: - grafana - loki + - mimir - lbac labels: products: @@ -14,17 +15,26 @@ weight: 100 # Label Based Access Control (LBAC) for data sources -Label Based Access Control (LBAC) simplifies and streamlines data source access management based on team memberships. +Label Based Access Control (LBAC) for data sources simplifies and streamlines data source access management based on team memberships. +Label-Based Access Control (LBAC) allows fine-grained access control to data sources by filtering logs or metrics based on labels. It lets administrators configure access rules for teams, ensuring that users only query data relevant to their assigned permissions. + +## Supported Data Sources + +LBAC for data sources is currently available for `Loki, Prometheus` with basic authentication. Support for additional data sources may be added in future updates. + +**LBAC for data sources offers:** + +- Team-based access control using `LogQL` rules. +- Simplified data source management by consolidating multiple sources into one. +- Dashboard reuse across teams with tailored access. {{< admonition type="note" >}} -LBAC rules is available for preview for logs with Loki in Grafana Cloud. +LBAC rules is available for **private preview** in Grafana Cloud. Report any unexpected behavior to the Grafana Support team. - -To use LBAC rules you must enable the `teamHttpHeaders` feature toggle because the feature uses HTTP headers for the LBAC rules requests. {{< /admonition >}} -You can configure user access based upon team memberships using LogQL. -LBAC for data sources controls access to logs depending on the rules set for each team. +You can configure user access based upon team memberships using `LogQL`. +LBAC for data sources controls access to logs or metrics depending on the rules set for each team. This feature addresses two common challenges faced by Grafana users: @@ -33,18 +43,32 @@ This feature addresses two common challenges faced by Grafana users: 1. Using the same dashboard across multiple teams. LBAC for data sources lets Grafana Teams use the same dashboard with different access control rules. -To set up LBAC for data sources for a Loki data source, refer to [Configure LBAC for data sources](https://grafana.com/docs/grafana//administration/data-source-management/teamlbac/configure-teamlbac-for-loki/). +To set up LBAC for data sources for a Loki data source, refer to [Configure LBAC for Loki Data Source](https://grafana.com/docs/grafana//administration/data-source-management/teamlbac/configure-teamlbac-for-loki/). +To set up LBAC for data sources for a Loki data source, refer to [Configure LBAC for Prometheus Data Source](https://grafana.com/docs/grafana//administration/data-source-management/teamlbac/configure-teamlbac-for-prometheus/). + +## Logs and Metrics Filtering with LBAC + +LBAC for data sources enables you to filter access for both logs and metrics. By defining rules with label selectors, you can specify: + +- **Logs**: Control access to log lines using LogQL queries with labels such as `namespace` or `cluster`. +- **Metrics**: Control access to metric data points using LogQL with labels such as `job` or `region` and access for metrics `__name__`. + +This flexibility allows teams to use the same data source for multiple use cases while maintaining secure access boundaries. + +## Before you begin + +To be able to use LBAC for data sources, you need to enable the feature toggle `teamHttpHeaders` on your Grafana instance. ## Limitations - There is a set number of rules to be configured within a data source, depending on the size of the rules. - Around ~500-600 rules is the upper limit. -- If there are no LBAC for data sources rules for a user's team, that user can query all logs. +- If there are no LBAC for data sources rules for a user's team, that user can query all logs or metrics. - If an administrator is part of a team with LBAC for data sources rules, those rules are applied to the administrator requests. - Cloud Access Policy (CAP) LBAC rules override LBAC for data sources rules. CAP are the access controls from Grafana Cloud. -You must remove any label selectors from your Cloud Access Policy that is configured for the Loki data source, otherwise the CAP label selectors override the LBAC for data sources rules. 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/). +You must remove any label selectors from your Cloud Access Policy that is configured for the data source, otherwise the CAP label selectors override the LBAC for data sources rules. 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/). ## Data source permissions @@ -54,17 +78,17 @@ You must remove any label selectors from your Cloud Access Policy that is config ## Recommended setup -It's recommended that you create a single Loki data source for using LBAC for data sources rules so you have a clear separation of data sources using LBAC for data sources and those that aren't. +It's recommended that you create a single data source for using LBAC for data sources rules so you have a clear separation of data sources using LBAC for data sources and those that aren't. All teams should have with only teams having `query` permission. -You should create another Loki data source configured without LBAC for data sources for full access to the logs. +You should create another data source configured without LBAC for data sources for full access. ## LBAC rules -Grafana adds LBAC for data sources rules to the HTTP request via the Loki data source. +Grafana adds LBAC for data sources rules to the HTTP request via the data source. If you configure multiple rules for a team, each rule is evaluated separately. Query results include lines that match any of the rules. Only users with data source `Admin` permissions can edit LBAC for data sources rules in the **Data source permissions** tab because changing LBAC rules requires the same access level as editing data source permissions. -To set up LBAC for data sources for a Loki data source, refer to [Configure LBAC for data sources](https://grafana.com/docs/grafana//administration/data-source-management/teamlbac/configure-teamlbac-for-loki/). +To set up LBAC for data sources for a data source, refer to [Configure LBAC for data sources](https://grafana.com/docs/grafana//administration/data-source-management/teamlbac/configure-teamlbac-for-loki/). diff --git a/docs/sources/administration/data-source-management/teamlbac/configure-teamlbac-for-prometheus/index.md b/docs/sources/administration/data-source-management/teamlbac/configure-teamlbac-for-prometheus/index.md new file mode 100644 index 00000000000..aa54d970e6f --- /dev/null +++ b/docs/sources/administration/data-source-management/teamlbac/configure-teamlbac-for-prometheus/index.md @@ -0,0 +1,92 @@ +--- +description: Configure LBAC for data sources for Prometheus data source +keywords: + - Prometheus + - datasource + - team +labels: + products: + - cloud + - enterprise +title: Configure LBAC for data sources for Prometheus +weight: 250 +--- + +# Configure LBAC for data sources for Prometheus data source + +## Grafana Cloud + +LBAC for data sources is available in private preview on Grafana Cloud for Prometheus created with basic authentication. Prometheus data sources for LBAC for data sources can only be created, provisioning is currently not available. + +You cannot configure LBAC rules for Grafana-provisioned data sources from the UI. Alternatively, you can replicate the setting of the provisioned data source in a new data source as described in [LBAC Configuration for New Prometheus Data Source](https://grafana.com/docs/grafana/latest/administration/data-source-management/teamlbac/configure-teamlbac-for-Prometheus/#task-1-lbac-configuration-for-new-Prometheus-data-source) and then add the LBAC configuration to the new data source. + +## Before you begin + +To be able to use LBAC for data sources rules, you need to enable the feature toggle `teamHttpHeaders` on your Grafana instance. Contact support to enable the feature toggle for you. + +- Be sure that you have the permission setup to create a Prometheus tenant in Grafana Cloud +- Be sure that you have admin data source permissions for Grafana. + +### Permissions + +We recommend that you remove all permissions for roles and teams that are not required to access the data source. This will help to ensure that only the required teams have access to the data source. The recommended permissions are `Admin` permission and only add the teams `Query` permissions that you want to add LBAC for data sources rules for. + +## Task 1: LBAC Configuration for New Prometheus Data Source + +1. Access Prometheus data sources details for your stack through grafana.com +1. Copy Prometheus details and create a CAP + - Copy the details of your Prometheus setup. + - Create a Cloud Access Policy (CAP) for the Prometheus data source in grafana.com. + - Ensure the CAP includes `metrics:read` permissions. + - Ensure the CAP does not include `labels` rules. +1. Create a new Prometheus data source + - In Grafana, proceed to add a new data source and select Prometheus as the type. +1. Navigate back to the Prometheus data source + - Set up the Prometheus data source using basic authentication. Use the `userID` as the username. Use the generated CAP `token` as the password. + - Save and connect. +1. Navigate to data source permissions + - Go to the permissions tab of the newly created Prometheus data source. Here, you'll find the LBAC for data sources rules section. + +For more information on how to setup LBAC for data sources rules for a Prometheus data source, refer to [Create LBAC for data sources rules for the Prometheus data source](https://grafana.com/docs/grafana//administration/data-source-management/teamlbac/create-teamlbac-rules/). + +## Grafana Enterprise + +LBAC for data sources is available in Grafana Enterprise for Prometheus created with basic authentication. Prometheus data sources for LBAC for data sources can only be created. + +You cannot configure LBAC rules for Grafana-provisioned data sources from the UI. Alternatively, you can replicate the setting of the provisioned data source in a new data source as described in [LBAC Configuration for New Prometheus Data Source](https://grafana.com/docs/grafana/latest/administration/data-source-management/teamlbac/configure-teamlbac-for-Prometheus/#task-1-lbac-configuration-for-new-Prometheus-data-source) and then add the LBAC configuration to the new data source. + +## Before you begin + +To be able to use LBAC for data sources rules, you need to enable the feature toggle `teamHttpHeaders` on your Grafana instance. Contact support to enable the feature toggle for you. + +- Be sure that you have the permission setup to create a cluster in your Grafana +- Be sure that you have admin plugins permissions for Grafana. +- Be sure that you have admin data source permissions for Grafana. + +### Permissions + +We recommend that you remove all permissions for roles and teams that are not required to access the data source. This will help to ensure that only the required teams have access to the data source. The recommended permissions are `Admin` permission and only add the teams `Query` permissions that you want to add LBAC for data sources rules for. + +## Task 0: Setup Grafana Enterprise Metrics tenant and access policies + +1. Access the plugins page and install Grafana Enterprise Metrics plugins +1. Connect your plugin and use app as the cluster +1. Access the app Grafana Enterprise Metrics and configure a tenant +1. Store the `uid` of the tenant to be used as the username for the basic authentication +1. Access the policies page inside of the app and create a AP + - Create a Access Policy (CAP) for the Prometheus data source. + - Ensure the CAP includes `metrics:read` permissions. + - Ensure the CAP does not include `labels` rules. + - Store the `token` to be used as password for authentication. + +## Task 1: LBAC Configuration for New Prometheus Data Source + +1. Create a new Prometheus data source + - In Grafana, proceed to add a new data source and select Prometheus as the type. +1. Navigate back to the Prometheus data source + - Set up the Prometheus data source using basic authentication. Use the `uid` as the username. Use the generated `token` as the password. + - Save and connect. +1. Navigate to data source permissions + - Go to the permissions tab of the newly created Prometheus data source. Here, you'll find the LBAC for data sources rules section. + +For more information on how to setup LBAC for data sources rules for a Prometheus data source, refer to [Create LBAC for data sources rules for the Prometheus data source](https://grafana.com/docs/grafana//administration/data-source-management/teamlbac/create-teamlbac-rules/). diff --git a/docs/sources/administration/data-source-management/teamlbac/create-teamlbac-rules/index.md b/docs/sources/administration/data-source-management/teamlbac/create-teamlbac-rules/index.md index cba9d8b3e30..3942490c0ff 100644 --- a/docs/sources/administration/data-source-management/teamlbac/create-teamlbac-rules/index.md +++ b/docs/sources/administration/data-source-management/teamlbac/create-teamlbac-rules/index.md @@ -1,5 +1,5 @@ --- -description: Learn how to create LBAC for data sources rules for the Loki data source. +description: Learn how to create LBAC for data sources rules for a supported data source. keywords: - loki - lbac @@ -7,13 +7,13 @@ keywords: labels: products: - cloud -title: Create LBAC for data sources rules for the Loki data source +title: Create LBAC for data sources rules for a supported data source weight: 250 --- -# Create LBAC for data sources rules for the Loki data source +# Create LBAC for data source rule -LBAC for data sources is available on Cloud for Loki data sources created with basic authentication. Managed/Provisioned Loki data source can **NOT** be configured with LBAC for data sources as of now. +LBAC for data sources is available for LBAC-supported data sources created with basic authentication. As of today, managed/provisioned data source can **NOT** be configured with LBAC rules. ## Before you begin @@ -23,19 +23,24 @@ To be able to use LBAC for data sources rules, you need to enable the feature to - Be sure that you have admin data source permissions for Grafana. - Be sure that you have a team setup in Grafana. -### Create a LBAC for data sources Rule for a team +### Create a LBAC for data sources rule for a team -1. Navigate to your Loki data source +1. Navigate to your data source 1. Navigate to the permissions tab - Here, you'll find the LBAC for data sources rules section. 1. Add a LBAC for data sources Rule - Add a new rule for the team in the LBAC for data sources rules section. 1. Define a label selector for the rule - - Add a label selector to the rule. Refer to Loki query documentation for guidance on the types of log selections you can specify. + - Add a label selector to the rule. Refer to documentation for guidance on the types of log selections you can specify. ### LBAC rule -A LBAC rule is a `logql` query that runs as a query to the Loki instance for your logs. Each rule operates independently as its own filter, separate from other rules within a team. For example, you can create a label policy that includes all log lines with a specific label. +An LBAC rule is a `logql` query that filters logs or metrics based on labels. Each rule operates independently as its own filter, separate from other rules within a team. + +For example: + +- For logs: `{namespace="dev", cluster="us-west-0"}` filters log lines matching both `namespace="dev"` and `cluster="us-west-0"`. +- For metrics: `{job="api-server", region="europe"}` filters metric data points matching `job="api-server"` and `region="europe"`. One rule `{namespace="dev", cluster="us-west-0"}` created with multiple namespaces will be seen as `namespace="dev"` **AND** `cluster="us-west-0"`. Two rules `{namespace="dev"}`, `{cluster="us-west-0"}` created for a team will be seen as `namespace="dev"` **OR** `cluster="us-west-0"`. @@ -46,39 +51,35 @@ We recommend you only add `query` permissions for teams that should use the data We recommend for a first setup, setting up as few rules as possible for each team and make them additive for simplicity. -To validate the rules, we recommend testing the rules in the Loki Explore view. This will allow you to see the logs that would be returned for the rule. +To validate the rules, we recommend testing the rules in the Explore view. This will allow you to see the metrics or logs that would be returned for the rule. #### Tasks -### Task 1: One rule set up for each team +### Task 1: One rule setup for each team -One common use case for creating an LBAC policy is to have specific access to logs that have a specific label. For example, you can create a label policy that includes all log lines with the label. +One common use case for creating an LBAC policy is to grant access to logs or metrics with a specific label. For example, you can create a label policy that includes all log lines or metrics with the label `namespace`. -We have two teams, Team A and Team B with `Query` permissions. Loki access is setup with `Admin` roles to have `Admin` permission only. +We have two teams, Team A and Team B with `Query` permissions. Data source access is set up with `Admin` roles to have `Admin` permission only. - Team A has a rule `namespace="dev"`. - Team B has a rule `namespace="prod"`. -A user that is part of Team A will have access to logs that match `namespace="dev"`. - -A user that is part of Team B will have access to logs that match `namespace="prod"`. - -A user that is part of Team A and Team B will have access to logs that match `namespace="dev"` OR `namespace="prod"`. +A user that is part of Team A will have access to logs or metrics matching `namespace="dev"`. A user in both Team A and Team B will have access to data matching `namespace="dev"` OR `namespace="prod"`. ### Task 2: Set up a rule to exclude a label for a team -One common use case for creating an LBAC policy is to exclude logs that have a specific label. For example, you can create a label policy that excludes all log lines with the label `secret=true` by adding a selector with `secret!="true"` when you create an access policy: +One common use case for creating an LBAC policy is to exclude logs or metrics that have a specific label. For example, you can create a label policy that excludes all log lines with the label `secret=true` by adding a selector with `secret!="true"` when you create an access policy: -We have one team, Team A `Query` permissions. Loki access is setup with `Admin` roles to have `Admin` permission only. +We have one team, Team A `Query` permissions. Data source access is setup with `Admin` roles to have `Admin` permission only. - Team A has a rule `secret!="true"`. -A user that is part of Team A will **NOT** have access to logs that match `secret!="true"`. +A user that is part of Team A will **NOT** have access to logs or metrics that match `secret!="true"`. ### Task 3: Set up multiple rules for a team -We have two teams, Team A and Team B with `Query` permissions. Loki access is setup with `Admin` roles having `Admin` permission. +We have two teams, Team A and Team B with `Query` permissions. Data Source access is setup with `Admin` roles having `Admin` permission. - Team A has rule `cluster="us-west-0", namespace=~"dev|prod"` configured. @@ -114,7 +115,7 @@ A user in Team B will have access to logs that match `namespace!="dev"`. ### Task 5: Single rule setup for a team -We have two teams, Team A and Team B. Loki access is setup with `Editor`, `Viewer` roles to have `Query` permission. +We have two teams, Team A and Team B. Data Source access is setup with `Editor`, `Viewer` roles to have `Query` permission. - Team A has a rule `namespace="dev"` configured. @@ -131,8 +132,8 @@ A user that is not part of Team A and part of Team B, that is `Editor` or `Viewe We have team B, user A is part of Team B and has an `Admin` basic role. - Team B has no roles assigned -- Team B has Query permissions to data source Loki +- Team B has Query permissions to data source - Team B has a rule `{ project_id="project-dev" }` -User A may only access logs for data source Loki that match `{ project_id="project-dev" }` and no other logs on the data source. +User A may only access logs or metrics for a data source that match `{ project_id="project-dev" }`. From b310b6f8c521e36653aeb4d1d4616f985090aa33 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 16:00:27 +0000 Subject: [PATCH 37/38] Update dependency react-use to v17.6.0 (#98042) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- packages/grafana-data/package.json | 2 +- packages/grafana-flamegraph/package.json | 2 +- .../grafana-o11y-ds-frontend/package.json | 2 +- packages/grafana-prometheus/package.json | 2 +- packages/grafana-runtime/package.json | 2 +- packages/grafana-sql/package.json | 2 +- packages/grafana-ui/package.json | 2 +- .../datasource/azuremonitor/package.json | 2 +- .../datasource/cloud-monitoring/package.json | 2 +- .../grafana-pyroscope-datasource/package.json | 2 +- .../grafana-testdata-datasource/package.json | 2 +- .../app/plugins/datasource/parca/package.json | 2 +- .../app/plugins/datasource/tempo/package.json | 2 +- .../plugins/datasource/zipkin/package.json | 2 +- yarn.lock | 38 +++++++++---------- 16 files changed, 34 insertions(+), 34 deletions(-) diff --git a/package.json b/package.json index 6648a018c8a..7c31d14ee7a 100644 --- a/package.json +++ b/package.json @@ -389,7 +389,7 @@ "react-split-pane": "0.1.92", "react-table": "7.8.0", "react-transition-group": "4.4.5", - "react-use": "17.5.1", + "react-use": "17.6.0", "react-virtual": "2.10.4", "react-virtualized-auto-sizer": "1.0.24", "react-window": "1.8.10", diff --git a/packages/grafana-data/package.json b/packages/grafana-data/package.json index bf294d4cf70..8840ce89acf 100644 --- a/packages/grafana-data/package.json +++ b/packages/grafana-data/package.json @@ -52,7 +52,7 @@ "moment-timezone": "0.5.46", "ol": "7.4.0", "papaparse": "5.4.1", - "react-use": "17.5.1", + "react-use": "17.6.0", "rxjs": "7.8.1", "string-hash": "^1.1.3", "tinycolor2": "1.6.0", diff --git a/packages/grafana-flamegraph/package.json b/packages/grafana-flamegraph/package.json index 6c29d354d38..a8a97a6e054 100644 --- a/packages/grafana-flamegraph/package.json +++ b/packages/grafana-flamegraph/package.json @@ -50,7 +50,7 @@ "d3": "^7.8.5", "lodash": "4.17.21", "react": "18.2.0", - "react-use": "17.5.1", + "react-use": "17.6.0", "react-virtualized-auto-sizer": "1.0.24", "tinycolor2": "1.6.0", "tslib": "2.7.0" diff --git a/packages/grafana-o11y-ds-frontend/package.json b/packages/grafana-o11y-ds-frontend/package.json index e836b93831d..3dc8d15c217 100644 --- a/packages/grafana-o11y-ds-frontend/package.json +++ b/packages/grafana-o11y-ds-frontend/package.json @@ -25,7 +25,7 @@ "@grafana/schema": "11.5.0-pre", "@grafana/ui": "11.5.0-pre", "react-select": "5.9.0", - "react-use": "17.5.1", + "react-use": "17.6.0", "rxjs": "7.8.1", "tslib": "2.7.0" }, diff --git a/packages/grafana-prometheus/package.json b/packages/grafana-prometheus/package.json index ac7a8604e74..635675922f2 100644 --- a/packages/grafana-prometheus/package.json +++ b/packages/grafana-prometheus/package.json @@ -66,7 +66,7 @@ "prismjs": "1.29.0", "react-highlight-words": "0.20.0", "react-select": "5.9.0", - "react-use": "17.5.1", + "react-use": "17.6.0", "react-window": "1.8.10", "rxjs": "7.8.1", "semver": "7.6.3", diff --git a/packages/grafana-runtime/package.json b/packages/grafana-runtime/package.json index 605996ab150..62202a9079a 100644 --- a/packages/grafana-runtime/package.json +++ b/packages/grafana-runtime/package.json @@ -44,7 +44,7 @@ "@grafana/ui": "11.5.0-pre", "history": "4.10.1", "lodash": "4.17.21", - "react-use": "17.5.1", + "react-use": "17.6.0", "rxjs": "7.8.1", "tslib": "2.7.0" }, diff --git a/packages/grafana-sql/package.json b/packages/grafana-sql/package.json index f62a7fbeba6..022ff223bd8 100644 --- a/packages/grafana-sql/package.json +++ b/packages/grafana-sql/package.json @@ -26,7 +26,7 @@ "react": "18.2.0", "react-dom": "18.2.0", "react-select": "5.9.0", - "react-use": "17.5.1", + "react-use": "17.6.0", "react-virtualized-auto-sizer": "1.0.24", "rxjs": "7.8.1", "sql-formatter-plus": "^1.3.6", diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index 2d38e1d7974..27600c1baf4 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -101,7 +101,7 @@ "react-select": "5.9.0", "react-table": "7.8.0", "react-transition-group": "4.4.5", - "react-use": "17.5.1", + "react-use": "17.6.0", "react-window": "1.8.10", "rxjs": "7.8.1", "slate": "0.47.9", diff --git a/public/app/plugins/datasource/azuremonitor/package.json b/public/app/plugins/datasource/azuremonitor/package.json index ec9a243185f..16a4e5d37a2 100644 --- a/public/app/plugins/datasource/azuremonitor/package.json +++ b/public/app/plugins/datasource/azuremonitor/package.json @@ -20,7 +20,7 @@ "react": "18.2.0", "react-dom": "18.2.0", "react-select": "5.9.0", - "react-use": "17.5.1", + "react-use": "17.6.0", "rxjs": "7.8.1", "tslib": "2.7.0" }, diff --git a/public/app/plugins/datasource/cloud-monitoring/package.json b/public/app/plugins/datasource/cloud-monitoring/package.json index 0f6dc9dbe6c..1dcf26348c2 100644 --- a/public/app/plugins/datasource/cloud-monitoring/package.json +++ b/public/app/plugins/datasource/cloud-monitoring/package.json @@ -21,7 +21,7 @@ "react": "18.2.0", "react-dom": "18.2.0", "react-select": "5.9.0", - "react-use": "17.5.1", + "react-use": "17.6.0", "rxjs": "7.8.1", "tslib": "2.7.0" }, diff --git a/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json b/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json index b9a62b84a26..7b5f827797c 100644 --- a/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json +++ b/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json @@ -15,7 +15,7 @@ "prismjs": "1.29.0", "react": "18.2.0", "react-dom": "18.2.0", - "react-use": "17.5.1", + "react-use": "17.6.0", "rxjs": "7.8.1", "tslib": "2.7.0" }, diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/package.json b/public/app/plugins/datasource/grafana-testdata-datasource/package.json index aa35c05c523..c6a0e9e1d83 100644 --- a/public/app/plugins/datasource/grafana-testdata-datasource/package.json +++ b/public/app/plugins/datasource/grafana-testdata-datasource/package.json @@ -16,7 +16,7 @@ "react": "18.2.0", "react-dom": "18.2.0", "react-select": "5.9.0", - "react-use": "17.5.1", + "react-use": "17.6.0", "rxjs": "7.8.1", "tslib": "2.7.0", "uuid": "9.0.1" diff --git a/public/app/plugins/datasource/parca/package.json b/public/app/plugins/datasource/parca/package.json index 9d217e0d0f8..eb9eeefb741 100644 --- a/public/app/plugins/datasource/parca/package.json +++ b/public/app/plugins/datasource/parca/package.json @@ -13,7 +13,7 @@ "monaco-editor": "0.34.1", "react": "18.2.0", "react-dom": "18.2.0", - "react-use": "17.5.1", + "react-use": "17.6.0", "rxjs": "7.8.1", "tslib": "2.7.0" }, diff --git a/public/app/plugins/datasource/tempo/package.json b/public/app/plugins/datasource/tempo/package.json index 657872288db..939b435a11f 100644 --- a/public/app/plugins/datasource/tempo/package.json +++ b/public/app/plugins/datasource/tempo/package.json @@ -30,7 +30,7 @@ "react": "18.2.0", "react-dom": "18.2.0", "react-select": "5.9.0", - "react-use": "17.5.1", + "react-use": "17.6.0", "rxjs": "7.8.1", "semver": "7.6.3", "stream-browserify": "3.0.0", diff --git a/public/app/plugins/datasource/zipkin/package.json b/public/app/plugins/datasource/zipkin/package.json index 3886ac17b12..9ea2f0b988c 100644 --- a/public/app/plugins/datasource/zipkin/package.json +++ b/public/app/plugins/datasource/zipkin/package.json @@ -15,7 +15,7 @@ "react": "18.2.0", "react-dom": "18.2.0", "react-select": "5.9.0", - "react-use": "17.5.1", + "react-use": "17.6.0", "rxjs": "7.8.1", "tslib": "2.7.0" }, diff --git a/yarn.lock b/yarn.lock index d1db1b07fca..bc40c7d2e35 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2831,7 +2831,7 @@ __metadata: react-dom: "npm:18.2.0" react-select: "npm:5.9.0" react-select-event: "npm:5.5.1" - react-use: "npm:17.5.1" + react-use: "npm:17.6.0" rxjs: "npm:7.8.1" ts-node: "npm:10.9.2" tslib: "npm:2.7.0" @@ -2901,7 +2901,7 @@ __metadata: prismjs: "npm:1.29.0" react: "npm:18.2.0" react-dom: "npm:18.2.0" - react-use: "npm:17.5.1" + react-use: "npm:17.6.0" rxjs: "npm:7.8.1" style-loader: "npm:4.0.0" ts-node: "npm:10.9.2" @@ -2941,7 +2941,7 @@ __metadata: react: "npm:18.2.0" react-dom: "npm:18.2.0" react-select: "npm:5.9.0" - react-use: "npm:17.5.1" + react-use: "npm:17.6.0" rxjs: "npm:7.8.1" ts-node: "npm:10.9.2" tslib: "npm:2.7.0" @@ -3078,7 +3078,7 @@ __metadata: monaco-editor: "npm:0.34.1" react: "npm:18.2.0" react-dom: "npm:18.2.0" - react-use: "npm:17.5.1" + react-use: "npm:17.6.0" rxjs: "npm:7.8.1" ts-node: "npm:10.9.2" tslib: "npm:2.7.0" @@ -3126,7 +3126,7 @@ __metadata: react-select: "npm:5.9.0" react-select-event: "npm:5.5.1" react-test-renderer: "npm:18.2.0" - react-use: "npm:17.5.1" + react-use: "npm:17.6.0" rxjs: "npm:7.8.1" ts-node: "npm:10.9.2" tslib: "npm:2.7.0" @@ -3182,7 +3182,7 @@ __metadata: react-dom: "npm:18.2.0" react-select: "npm:5.9.0" react-select-event: "npm:5.5.1" - react-use: "npm:17.5.1" + react-use: "npm:17.6.0" rxjs: "npm:7.8.1" semver: "npm:7.6.3" stream-browserify: "npm:3.0.0" @@ -3221,7 +3221,7 @@ __metadata: react: "npm:18.2.0" react-dom: "npm:18.2.0" react-select: "npm:5.9.0" - react-use: "npm:17.5.1" + react-use: "npm:17.6.0" rxjs: "npm:7.8.1" ts-node: "npm:10.9.2" tslib: "npm:2.7.0" @@ -3295,7 +3295,7 @@ __metadata: papaparse: "npm:5.4.1" react: "npm:18.2.0" react-dom: "npm:18.2.0" - react-use: "npm:17.5.1" + react-use: "npm:17.6.0" rimraf: "npm:6.0.1" rollup: "npm:^4.22.4" rollup-plugin-dts: "npm:^6.1.1" @@ -3492,7 +3492,7 @@ __metadata: jest-canvas-mock: "npm:2.5.2" lodash: "npm:4.17.21" react: "npm:18.2.0" - react-use: "npm:17.5.1" + react-use: "npm:17.6.0" react-virtualized-auto-sizer: "npm:1.0.24" rollup: "npm:^4.22.4" rollup-plugin-dts: "npm:^6.1.1" @@ -3571,7 +3571,7 @@ __metadata: jest: "npm:^29.6.4" react: "npm:18.2.0" react-select: "npm:5.9.0" - react-use: "npm:17.5.1" + react-use: "npm:17.6.0" rxjs: "npm:7.8.1" ts-jest: "npm:29.2.5" ts-node: "npm:10.9.2" @@ -3704,7 +3704,7 @@ __metadata: react-select: "npm:5.9.0" react-select-event: "npm:5.5.1" react-test-renderer: "npm:18.2.0" - react-use: "npm:17.5.1" + react-use: "npm:17.6.0" react-window: "npm:1.8.10" rollup: "npm:^4.22.4" rollup-plugin-dts: "npm:^6.1.1" @@ -3756,7 +3756,7 @@ __metadata: lodash: "npm:4.17.21" react: "npm:18.2.0" react-dom: "npm:18.2.0" - react-use: "npm:17.5.1" + react-use: "npm:17.6.0" rimraf: "npm:6.0.1" rollup: "npm:^4.22.4" rollup-plugin-dts: "npm:^6.1.1" @@ -3898,7 +3898,7 @@ __metadata: react: "npm:18.2.0" react-dom: "npm:18.2.0" react-select: "npm:5.9.0" - react-use: "npm:17.5.1" + react-use: "npm:17.6.0" react-virtualized-auto-sizer: "npm:1.0.24" rxjs: "npm:7.8.1" sql-formatter-plus: "npm:^1.3.6" @@ -4037,7 +4037,7 @@ __metadata: react-table: "npm:7.8.0" react-test-renderer: "npm:18.2.0" react-transition-group: "npm:4.4.5" - react-use: "npm:17.5.1" + react-use: "npm:17.6.0" react-window: "npm:1.8.10" rimraf: "npm:6.0.1" rollup: "npm:^4.22.4" @@ -17830,7 +17830,7 @@ __metadata: react-table: "npm:7.8.0" react-test-renderer: "npm:18.2.0" react-transition-group: "npm:4.4.5" - react-use: "npm:17.5.1" + react-use: "npm:17.6.0" react-virtual: "npm:2.10.4" react-virtualized-auto-sizer: "npm:1.0.24" react-window: "npm:1.8.10" @@ -25931,9 +25931,9 @@ __metadata: languageName: node linkType: hard -"react-use@npm:17.5.1, react-use@npm:^17.4.0, react-use@npm:^17.4.2, react-use@npm:^17.5.0": - version: 17.5.1 - resolution: "react-use@npm:17.5.1" +"react-use@npm:17.6.0, react-use@npm:^17.4.0, react-use@npm:^17.4.2, react-use@npm:^17.5.0": + version: 17.6.0 + resolution: "react-use@npm:17.6.0" dependencies: "@types/js-cookie": "npm:^2.2.6" "@xobotyi/scrollbar-width": "npm:^1.9.5" @@ -25952,7 +25952,7 @@ __metadata: peerDependencies: react: "*" react-dom: "*" - checksum: 10/2da403a9949dbd964b9b8e20dcd354db66b7f7d5ca1f42572fbcdb06bd49ee828c295be4912cb87abc163d1b54820bb8c5fa85314a16c4579d9e30bf9cbd5759 + checksum: 10/a817b74e82b481a39d3539bfe8d3b535c08d59d44a75ea91f65e56a7ccaedb0de185159e50b44ea4a635dda0c1c7159f07530e81a1d64b57130e0a715a107795 languageName: node linkType: hard From 6cd3a5458e5d276147df6ada79f0f9e0c471b99d Mon Sep 17 00:00:00 2001 From: Misi Date: Mon, 16 Dec 2024 17:03:39 +0100 Subject: [PATCH 38/38] Auth: Return error when retries have been exhausted for OAuth token refresh (#98034) Return error when retries for DB lock have been exhausted in oauth_token.go --- .../authn/authnimpl/sync/oauth_token_sync.go | 5 ++ pkg/services/oauthtoken/oauth_token.go | 3 +- pkg/services/oauthtoken/oauth_token_test.go | 55 ++++++++++++++++++- 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/pkg/services/authn/authnimpl/sync/oauth_token_sync.go b/pkg/services/authn/authnimpl/sync/oauth_token_sync.go index ec6f8e926b6..28fc69f1159 100644 --- a/pkg/services/authn/authnimpl/sync/oauth_token_sync.go +++ b/pkg/services/authn/authnimpl/sync/oauth_token_sync.go @@ -98,6 +98,11 @@ func (s *OAuthTokenSync) SyncOauthTokenHook(ctx context.Context, id *authn.Ident return nil, nil } + if errors.Is(refreshErr, oauthtoken.ErrRetriesExhausted) { + ctxLogger.Warn("Retries have been exhausted for locking the DB for OAuth token refresh", "id", id.ID, "error", refreshErr) + return nil, refreshErr + } + ctxLogger.Error("Failed to refresh OAuth access token", "id", id.ID, "error", refreshErr) // log the user out diff --git a/pkg/services/oauthtoken/oauth_token.go b/pkg/services/oauthtoken/oauth_token.go index cbb4cf67b97..fc9b64edc6f 100644 --- a/pkg/services/oauthtoken/oauth_token.go +++ b/pkg/services/oauthtoken/oauth_token.go @@ -35,6 +35,7 @@ var ( ErrNoRefreshTokenFound = errors.New("no refresh token found") ErrNotAnOAuthProvider = errors.New("not an oauth provider") ErrCouldntRefreshToken = errors.New("could not refresh token") + ErrRetriesExhausted = errors.New("retries exhausted") ) type Service struct { @@ -270,7 +271,7 @@ func (o *Service) TryTokenRefresh(ctx context.Context, usr identity.Requester, s if attempts < 5 { return nil } - return ErrCouldntRefreshToken + return ErrRetriesExhausted } var newToken *oauth2.Token diff --git a/pkg/services/oauthtoken/oauth_token_test.go b/pkg/services/oauthtoken/oauth_token_test.go index f20128526e2..36b5528a5c7 100644 --- a/pkg/services/oauthtoken/oauth_token_test.go +++ b/pkg/services/oauthtoken/oauth_token_test.go @@ -62,7 +62,11 @@ func (f *FakeAuthInfoStore) DeleteAuthInfo(ctx context.Context, cmd *login.Delet return f.ExpectedError } -func TestService_TryTokenRefresh(t *testing.T) { +func TestIntegration_TryTokenRefresh(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test") + } + unexpiredToken := &oauth2.Token{ AccessToken: "testaccess", RefreshToken: "testrefresh", @@ -86,6 +90,7 @@ func TestService_TryTokenRefresh(t *testing.T) { socialConnector *socialtest.MockSocialConnector socialService *socialtest.FakeSocialService + store db.DB service *Service } @@ -251,6 +256,30 @@ func TestService_TryTokenRefresh(t *testing.T) { }, expectedToken: unexpiredTokenWithIDToken, }, + { + desc: "should return ErrRetriesExhausted when lock cannot be acquired", + identity: &authn.Identity{ID: "1234", Type: claims.TypeUser, AuthenticatedBy: login.GenericOAuthModule}, + setup: func(env *environment) { + env.socialService.ExpectedAuthInfoProvider = &social.OAuthInfo{ + UseRefreshToken: true, + } + env.authInfoService.ExpectedUserAuth = &login.UserAuth{ + AuthModule: login.GenericOAuthModule, + AuthId: "subject", + UserId: 1234, + OAuthAccessToken: unexpiredTokenWithIDToken.AccessToken, + OAuthRefreshToken: unexpiredTokenWithIDToken.RefreshToken, + OAuthExpiry: unexpiredTokenWithIDToken.Expiry, + OAuthTokenType: unexpiredTokenWithIDToken.TokenType, + OAuthIdToken: EXPIRED_ID_TOKEN, + } + _ = env.store.WithDbSession(context.Background(), func(sess *db.Session) error { + _, err := sess.Exec(`INSERT INTO server_lock (operation_uid, last_execution, version) VALUES (?, ?, ?)`, "oauth-refresh-token-1234", time.Now().Add(2*time.Second).Unix(), 0) + return err + }) + }, + expectedErr: ErrRetriesExhausted, + }, } for _, tt := range tests { t.Run(tt.desc, func(t *testing.T) { @@ -265,6 +294,7 @@ func TestService_TryTokenRefresh(t *testing.T) { socialService: &socialtest.FakeSocialService{ ExpectedConnector: socialConnector, }, + store: store, } if tt.setup != nil { @@ -308,7 +338,11 @@ func TestService_TryTokenRefresh(t *testing.T) { } } -func TestService_TryTokenRefresh_WithExternalSessions(t *testing.T) { +func TestIntegration_TryTokenRefresh_WithExternalSessions(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test") + } + unexpiredToken := &oauth2.Token{ AccessToken: "testaccess", RefreshToken: "testrefresh", @@ -338,6 +372,7 @@ func TestService_TryTokenRefresh_WithExternalSessions(t *testing.T) { socialConnector *socialtest.MockSocialConnector socialService *socialtest.FakeSocialService + store db.DB service *Service } @@ -509,6 +544,21 @@ func TestService_TryTokenRefresh_WithExternalSessions(t *testing.T) { }, expectedToken: unexpiredTokenWithIDToken, }, + { + desc: "should return ErrRetriesExhausted when lock cannot be acquired", + identity: &authn.Identity{ID: "1234", Type: claims.TypeUser, AuthenticatedBy: login.GenericOAuthModule}, + setup: func(env *environment) { + env.socialService.ExpectedAuthInfoProvider = &social.OAuthInfo{ + UseRefreshToken: true, + } + + _ = env.store.WithDbSession(context.Background(), func(sess *db.Session) error { + _, err := sess.Exec(`INSERT INTO server_lock (operation_uid, last_execution, version) VALUES (?, ?, ?)`, "oauth-refresh-token-1234-1", time.Now().Add(2*time.Second).Unix(), 0) + return err + }) + }, + expectedErr: ErrRetriesExhausted, + }, } for _, tt := range tests { t.Run(tt.desc, func(t *testing.T) { @@ -523,6 +573,7 @@ func TestService_TryTokenRefresh_WithExternalSessions(t *testing.T) { socialService: &socialtest.FakeSocialService{ ExpectedConnector: socialConnector, }, + store: store, } if tt.setup != nil {