From 743991e30212f8afb26ca808b5f89236d0d6350c Mon Sep 17 00:00:00 2001 From: Oscar Kilhed Date: Thu, 27 Feb 2025 12:02:00 +0100 Subject: [PATCH 01/74] Chore: Bump scenes to v6.1.3 (#101370) * Bump scenes * Fix profile name --- package.json | 4 ++-- .../pages/DashboardScenePageStateManager.ts | 2 +- yarn.lock | 22 +++++++++---------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index 012ee9da149..9e5f4588c92 100644 --- a/package.json +++ b/package.json @@ -276,8 +276,8 @@ "@grafana/prometheus": "workspace:*", "@grafana/runtime": "workspace:*", "@grafana/saga-icons": "workspace:*", - "@grafana/scenes": "6.0.2", - "@grafana/scenes-react": "6.0.2", + "@grafana/scenes": "6.1.3", + "@grafana/scenes-react": "6.1.3", "@grafana/schema": "workspace:*", "@grafana/sql": "workspace:*", "@grafana/ui": "workspace:*", diff --git a/public/app/features/dashboard-scene/pages/DashboardScenePageStateManager.ts b/public/app/features/dashboard-scene/pages/DashboardScenePageStateManager.ts index b9f37706bad..63da7075646 100644 --- a/public/app/features/dashboard-scene/pages/DashboardScenePageStateManager.ts +++ b/public/app/features/dashboard-scene/pages/DashboardScenePageStateManager.ts @@ -151,7 +151,7 @@ abstract class DashboardScenePageStateManagerBase const queryController = sceneGraph.getQueryController(dashboard); trackDashboardSceneLoaded(dashboard, measure?.duration); - queryController?.startProfile(dashboard); + queryController?.startProfile('DashboardScene'); if (options.route !== DashboardRoutes.New) { emitDashboardViewEvent({ diff --git a/yarn.lock b/yarn.lock index eb8360924ac..3d8020c64dd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3772,11 +3772,11 @@ __metadata: languageName: unknown linkType: soft -"@grafana/scenes-react@npm:6.0.2": - version: 6.0.2 - resolution: "@grafana/scenes-react@npm:6.0.2" +"@grafana/scenes-react@npm:6.1.3": + version: 6.1.3 + resolution: "@grafana/scenes-react@npm:6.1.3" dependencies: - "@grafana/scenes": "npm:6.0.2" + "@grafana/scenes": "npm:6.1.3" lru-cache: "npm:^10.2.2" react-use: "npm:^17.4.0" peerDependencies: @@ -3788,13 +3788,13 @@ __metadata: react: ^18.0.0 react-dom: ^18.0.0 react-router-dom: ^6.28.0 - checksum: 10/9744e01f2ff912229e43cedfa41d626ccdfd034f5b9718b57c593bc90edadade960f76baf1d8ad19eed03709c17c62397df1871b89acc635172aa14f6a20e096 + checksum: 10/51b023de3ad6c3c9c1d08b1e0f3f5f9d99c65bc3a0871e34cbfd1bc542b0e5b945d9075baacb1d07009a731fb3c94a59a5631361c30961c7fea59be127878d93 languageName: node linkType: hard -"@grafana/scenes@npm:6.0.2": - version: 6.0.2 - resolution: "@grafana/scenes@npm:6.0.2" +"@grafana/scenes@npm:6.1.3": + version: 6.1.3 + resolution: "@grafana/scenes@npm:6.1.3" dependencies: "@floating-ui/react": "npm:^0.26.16" "@leeoniya/ufuzzy": "npm:^1.0.16" @@ -3812,7 +3812,7 @@ __metadata: react: ^18.0.0 react-dom: ^18.0.0 react-router-dom: ^6.28.0 - checksum: 10/2584f296db6299ef0a09d51f5c267ebcf7e44bd17b4d6516e38d3220f8f1d7aebc63c5fc6523979c4ac4d3f555416ca573e85e03bd36eb33a11941a5b3497149 + checksum: 10/10db2094648bf1e308b2f3ca1725acf9a5ea5bfa7f1015f9da0765abc34f5c718ec410275f45f78e5428ecd3ff6285343e95c02841eeef39eef5be7c8875fe9f languageName: node linkType: hard @@ -18126,8 +18126,8 @@ __metadata: "@grafana/prometheus": "workspace:*" "@grafana/runtime": "workspace:*" "@grafana/saga-icons": "workspace:*" - "@grafana/scenes": "npm:6.0.2" - "@grafana/scenes-react": "npm:6.0.2" + "@grafana/scenes": "npm:6.1.3" + "@grafana/scenes-react": "npm:6.1.3" "@grafana/schema": "workspace:*" "@grafana/sql": "workspace:*" "@grafana/tsconfig": "npm:^2.0.0" From c6a78978c39df988121b0289b6e039e3872186b6 Mon Sep 17 00:00:00 2001 From: Karl Persson <23356117+kalleep@users.noreply.github.com> Date: Thu, 27 Feb 2025 12:03:03 +0100 Subject: [PATCH 02/74] ContextHandler: unexport cfg (#101396) --- pkg/services/contexthandler/contexthandler.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/services/contexthandler/contexthandler.go b/pkg/services/contexthandler/contexthandler.go index df738065715..ee01105e37c 100644 --- a/pkg/services/contexthandler/contexthandler.go +++ b/pkg/services/contexthandler/contexthandler.go @@ -29,7 +29,7 @@ import ( func ProvideService(cfg *setting.Cfg, authenticator authn.Authenticator, features featuremgmt.FeatureToggles, ) *ContextHandler { return &ContextHandler{ - Cfg: cfg, + cfg: cfg, authenticator: authenticator, features: features, } @@ -37,7 +37,7 @@ func ProvideService(cfg *setting.Cfg, authenticator authn.Authenticator, feature // ContextHandler is a middleware. type ContextHandler struct { - Cfg *setting.Cfg + cfg *setting.Cfg authenticator authn.Authenticator features featuremgmt.FeatureToggles } @@ -104,7 +104,7 @@ func (h *ContextHandler) Middleware(next http.Handler) http.Handler { // inject ReqContext in the context ctx = context.WithValue(ctx, reqContextKey{}, reqContext) // store list of possible auth header in context - ctx = WithAuthHTTPHeaders(ctx, h.Cfg) + ctx = WithAuthHTTPHeaders(ctx, h.cfg) // Set the context for the http.Request.Context // This modifies both r and reqContext.Req since they point to the same value *reqContext.Req = *reqContext.Req.WithContext(ctx) @@ -137,7 +137,7 @@ func (h *ContextHandler) Middleware(next http.Handler) http.Handler { attribute.Int64("userId", reqContext.UserID), )) - if h.Cfg.IDResponseHeaderEnabled && reqContext.SignedInUser != nil { + if h.cfg.IDResponseHeaderEnabled && reqContext.SignedInUser != nil { reqContext.Resp.Before(h.addIDHeaderEndOfRequestFunc(reqContext.SignedInUser)) } @@ -167,11 +167,11 @@ func (h *ContextHandler) addIDHeaderEndOfRequestFunc(ident identity.Requester) w return } - if _, ok := h.Cfg.IDResponseHeaderNamespaces[string(ident.GetIdentityType())]; !ok { + if _, ok := h.cfg.IDResponseHeaderNamespaces[string(ident.GetIdentityType())]; !ok { return } - headerName := fmt.Sprintf("%s-Identity-Id", h.Cfg.IDResponseHeaderPrefix) + headerName := fmt.Sprintf("%s-Identity-Id", h.cfg.IDResponseHeaderPrefix) w.Header().Add(headerName, ident.GetID()) } } From 2372508e9e736ab5fad6ce6905ac84d4e37f5233 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 27 Feb 2025 13:25:30 +0200 Subject: [PATCH 03/74] Update scenes to v6.1.4 (#101402) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 4 ++-- yarn.lock | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 9e5f4588c92..3eb2cbbeabf 100644 --- a/package.json +++ b/package.json @@ -276,8 +276,8 @@ "@grafana/prometheus": "workspace:*", "@grafana/runtime": "workspace:*", "@grafana/saga-icons": "workspace:*", - "@grafana/scenes": "6.1.3", - "@grafana/scenes-react": "6.1.3", + "@grafana/scenes": "6.1.4", + "@grafana/scenes-react": "6.1.4", "@grafana/schema": "workspace:*", "@grafana/sql": "workspace:*", "@grafana/ui": "workspace:*", diff --git a/yarn.lock b/yarn.lock index 3d8020c64dd..d5a786396d4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3772,11 +3772,11 @@ __metadata: languageName: unknown linkType: soft -"@grafana/scenes-react@npm:6.1.3": - version: 6.1.3 - resolution: "@grafana/scenes-react@npm:6.1.3" +"@grafana/scenes-react@npm:6.1.4": + version: 6.1.4 + resolution: "@grafana/scenes-react@npm:6.1.4" dependencies: - "@grafana/scenes": "npm:6.1.3" + "@grafana/scenes": "npm:6.1.4" lru-cache: "npm:^10.2.2" react-use: "npm:^17.4.0" peerDependencies: @@ -3788,13 +3788,13 @@ __metadata: react: ^18.0.0 react-dom: ^18.0.0 react-router-dom: ^6.28.0 - checksum: 10/51b023de3ad6c3c9c1d08b1e0f3f5f9d99c65bc3a0871e34cbfd1bc542b0e5b945d9075baacb1d07009a731fb3c94a59a5631361c30961c7fea59be127878d93 + checksum: 10/69a344f30937a80e25201c8ce1261f85c10663e68d70103c28603abbee2496c7855d999b2a212132f48af597f3f528de65bade66c05b02c719ca25f8f8c682bd languageName: node linkType: hard -"@grafana/scenes@npm:6.1.3": - version: 6.1.3 - resolution: "@grafana/scenes@npm:6.1.3" +"@grafana/scenes@npm:6.1.4": + version: 6.1.4 + resolution: "@grafana/scenes@npm:6.1.4" dependencies: "@floating-ui/react": "npm:^0.26.16" "@leeoniya/ufuzzy": "npm:^1.0.16" @@ -3812,7 +3812,7 @@ __metadata: react: ^18.0.0 react-dom: ^18.0.0 react-router-dom: ^6.28.0 - checksum: 10/10db2094648bf1e308b2f3ca1725acf9a5ea5bfa7f1015f9da0765abc34f5c718ec410275f45f78e5428ecd3ff6285343e95c02841eeef39eef5be7c8875fe9f + checksum: 10/708652236c3b4a5bb0e1cd84739bef530b06244e2798e754347eabd8ab040b24c7f39376fd7b93d1049da6c0ee40785294882cba0125ce8171d5627a71ae63db languageName: node linkType: hard @@ -18126,8 +18126,8 @@ __metadata: "@grafana/prometheus": "workspace:*" "@grafana/runtime": "workspace:*" "@grafana/saga-icons": "workspace:*" - "@grafana/scenes": "npm:6.1.3" - "@grafana/scenes-react": "npm:6.1.3" + "@grafana/scenes": "npm:6.1.4" + "@grafana/scenes-react": "npm:6.1.4" "@grafana/schema": "workspace:*" "@grafana/sql": "workspace:*" "@grafana/tsconfig": "npm:^2.0.0" From 77305325c26d228404865635655ccdba0b9dd734 Mon Sep 17 00:00:00 2001 From: Victor Marin <36818606+mdvictor@users.noreply.github.com> Date: Thu, 27 Feb 2025 13:33:32 +0200 Subject: [PATCH 04/74] [Scopes]: Pass formatted scope filters to adhoc (#101217) * pass formatted scope filters to adhoc * fix * fix * fix scenario where we have equals and not-equals filters with the same key * add canary packages for testing * WIP * refactor to pass all filter values * rename property * refactor * update canary scenes * update scenes version * fix tests * fix arg startProfile bug that arised with scenes update --- .betterer.results | 3 + packages/grafana-data/src/index.ts | 2 + packages/grafana-data/src/types/scopes.ts | 11 + .../scene/DashboardScopesFacade.ts | 31 +- .../scene/convertScopesToAdHocFilters.test.ts | 288 ++++++++++++++++++ .../scene/convertScopesToAdHocFilters.ts | 92 ++++++ 6 files changed, 426 insertions(+), 1 deletion(-) create mode 100644 public/app/features/dashboard-scene/scene/convertScopesToAdHocFilters.test.ts create mode 100644 public/app/features/dashboard-scene/scene/convertScopesToAdHocFilters.ts diff --git a/.betterer.results b/.betterer.results index b593c39ca68..552f1bfd1a5 100644 --- a/.betterer.results +++ b/.betterer.results @@ -285,6 +285,9 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"] ], + "packages/grafana-data/src/types/scopes.ts:5381": [ + [0, 0, 0, "Do not use any type assertions.", "0"] + ], "packages/grafana-data/src/types/select.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"] diff --git a/packages/grafana-data/src/index.ts b/packages/grafana-data/src/index.ts index ec84e8f0d7b..67c8483ed11 100644 --- a/packages/grafana-data/src/index.ts +++ b/packages/grafana-data/src/index.ts @@ -576,6 +576,8 @@ export { type ScopeNodeSpec, type ScopeNode, scopeFilterOperatorMap, + reverseScopeFilterOperatorMap, + isEqualityOrMultiOperator, } from './types/scopes'; export { PluginState, diff --git a/packages/grafana-data/src/types/scopes.ts b/packages/grafana-data/src/types/scopes.ts index 90579b72017..2f85a19237d 100644 --- a/packages/grafana-data/src/types/scopes.ts +++ b/packages/grafana-data/src/types/scopes.ts @@ -18,6 +18,12 @@ export interface ScopeDashboardBinding { } export type ScopeFilterOperator = 'equals' | 'not-equals' | 'regex-match' | 'regex-not-match' | 'one-of' | 'not-one-of'; +export type EqualityOrMultiOperator = Extract; + +export function isEqualityOrMultiOperator(value: string): value is EqualityOrMultiOperator { + const operators = new Set(['equals', 'not-equals', 'one-of', 'not-one-of']); + return operators.has(value); +} export const scopeFilterOperatorMap: Record = { '=': 'equals', @@ -28,6 +34,11 @@ export const scopeFilterOperatorMap: Record = { '!=|': 'not-one-of', }; +export const reverseScopeFilterOperatorMap: Record = Object.fromEntries( + Object.entries(scopeFilterOperatorMap).map(([symbol, operator]) => [operator, symbol]) + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions +) as Record; + export interface ScopeSpecFilter { key: string; value: string; diff --git a/public/app/features/dashboard-scene/scene/DashboardScopesFacade.ts b/public/app/features/dashboard-scene/scene/DashboardScopesFacade.ts index 93b81e735ce..ccde822ce13 100644 --- a/public/app/features/dashboard-scene/scene/DashboardScopesFacade.ts +++ b/public/app/features/dashboard-scene/scene/DashboardScopesFacade.ts @@ -1,6 +1,10 @@ -import { sceneGraph } from '@grafana/scenes'; +import { AdHocFiltersVariable, sceneGraph } from '@grafana/scenes'; import { ScopesFacade } from 'app/features/scopes'; +import { getDashboardSceneFor } from '../utils/utils'; + +import { convertScopesToAdHocFilters } from './convertScopesToAdHocFilters'; + export interface DashboardScopesFacadeState { reloadOnParamsChange?: boolean; uid?: string; @@ -13,7 +17,32 @@ export class DashboardScopesFacade extends ScopesFacade { if (!reloadOnParamsChange || !uid) { sceneGraph.getTimeRange(facade).onRefresh(); } + + // push filters as soon as they come + this.pushScopeFiltersToAdHocVariable(); }, }); + + this.addActivationHandler(() => { + // also try to push filters on activation, for + // when the dashboard is changed + this.pushScopeFiltersToAdHocVariable(); + }); + } + + private pushScopeFiltersToAdHocVariable() { + const dashboard = getDashboardSceneFor(this); + + const adhoc = dashboard.state.$variables?.state.variables.find((v) => v instanceof AdHocFiltersVariable); + + if (!adhoc) { + return; + } + + const filters = convertScopesToAdHocFilters(this.value); + + adhoc.setState({ + baseFilters: filters, + }); } } diff --git a/public/app/features/dashboard-scene/scene/convertScopesToAdHocFilters.test.ts b/public/app/features/dashboard-scene/scene/convertScopesToAdHocFilters.test.ts new file mode 100644 index 00000000000..c6b84a4d39f --- /dev/null +++ b/public/app/features/dashboard-scene/scene/convertScopesToAdHocFilters.test.ts @@ -0,0 +1,288 @@ +import { Scope, ScopeSpecFilter } from '@grafana/data'; +import { FilterOrigin } from '@grafana/scenes'; + +import { convertScopesToAdHocFilters } from './convertScopesToAdHocFilters'; + +describe('convertScopesToAdHocFilters', () => { + it('should return empty filters when no scopes are provided', () => { + let scopes = generateScopes([]); + + expect(scopes).toEqual([]); + expect(convertScopesToAdHocFilters(scopes)).toEqual([]); + + scopes = generateScopes([[], []]); + + expect(convertScopesToAdHocFilters(scopes)).toEqual([]); + }); + + it('should return filters formatted for adHoc from a single scope', () => { + let scopes = generateScopes([ + [ + { key: 'key1', value: 'value1', operator: 'equals' }, + { key: 'key2', value: 'value2', operator: 'not-equals' }, + { key: 'key3', value: 'value3', operator: 'regex-not-match' }, + ], + ]); + + expect(convertScopesToAdHocFilters(scopes)).toEqual([ + { key: 'key1', value: 'value1', operator: '=', origin: FilterOrigin.Scopes, values: ['value1'] }, + { key: 'key2', value: 'value2', operator: '!=', origin: FilterOrigin.Scopes, values: ['value2'] }, + { key: 'key3', value: 'value3', operator: '!~', origin: FilterOrigin.Scopes, values: ['value3'] }, + ]); + + scopes = generateScopes([[{ key: 'key3', value: 'value3', operator: 'regex-match' }]]); + + expect(convertScopesToAdHocFilters(scopes)).toEqual([ + { key: 'key3', value: 'value3', operator: '=~', origin: FilterOrigin.Scopes, values: ['value3'] }, + ]); + }); + + it('should return filters formatted for adHoc from multiple scopes with single values', () => { + let scopes = generateScopes([ + [{ key: 'key1', value: 'value1', operator: 'equals' }], + [{ key: 'key2', value: 'value2', operator: 'regex-match' }], + ]); + + expect(convertScopesToAdHocFilters(scopes)).toEqual([ + { key: 'key1', value: 'value1', operator: '=', origin: FilterOrigin.Scopes, values: ['value1'] }, + { key: 'key2', value: 'value2', operator: '=~', origin: FilterOrigin.Scopes, values: ['value2'] }, + ]); + }); + + it('should return filters formatted for adHoc from multiple scopes with multiple values', () => { + let scopes = generateScopes([ + [ + { key: 'key1', value: 'value1', operator: 'equals' }, + { key: 'key2', value: 'value2', operator: 'not-equals' }, + ], + [ + { key: 'key3', value: 'value3', operator: 'regex-match' }, + { key: 'key4', value: 'value4', operator: 'regex-match' }, + ], + ]); + + expect(convertScopesToAdHocFilters(scopes)).toEqual([ + { key: 'key1', value: 'value1', operator: '=', origin: FilterOrigin.Scopes, values: ['value1'] }, + { key: 'key2', value: 'value2', operator: '!=', origin: FilterOrigin.Scopes, values: ['value2'] }, + { key: 'key3', value: 'value3', operator: '=~', origin: FilterOrigin.Scopes, values: ['value3'] }, + { key: 'key4', value: 'value4', operator: '=~', origin: FilterOrigin.Scopes, values: ['value4'] }, + ]); + }); + + it('should return formatted filters and concat values of the same key, coming from different scopes, if operator supports multi-value', () => { + let scopes = generateScopes([ + [ + { key: 'key1', value: 'value1', operator: 'equals' }, + { key: 'key2', value: 'value2', operator: 'not-equals' }, + ], + [ + { key: 'key1', value: 'value3', operator: 'equals' }, + { key: 'key2', value: 'value4', operator: 'not-equals' }, + ], + [{ key: 'key1', value: 'value5', operator: 'equals' }], + ]); + + expect(convertScopesToAdHocFilters(scopes)).toEqual([ + { + key: 'key1', + value: 'value1', + operator: '=|', + origin: FilterOrigin.Scopes, + values: ['value1', 'value3', 'value5'], + }, + { key: 'key2', value: 'value2', operator: '!=|', origin: FilterOrigin.Scopes, values: ['value2', 'value4'] }, + ]); + }); + + it('should ignore the rest of the duplicate filters, if they are a combination of equals and not-equals', () => { + let scopes = generateScopes([ + [{ key: 'key1', value: 'value1', operator: 'equals' }], + [{ key: 'key1', value: 'value2', operator: 'not-equals' }], + [{ key: 'key1', value: 'value3', operator: 'equals' }], + ]); + + expect(convertScopesToAdHocFilters(scopes)).toEqual([ + { + key: 'key1', + value: 'value1', + operator: '=|', + origin: FilterOrigin.Scopes, + values: ['value1', 'value3'], + }, + { + key: 'key1', + value: 'value2', + operator: '!=', + origin: FilterOrigin.Scopes, + values: ['value2'], + }, + ]); + }); + + it('should return formatted filters and keep only the first filter of the same key if operator is not multi-value', () => { + let scopes = generateScopes([ + [ + { key: 'key1', value: 'value1', operator: 'regex-match' }, + { key: 'key2', value: 'value2', operator: 'not-equals' }, + ], + [ + { key: 'key1', value: 'value3', operator: 'regex-match' }, + { key: 'key2', value: 'value4', operator: 'not-equals' }, + ], + [{ key: 'key1', value: 'value5', operator: 'equals' }], + ]); + + expect(convertScopesToAdHocFilters(scopes)).toEqual([ + { + key: 'key1', + value: 'value1', + operator: '=~', + origin: FilterOrigin.Scopes, + values: ['value1'], + }, + { key: 'key2', value: 'value2', operator: '!=|', origin: FilterOrigin.Scopes, values: ['value2', 'value4'] }, + { + key: 'key1', + value: 'value3', + operator: '=~', + origin: FilterOrigin.Scopes, + values: ['value3'], + }, + { + key: 'key1', + value: 'value5', + operator: '=', + origin: FilterOrigin.Scopes, + values: ['value5'], + }, + ]); + + scopes = generateScopes([ + [{ key: 'key1', value: 'value1', operator: 'regex-match' }], + [{ key: 'key1', value: 'value5', operator: 'equals' }], + [{ key: 'key1', value: 'value3', operator: 'regex-match' }], + ]); + + expect(convertScopesToAdHocFilters(scopes)).toEqual([ + { + key: 'key1', + value: 'value1', + operator: '=~', + origin: FilterOrigin.Scopes, + values: ['value1'], + }, + { + key: 'key1', + value: 'value5', + operator: '=', + origin: FilterOrigin.Scopes, + values: ['value5'], + }, + { + key: 'key1', + value: 'value3', + operator: '=~', + origin: FilterOrigin.Scopes, + values: ['value3'], + }, + ]); + }); + + it('should return formatted filters and concat values that are multi-value and drop duplicates with non multi-value operator', () => { + let scopes = generateScopes([ + [{ key: 'key1', value: 'value1', operator: 'equals' }], + [{ key: 'key1', value: 'value2', operator: 'regex-match' }], + [{ key: 'key1', value: 'value3', operator: 'equals' }], + ]); + + expect(convertScopesToAdHocFilters(scopes)).toEqual([ + { + key: 'key1', + value: 'value1', + operator: '=|', + origin: FilterOrigin.Scopes, + values: ['value1', 'value3'], + }, + { + key: 'key1', + value: 'value2', + operator: '=~', + origin: FilterOrigin.Scopes, + values: ['value2'], + }, + ]); + + scopes = generateScopes([ + [ + { key: 'key1', value: 'value1', operator: 'equals' }, + { key: 'key2', value: 'value2', operator: 'equals' }, + ], + [ + { key: 'key1', value: 'value3', operator: 'equals' }, + { key: 'key2', value: 'value4', operator: 'equals' }, + ], + [ + { key: 'key1', value: 'value5', operator: 'regex-match' }, + { key: 'key2', value: 'value6', operator: 'equals' }, + ], + [ + { key: 'key1', value: 'value7', operator: 'equals' }, + { key: 'key2', value: 'value8', operator: 'regex-match' }, + ], + [ + { key: 'key1', value: 'value9', operator: 'equals' }, + { key: 'key2', value: 'value10', operator: 'equals' }, + ], + ]); + + expect(convertScopesToAdHocFilters(scopes)).toEqual([ + { + key: 'key1', + value: 'value1', + operator: '=|', + origin: FilterOrigin.Scopes, + values: ['value1', 'value3', 'value7', 'value9'], + }, + { + key: 'key2', + value: 'value2', + operator: '=|', + origin: FilterOrigin.Scopes, + values: ['value2', 'value4', 'value6', 'value10'], + }, + { + key: 'key1', + value: 'value5', + operator: '=~', + origin: FilterOrigin.Scopes, + values: ['value5'], + }, + { + key: 'key2', + value: 'value8', + operator: '=~', + origin: FilterOrigin.Scopes, + values: ['value8'], + }, + ]); + }); +}); + +function generateScopes(filtersSpec: ScopeSpecFilter[][]) { + const scopes: Scope[] = []; + + for (let i = 0; i < filtersSpec.length; i++) { + scopes.push({ + metadata: { name: `name-${i}` }, + spec: { + title: `scope-${i}`, + type: '', + description: 'desc', + category: '', + filters: filtersSpec[i], + }, + }); + } + + return scopes; +} diff --git a/public/app/features/dashboard-scene/scene/convertScopesToAdHocFilters.ts b/public/app/features/dashboard-scene/scene/convertScopesToAdHocFilters.ts new file mode 100644 index 00000000000..1066a8f7b15 --- /dev/null +++ b/public/app/features/dashboard-scene/scene/convertScopesToAdHocFilters.ts @@ -0,0 +1,92 @@ +import { + Scope, + ScopeSpecFilter, + isEqualityOrMultiOperator, + reverseScopeFilterOperatorMap, + scopeFilterOperatorMap, +} from '@grafana/data'; +import { AdHocFilterWithLabels, FilterOrigin } from '@grafana/scenes'; + +export function convertScopesToAdHocFilters(scopes: Scope[]): AdHocFilterWithLabels[] { + const formattedFilters: Map = new Map(); + // duplicated filters that could not be processed in any way are just appended to the list + const duplicatedFilters: AdHocFilterWithLabels[] = []; + const allFilters = scopes.flatMap((scope) => scope.spec.filters); + + for (const filter of allFilters) { + processFilter(formattedFilters, duplicatedFilters, filter); + } + + return [...formattedFilters.values(), ...duplicatedFilters]; +} + +function processFilter( + formattedFilters: Map, + duplicatedFilters: AdHocFilterWithLabels[], + filter: ScopeSpecFilter +) { + const existingFilter = formattedFilters.get(filter.key); + + if (existingFilter && canValueBeMerged(existingFilter.operator, filter.operator)) { + mergeFilterValues(existingFilter, filter); + } else if (!existingFilter) { + // Add filter to map either only if it is new. + // Otherwise it is an existing filter that cannot be converted to multi-value + // and thus will be moved to the duplicatedFilters list + formattedFilters.set(filter.key, { + key: filter.key, + operator: reverseScopeFilterOperatorMap[filter.operator], + value: filter.value, + values: filter.values ?? [filter.value], + origin: FilterOrigin.Scopes, + }); + } else { + duplicatedFilters.push({ + key: filter.key, + operator: reverseScopeFilterOperatorMap[filter.operator], + value: filter.value, + values: filter.values ?? [filter.value], + origin: FilterOrigin.Scopes, + }); + } +} + +function mergeFilterValues(adHocFilter: AdHocFilterWithLabels, filter: ScopeSpecFilter) { + const values = filter.values ?? [filter.value]; + + for (const value of values) { + if (!adHocFilter.values?.includes(value)) { + adHocFilter.values?.push(value); + } + } + + // If there's only one value, there's no need to update the + // operator to its multi-value equivalent + if (adHocFilter.values?.length === 1) { + return; + } + + // Otherwise update it to the equivalent multi-value operator + if (filter.operator === 'equals' && adHocFilter.operator === reverseScopeFilterOperatorMap['equals']) { + adHocFilter.operator = reverseScopeFilterOperatorMap['one-of']; + } else if (filter.operator === 'not-equals' && adHocFilter.operator === reverseScopeFilterOperatorMap['not-equals']) { + adHocFilter.operator = reverseScopeFilterOperatorMap['not-one-of']; + } +} + +function canValueBeMerged(adHocFilterOperator: string, filterOperator: string) { + const scopeConvertedOperator = scopeFilterOperatorMap[adHocFilterOperator]; + + if (!isEqualityOrMultiOperator(scopeConvertedOperator) || !isEqualityOrMultiOperator(filterOperator)) { + return false; + } + + if ( + (scopeConvertedOperator.includes('not') && !filterOperator.includes('not')) || + (!scopeConvertedOperator.includes('not') && filterOperator.includes('not')) + ) { + return false; + } + + return true; +} From d947433d19ed95a1a6ebb76123c113cbd1c7011f Mon Sep 17 00:00:00 2001 From: Alexander Akhmetov Date: Thu, 27 Feb 2025 13:04:47 +0100 Subject: [PATCH 05/74] Alerting: API to delete rule groups using mimirtool (#100687) * Alerting: API to delete rule groups using mimirtool --- .../ngalert/api/api_convert_prometheus.go | 46 ++- .../api/api_convert_prometheus_test.go | 288 +++++++++++++++++- pkg/services/ngalert/api/api_provisioning.go | 1 + pkg/services/ngalert/api/errors.go | 5 +- pkg/services/ngalert/api/tooling/api.json | 1 - .../ngalert/provisioning/alert_rules.go | 75 +++-- .../ngalert/provisioning/alert_rules_test.go | 250 ++++++++++++++- pkg/services/ngalert/store/deltas.go | 54 +++- pkg/services/ngalert/store/deltas_test.go | 89 +++++- pkg/services/ngalert/tests/fakes/rules.go | 18 ++ .../alerting/api_convert_prometheus_test.go | 111 ++++++- pkg/tests/api/alerting/testing.go | 16 + public/api-merged.json | 1 - public/openapi3.json | 1 - 14 files changed, 908 insertions(+), 48 deletions(-) diff --git a/pkg/services/ngalert/api/api_convert_prometheus.go b/pkg/services/ngalert/api/api_convert_prometheus.go index e9dec2d4481..5dca89080a5 100644 --- a/pkg/services/ngalert/api/api_convert_prometheus.go +++ b/pkg/services/ngalert/api/api_convert_prometheus.go @@ -103,12 +103,46 @@ func (srv *ConvertPrometheusSrv) RouteConvertPrometheusGetRules(c *contextmodel. // RouteConvertPrometheusDeleteNamespace deletes all rule groups that were imported from a Prometheus-compatible source // within a specified namespace. func (srv *ConvertPrometheusSrv) RouteConvertPrometheusDeleteNamespace(c *contextmodel.ReqContext, namespaceTitle string) response.Response { - return response.Error(501, "Not implemented", nil) + logger := srv.logger.FromContext(c.Req.Context()) + + logger.Debug("Looking up folder in the root by title", "folder_title", namespaceTitle) + namespace, err := srv.ruleStore.GetNamespaceInRootByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.GetOrgID(), c.SignedInUser) + if err != nil { + return namespaceErrorResponse(err) + } + logger.Info("Deleting all Prometheus-imported rule groups", "folder_uid", namespace.UID, "folder_title", namespaceTitle) + + filterOpts := &provisioning.FilterOptions{ + NamespaceUIDs: []string{namespace.UID}, + ImportedPrometheusRule: util.Pointer(true), + } + err = srv.alertRuleService.DeleteRuleGroups(c.Req.Context(), c.SignedInUser, models.ProvenanceConvertedPrometheus, filterOpts) + if err != nil { + logger.Error("Failed to delete rule groups", "folder_uid", namespace.UID, "error", err) + return errorToResponse(err) + } + + return successfulResponse() } // RouteConvertPrometheusDeleteRuleGroup deletes a specific rule group if it was imported from a Prometheus-compatible source. func (srv *ConvertPrometheusSrv) RouteConvertPrometheusDeleteRuleGroup(c *contextmodel.ReqContext, namespaceTitle string, group string) response.Response { - return response.Error(501, "Not implemented", nil) + logger := srv.logger.FromContext(c.Req.Context()) + + logger.Debug("Looking up folder in the root by title", "folder_title", namespaceTitle) + folder, err := srv.ruleStore.GetNamespaceInRootByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.GetOrgID(), c.SignedInUser) + if err != nil { + return namespaceErrorResponse(err) + } + logger.Info("Deleting Prometheus-imported rule group", "folder_uid", folder.UID, "folder_title", namespaceTitle, "group", group) + + err = srv.alertRuleService.DeleteRuleGroup(c.Req.Context(), c.SignedInUser, folder.UID, group, models.ProvenanceConvertedPrometheus) + if err != nil { + logger.Error("Failed to delete rule group", "folder_uid", folder.UID, "group", group, "error", err) + return errorToResponse(err) + } + + return successfulResponse() } // RouteConvertPrometheusGetNamespace returns the Grafana-managed alert rules for a specified namespace (folder). @@ -220,7 +254,7 @@ func (srv *ConvertPrometheusSrv) RouteConvertPrometheusPostRuleGroup(c *contextm return errorToResponse(err) } - return response.JSON(http.StatusAccepted, map[string]string{"status": "success"}) + return successfulResponse() } func (srv *ConvertPrometheusSrv) getOrCreateNamespace(c *contextmodel.ReqContext, title string, logger log.Logger) (*folder.Folder, response.Response) { @@ -363,3 +397,9 @@ func namespaceErrorResponse(err error) response.Response { return toNamespaceErrorResponse(err) } + +func successfulResponse() response.Response { + return response.JSON(http.StatusAccepted, apimodels.ConvertPrometheusResponse{ + Status: "success", + }) +} diff --git a/pkg/services/ngalert/api/api_convert_prometheus_test.go b/pkg/services/ngalert/api/api_convert_prometheus_test.go index 05f84347334..51b378d437c 100644 --- a/pkg/services/ngalert/api/api_convert_prometheus_test.go +++ b/pkg/services/ngalert/api/api_convert_prometheus_test.go @@ -2,6 +2,7 @@ package api import ( "context" + "fmt" "net/http" "net/http/httptest" "testing" @@ -77,6 +78,79 @@ func TestRouteConvertPrometheusPostRuleGroup(t *testing.T) { require.Equal(t, http.StatusAccepted, response.Status()) }) + t.Run("should replace an existing rule group", func(t *testing.T) { + provenanceStore := fakes.NewFakeProvisioningStore() + srv, _, ruleStore, folderService := createConvertPrometheusSrv(t, withProvenanceStore(provenanceStore)) + + // Create a folder in the root + fldr := randFolder() + fldr.ParentUID = "" + folderService.ExpectedFolder = fldr + folderService.ExpectedFolders = []*folder.Folder{fldr} + ruleStore.Folders[1] = append(ruleStore.Folders[1], fldr) + + // And a rule + rule := models.RuleGen. + With(models.RuleGen.WithNamespaceUID(fldr.UID)). + With(models.RuleGen.WithGroupName(simpleGroup.Name)). + With(models.RuleGen.WithOrgID(1)). + With(models.RuleGen.WithPrometheusOriginalRuleDefinition("123")). + GenerateRef() + ruleStore.PutRule(context.Background(), rule) + + rc := createRequestCtx() + response := srv.RouteConvertPrometheusPostRuleGroup(rc, fldr.Title, simpleGroup) + require.Equal(t, http.StatusAccepted, response.Status()) + + // Get the updated rule + remaining, err := ruleStore.ListAlertRules(context.Background(), &models.ListAlertRulesQuery{ + OrgID: 1, + }) + require.NoError(t, err) + require.Len(t, remaining, 1) + + require.Equal(t, simpleGroup.Name, remaining[0].RuleGroup) + require.Equal(t, fmt.Sprintf("[%s] %s", simpleGroup.Name, simpleGroup.Rules[0].Alert), remaining[0].Title) + promRuleYAML, err := yaml.Marshal(simpleGroup.Rules[0]) + require.NoError(t, err) + require.Equal(t, string(promRuleYAML), remaining[0].PrometheusRuleDefinition()) + }) + + t.Run("should fail to replace a provisioned rule group", func(t *testing.T) { + provenanceStore := fakes.NewFakeProvisioningStore() + srv, _, ruleStore, folderService := createConvertPrometheusSrv(t, withProvenanceStore(provenanceStore)) + + // Create a folder in the root + fldr := randFolder() + fldr.ParentUID = "" + folderService.ExpectedFolder = fldr + folderService.ExpectedFolders = []*folder.Folder{fldr} + ruleStore.Folders[1] = append(ruleStore.Folders[1], fldr) + + rule := models.RuleGen. + With(models.RuleGen.WithNamespaceUID(fldr.UID)). + With(models.RuleGen.WithGroupName(simpleGroup.Name)). + With(models.RuleGen.WithOrgID(1)). + With(models.RuleGen.WithPrometheusOriginalRuleDefinition("123")). + GenerateRef() + ruleStore.PutRule(context.Background(), rule) + // mark the rule as provisioned + err := provenanceStore.SetProvenance(context.Background(), rule, 1, models.ProvenanceAPI) + require.NoError(t, err) + + rc := createRequestCtx() + response := srv.RouteConvertPrometheusPostRuleGroup(rc, fldr.Title, simpleGroup) + require.Equal(t, http.StatusConflict, response.Status()) + + // Verify the rule is still present + remaining, err := ruleStore.GetAlertRuleByUID(context.Background(), &models.GetAlertRuleByUIDQuery{ + UID: rule.UID, + OrgID: rule.OrgID, + }) + require.NoError(t, err) + require.NotNil(t, remaining) + }) + t.Run("with valid pause header values should return 202", func(t *testing.T) { testCases := []struct { name string @@ -420,9 +494,219 @@ func TestRouteConvertPrometheusGetRules(t *testing.T) { }) } -func createConvertPrometheusSrv(t *testing.T) (*ConvertPrometheusSrv, datasources.CacheService, *fakes.RuleStore, *foldertest.FakeService) { +func TestRouteConvertPrometheusDeleteNamespace(t *testing.T) { + t.Run("for non-existent folder should return 404", func(t *testing.T) { + srv, _, _, _ := createConvertPrometheusSrv(t) + rc := createRequestCtx() + + response := srv.RouteConvertPrometheusDeleteNamespace(rc, "non-existent") + require.Equal(t, http.StatusNotFound, response.Status()) + }) + + t.Run("valid request should delete rules", func(t *testing.T) { + initNamespace := func(promDefinition string, opts ...convertPrometheusSrvOptionsFunc) (*ConvertPrometheusSrv, *fakes.RuleStore, *folder.Folder, *models.AlertRule) { + srv, _, ruleStore, folderService := createConvertPrometheusSrv(t, opts...) + + // Create a folder in the root + fldr := randFolder() + fldr.ParentUID = "" + folderService.ExpectedFolder = fldr + folderService.ExpectedFolders = []*folder.Folder{fldr} + ruleStore.Folders[1] = append(ruleStore.Folders[1], fldr) + + rule := models.RuleGen. + With(models.RuleGen.WithNamespaceUID(fldr.UID)). + With(models.RuleGen.WithOrgID(1)). + With(models.RuleGen.WithPrometheusOriginalRuleDefinition(promDefinition)). + GenerateRef() + ruleStore.PutRule(context.Background(), rule) + + return srv, ruleStore, fldr, rule + } + + t.Run("valid request should delete rules", func(t *testing.T) { + srv, ruleStore, fldr, rule := initNamespace("prometheus definition") + + // Create another rule group in a different namespace that should not be deleted + otherGroupName := "other-group" + otherRule := models.RuleGen. + With(models.RuleGen.WithOrgID(1)). + With(models.RuleGen.WithGroupName(otherGroupName)). + With(models.RuleGen.WithPrometheusOriginalRuleDefinition("other prometheus definition")). + GenerateRef() + ruleStore.PutRule(context.Background(), otherRule) + + rc := createRequestCtx() + + response := srv.RouteConvertPrometheusDeleteNamespace(rc, fldr.Title) + require.Equal(t, http.StatusAccepted, response.Status()) + + // Verify the rule in the specified group was deleted + remaining, err := ruleStore.GetAlertRuleByUID(context.Background(), &models.GetAlertRuleByUIDQuery{ + UID: rule.UID, + OrgID: rule.OrgID, + }) + require.Error(t, err) + require.Nil(t, remaining) + + // Verify the rule in the other group still exists + remainingOther, err := ruleStore.GetAlertRuleByUID(context.Background(), &models.GetAlertRuleByUIDQuery{ + UID: otherRule.UID, + OrgID: otherRule.OrgID, + }) + require.NoError(t, err) + require.NotNil(t, remainingOther) + }) + + t.Run("fails to delete rules when they are provisioned", func(t *testing.T) { + provenanceStore := fakes.NewFakeProvisioningStore() + srv, ruleStore, fldr, rule := initNamespace("", withProvenanceStore(provenanceStore)) + rc := createRequestCtx() + + // Create a provisioned rule + rule2 := models.RuleGen. + With(models.RuleGen.WithNamespaceUID(fldr.UID)). + With(models.RuleGen.WithOrgID(1)). + With(models.RuleGen.WithPrometheusOriginalRuleDefinition("prometheus definition")). + GenerateRef() + ruleStore.PutRule(context.Background(), rule2) + err := provenanceStore.SetProvenance(context.Background(), rule2, 1, models.ProvenanceAPI) + require.NoError(t, err) + + response := srv.RouteConvertPrometheusDeleteNamespace(rc, fldr.Title) + require.Equal(t, http.StatusConflict, response.Status()) + + // Verify the rule is still present + remaining, err := ruleStore.GetAlertRuleByUID(context.Background(), &models.GetAlertRuleByUIDQuery{ + UID: rule.UID, + OrgID: rule.OrgID, + }) + require.NoError(t, err) + require.NotNil(t, remaining) + }) + }) +} + +func TestRouteConvertPrometheusDeleteRuleGroup(t *testing.T) { + t.Run("for non-existent folder should return 404", func(t *testing.T) { + srv, _, _, _ := createConvertPrometheusSrv(t) + rc := createRequestCtx() + + response := srv.RouteConvertPrometheusDeleteRuleGroup(rc, "non-existent", "test-group") + require.Equal(t, http.StatusNotFound, response.Status()) + }) + + const groupName = "test-group" + + t.Run("valid request should delete rules", func(t *testing.T) { + initGroup := func(promDefinition string, groupName string, opts ...convertPrometheusSrvOptionsFunc) (*ConvertPrometheusSrv, *fakes.RuleStore, *folder.Folder, *models.AlertRule) { + srv, _, ruleStore, folderService := createConvertPrometheusSrv(t, opts...) + + // Create a folder in the root + fldr := randFolder() + fldr.ParentUID = "" + folderService.ExpectedFolder = fldr + folderService.ExpectedFolders = []*folder.Folder{fldr} + ruleStore.Folders[1] = append(ruleStore.Folders[1], fldr) + + rule := models.RuleGen. + With(models.RuleGen.WithNamespaceUID(fldr.UID)). + With(models.RuleGen.WithOrgID(1)). + With(models.RuleGen.WithGroupName(groupName)). + With(models.RuleGen.WithPrometheusOriginalRuleDefinition(promDefinition)). + GenerateRef() + ruleStore.PutRule(context.Background(), rule) + + return srv, ruleStore, fldr, rule + } + + t.Run("valid request should delete rules", func(t *testing.T) { + srv, ruleStore, fldr, rule := initGroup("prometheus definition", groupName) + rc := createRequestCtx() + + // Create another rule in a different group that should not be deleted + otherGroupName := "other-group" + otherRule := models.RuleGen. + With(models.RuleGen.WithNamespaceUID(fldr.UID)). + With(models.RuleGen.WithOrgID(1)). + With(models.RuleGen.WithGroupName(otherGroupName)). + With(models.RuleGen.WithPrometheusOriginalRuleDefinition("other prometheus definition")). + GenerateRef() + ruleStore.PutRule(context.Background(), otherRule) + + response := srv.RouteConvertPrometheusDeleteRuleGroup(rc, fldr.Title, groupName) + require.Equal(t, http.StatusAccepted, response.Status()) + + // Verify the rule was deleted + remaining, err := ruleStore.GetAlertRuleByUID(context.Background(), &models.GetAlertRuleByUIDQuery{ + UID: rule.UID, + OrgID: rule.OrgID, + }) + require.Error(t, err) + require.Nil(t, remaining) + + // Verify the otherRule from the "other-group" is still present + otherRuleRefreshed, err := ruleStore.GetAlertRuleByUID(context.Background(), &models.GetAlertRuleByUIDQuery{ + UID: otherRule.UID, + OrgID: otherRule.OrgID, + }) + require.NoError(t, err) + require.NotNil(t, otherRuleRefreshed) + }) + + t.Run("fails to delete rules when they are provisioned", func(t *testing.T) { + provenanceStore := fakes.NewFakeProvisioningStore() + srv, ruleStore, fldr, rule := initGroup("", groupName, withProvenanceStore(provenanceStore)) + rc := createRequestCtx() + + // Create a provisioned rule + rule2 := models.RuleGen. + With(models.RuleGen.WithNamespaceUID(fldr.UID)). + With(models.RuleGen.WithOrgID(1)). + With(models.RuleGen.WithGroupName(groupName)). + With(models.RuleGen.WithPrometheusOriginalRuleDefinition("prometheus definition")). + GenerateRef() + ruleStore.PutRule(context.Background(), rule2) + err := provenanceStore.SetProvenance(context.Background(), rule2, 1, models.ProvenanceAPI) + require.NoError(t, err) + + response := srv.RouteConvertPrometheusDeleteRuleGroup(rc, fldr.Title, groupName) + require.Equal(t, http.StatusConflict, response.Status()) + + // Verify the rule is still present + remaining, err := ruleStore.GetAlertRuleByUID(context.Background(), &models.GetAlertRuleByUIDQuery{ + UID: rule.UID, + OrgID: rule.OrgID, + }) + require.NoError(t, err) + require.NotNil(t, remaining) + }) + }) +} + +type convertPrometheusSrvOptions struct { + provenanceStore provisioning.ProvisioningStore +} + +type convertPrometheusSrvOptionsFunc func(*convertPrometheusSrvOptions) + +func withProvenanceStore(store provisioning.ProvisioningStore) convertPrometheusSrvOptionsFunc { + return func(opts *convertPrometheusSrvOptions) { + opts.provenanceStore = store + } +} + +func createConvertPrometheusSrv(t *testing.T, opts ...convertPrometheusSrvOptionsFunc) (*ConvertPrometheusSrv, datasources.CacheService, *fakes.RuleStore, *foldertest.FakeService) { t.Helper() + options := convertPrometheusSrvOptions{ + provenanceStore: fakes.NewFakeProvisioningStore(), + } + + for _, opt := range opts { + opt(&options) + } + ruleStore := fakes.NewRuleStore(t) folder := randFolder() ruleStore.Folders[1] = append(ruleStore.Folders[1], folder) @@ -441,7 +725,7 @@ func createConvertPrometheusSrv(t *testing.T) (*ConvertPrometheusSrv, datasource alertRuleService := provisioning.NewAlertRuleService( ruleStore, - fakes.NewFakeProvisioningStore(), + options.provenanceStore, folderService, quotas, &provisioning.NopTransactionManager{}, diff --git a/pkg/services/ngalert/api/api_provisioning.go b/pkg/services/ngalert/api/api_provisioning.go index 6eb8f38a3c4..b5c7f5ab1c2 100644 --- a/pkg/services/ngalert/api/api_provisioning.go +++ b/pkg/services/ngalert/api/api_provisioning.go @@ -75,6 +75,7 @@ type AlertRuleService interface { GetRuleGroup(ctx context.Context, user identity.Requester, folder, group string) (alerting_models.AlertRuleGroup, error) ReplaceRuleGroup(ctx context.Context, user identity.Requester, group alerting_models.AlertRuleGroup, provenance alerting_models.Provenance) error DeleteRuleGroup(ctx context.Context, user identity.Requester, folder, group string, provenance alerting_models.Provenance) error + DeleteRuleGroups(ctx context.Context, user identity.Requester, provenance alerting_models.Provenance, opts *provisioning.FilterOptions) error GetAlertRuleWithFolderFullpath(ctx context.Context, u identity.Requester, ruleUID string) (provisioning.AlertRuleWithFolderFullpath, error) GetAlertRuleGroupWithFolderFullpath(ctx context.Context, u identity.Requester, folder, group string) (alerting_models.AlertRuleGroupWithFolderFullpath, error) GetAlertGroupsWithFolderFullpath(ctx context.Context, u identity.Requester, opts *provisioning.FilterOptions) ([]alerting_models.AlertRuleGroupWithFolderFullpath, error) diff --git a/pkg/services/ngalert/api/errors.go b/pkg/services/ngalert/api/errors.go index 0207d06cc43..a66db1e4fb2 100644 --- a/pkg/services/ngalert/api/errors.go +++ b/pkg/services/ngalert/api/errors.go @@ -3,6 +3,7 @@ package api import ( "errors" "fmt" + "net/http" "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/apimachinery/errutil" @@ -33,7 +34,7 @@ func errorToResponse(err error) response.Response { return response.Err(err) } if errors.Is(err, datasources.ErrDataSourceNotFound) { - return ErrResp(404, err, "") + return ErrResp(http.StatusNotFound, err, "") } if errors.Is(err, errUnexpectedDatasourceType) { return ErrResp(400, err, "") @@ -41,5 +42,5 @@ func errorToResponse(err error) response.Response { if errors.Is(err, errFolderAccess) { return toNamespaceErrorResponse(err) } - return ErrResp(500, err, "") + return ErrResp(http.StatusInternalServerError, err, "") } diff --git a/pkg/services/ngalert/api/tooling/api.json b/pkg/services/ngalert/api/tooling/api.json index 7fc64a8291f..0a2fb0af0d4 100644 --- a/pkg/services/ngalert/api/tooling/api.json +++ b/pkg/services/ngalert/api/tooling/api.json @@ -4932,7 +4932,6 @@ "type": "object" }, "gettableAlerts": { - "description": "GettableAlerts gettable alerts", "items": { "$ref": "#/definitions/gettableAlert", "type": "object" diff --git a/pkg/services/ngalert/provisioning/alert_rules.go b/pkg/services/ngalert/provisioning/alert_rules.go index 7e6f8387273..17b95ef314d 100644 --- a/pkg/services/ngalert/provisioning/alert_rules.go +++ b/pkg/services/ngalert/provisioning/alert_rules.go @@ -6,6 +6,7 @@ import ( "fmt" "time" + "github.com/grafana/grafana/pkg/apimachinery/errutil" "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/services/dashboards" @@ -29,6 +30,11 @@ type ruleAccessControlService interface { CanWriteAllRules(ctx context.Context, user identity.Requester) (bool, error) } +var errProvenanceMismatch = errutil.NewBase(errutil.StatusConflict, "alerting.provenanceMismatch").MustTemplate( + "cannot {{ .Public.Operation }} with provided provenance '{{ .Public.ProvidedProvenance }}', needs '{{ .Public.StoredProvenance }}'", + errutil.WithPublic("cannot {{ .Public.Operation }} with provided provenance '{{ .Public.ProvidedProvenance }}', needs '{{ .Public.StoredProvenance }}'"), +) + type NotificationSettingsValidatorProvider interface { Validator(ctx context.Context, orgID int64) (notifier.NotificationSettingsValidator, error) } @@ -445,27 +451,42 @@ func (service *AlertRuleService) ReplaceRuleGroup(ctx context.Context, user iden } func (service *AlertRuleService) DeleteRuleGroup(ctx context.Context, user identity.Requester, namespaceUID, group string, provenance models.Provenance) error { - delta, err := store.CalculateRuleGroupDelete(ctx, service.ruleStore, models.AlertRuleGroupKey{ - OrgID: user.GetOrgID(), - NamespaceUID: namespaceUID, - RuleGroup: group, + return service.DeleteRuleGroups(ctx, user, provenance, &FilterOptions{ + NamespaceUIDs: []string{namespaceUID}, + RuleGroups: []string{group}, }) +} + +// DeleteRuleGroups deletes alert rule groups by the specified filter options. +func (service *AlertRuleService) DeleteRuleGroups(ctx context.Context, user identity.Requester, provenance models.Provenance, filterOpts *FilterOptions) error { + q := models.ListAlertRulesQuery{} + q = filterOpts.apply(q) + q.OrgID = user.GetOrgID() + + deltas, err := store.CalculateRuleGroupsDelete(ctx, service.ruleStore, user.GetOrgID(), &q) if err != nil { return err } - // check if the current user has permissions to all rules and can bypass the regular authorization validation. - can, err := service.authz.CanWriteAllRules(ctx, user) - if err != nil { - return err - } - if !can { - if err := service.authz.AuthorizeRuleGroupWrite(ctx, user, delta); err != nil { - return err + // Perform all deletions in a transaction + return service.xact.InTransaction(ctx, func(ctx context.Context) error { + for _, delta := range deltas { + can, err := service.authz.CanWriteAllRules(ctx, user) + if err != nil { + return err + } + if !can { + if err := service.authz.AuthorizeRuleGroupWrite(ctx, user, delta); err != nil { + return err + } + } + err = service.persistDelta(ctx, user, delta, provenance) + if err != nil { + return err + } } - } - - return service.persistDelta(ctx, user, delta, provenance) + return nil + }) } func (service *AlertRuleService) calcDelta(ctx context.Context, user identity.Requester, group models.AlertRuleGroup) (*store.GroupDelta, error) { @@ -526,7 +547,13 @@ func (service *AlertRuleService) persistDelta(ctx context.Context, user identity return err } if canUpdate := validation.CanUpdateProvenanceInRuleGroup(storedProvenance, provenance); !canUpdate { - return fmt.Errorf("cannot delete with provided provenance '%s', needs '%s'", provenance, storedProvenance) + return errProvenanceMismatch.Build(errutil.TemplateData{ + Public: map[string]interface{}{ + "ProvidedProvenance": provenance, + "StoredProvenance": storedProvenance, + "Operation": "delete", + }, + }) } } if err := service.deleteRules(ctx, user.GetOrgID(), delta.Delete...); err != nil { @@ -543,7 +570,13 @@ func (service *AlertRuleService) persistDelta(ctx context.Context, user identity return err } if canUpdate := validation.CanUpdateProvenanceInRuleGroup(storedProvenance, provenance); !canUpdate { - return fmt.Errorf("cannot update with provided provenance '%s', needs '%s'", provenance, storedProvenance) + return errProvenanceMismatch.Build(errutil.TemplateData{ + Public: map[string]interface{}{ + "ProvidedProvenance": provenance, + "StoredProvenance": storedProvenance, + "Operation": "update", + }, + }) } updates = append(updates, models.UpdateRule{ Existing: update.Existing, @@ -689,7 +722,13 @@ func (service *AlertRuleService) DeleteAlertRule(ctx context.Context, user ident return err } if storedProvenance != provenance && storedProvenance != models.ProvenanceNone { - return fmt.Errorf("cannot delete with provided provenance '%s', needs '%s'", provenance, storedProvenance) + return errProvenanceMismatch.Build(errutil.TemplateData{ + Public: map[string]interface{}{ + "ProvidedProvenance": provenance, + "StoredProvenance": storedProvenance, + "Operation": "delete", + }, + }) } can, err := service.authz.CanWriteAllRules(ctx, user) diff --git a/pkg/services/ngalert/provisioning/alert_rules_test.go b/pkg/services/ngalert/provisioning/alert_rules_test.go index 3a10b26fd39..c269a92c664 100644 --- a/pkg/services/ngalert/provisioning/alert_rules_test.go +++ b/pkg/services/ngalert/provisioning/alert_rules_test.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "math/rand" + "slices" "strconv" "strings" "testing" @@ -1577,7 +1578,7 @@ func TestDeleteRuleGroup(t *testing.T) { assert.Equal(t, u, user) assert.Equal(t, groupKey, change.GroupKey) assert.Contains(t, change.AffectedGroups, groupKey) - assert.EqualValues(t, rules, change.AffectedGroups[groupKey]) + assert.ElementsMatch(t, rules, change.AffectedGroups[groupKey]) assert.Empty(t, change.Update) assert.Empty(t, change.New) assert.Len(t, change.Delete, len(rules)) @@ -1597,6 +1598,228 @@ func TestDeleteRuleGroup(t *testing.T) { }) } +func TestDeleteRuleGroups(t *testing.T) { + orgID1 := rand.Int63() + orgID2 := rand.Int63() + u := &user.SignedInUser{OrgID: orgID1} + + // Create groups across different orgs and namespaces + groupKey1 := models.AlertRuleGroupKey{ + OrgID: orgID1, + NamespaceUID: "namespace1", + RuleGroup: "group1", + } + groupKey2 := models.AlertRuleGroupKey{ + OrgID: orgID1, + NamespaceUID: "namespace2", + RuleGroup: "group2", + } + groupKey3 := models.AlertRuleGroupKey{ + OrgID: orgID1, + NamespaceUID: "namespace3", + RuleGroup: "group3", + } + groupKey4 := models.AlertRuleGroupKey{ + OrgID: orgID2, // Different org + NamespaceUID: "namespace1", + RuleGroup: "group1", + } + + gen := models.RuleGen + // Create rules for each group + rules1 := gen.With(gen.WithGroupKey(groupKey1)).GenerateManyRef(2) + rules2 := gen.With(gen.WithGroupKey(groupKey2)).GenerateManyRef(3) + rules3 := gen.With(gen.WithGroupKey(groupKey3)).GenerateManyRef(2) + rules4 := gen.With(gen.WithGroupKey(groupKey4)).GenerateManyRef(2) + + org1Rules := slices.Concat(rules1, rules2, rules3) + org2Rules := rules4 + + initServiceWithData := func(t *testing.T) (*AlertRuleService, *fakes.RuleStore, *fakes.FakeProvisioningStore, *fakeRuleAccessControlService) { + service, ruleStore, provenanceStore, ac := initService(t) + ruleStore.Rules = map[int64][]*models.AlertRule{ + orgID1: org1Rules, + orgID2: org2Rules, + } + // Set provenance for all rules + for _, rules := range []([]*models.AlertRule){org1Rules, org2Rules} { + for _, rule := range rules { + err := provenanceStore.SetProvenance(context.Background(), rule, rule.OrgID, models.ProvenanceAPI) + require.NoError(t, err) + } + } + return service, ruleStore, provenanceStore, ac + } + + getUIDs := func(rules []*models.AlertRule) []string { + uids := make([]string, 0, len(rules)) + for _, rule := range rules { + uids = append(uids, rule.UID) + } + return uids + } + + t.Run("when deleting specific groups", func(t *testing.T) { + filterOpts := &FilterOptions{ + NamespaceUIDs: []string{"namespace1"}, + RuleGroups: []string{"group1"}, + } + + t.Run("when user can write all rules", func(t *testing.T) { + service, ruleStore, _, ac := initServiceWithData(t) + ac.CanWriteAllRulesFunc = func(ctx context.Context, user identity.Requester) (bool, error) { + return true, nil + } + + err := service.DeleteRuleGroups(context.Background(), u, models.ProvenanceAPI, filterOpts) + require.NoError(t, err) + + require.Len(t, ac.Calls, 1) + assert.Equal(t, "CanWriteAllRules", ac.Calls[0].Method) + + // Verify only rules from group1 in org1 were deleted + deletes := getDeletedRules(t, ruleStore) + require.Len(t, deletes, 1) + require.ElementsMatch(t, getUIDs(rules1), deletes[0].uids) + }) + + t.Run("when user cannot write all rules", func(t *testing.T) { + t.Run("should not delete if not authorized", func(t *testing.T) { + service, ruleStore, _, ac := initServiceWithData(t) + ac.CanWriteAllRulesFunc = func(ctx context.Context, user identity.Requester) (bool, error) { + return false, nil + } + expectedErr := errors.New("test error") + ac.AuthorizeRuleChangesFunc = func(ctx context.Context, user identity.Requester, change *store.GroupDelta) error { + return expectedErr + } + + err := service.DeleteRuleGroups(context.Background(), u, models.ProvenanceAPI, filterOpts) + require.ErrorIs(t, err, expectedErr) + + require.Len(t, ac.Calls, 2) + assert.Equal(t, "CanWriteAllRules", ac.Calls[0].Method) + assert.Equal(t, "AuthorizeRuleGroupWrite", ac.Calls[1].Method) + + deletes := getDeletedRules(t, ruleStore) + require.Empty(t, deletes) + }) + + t.Run("should delete group1 when authorized", func(t *testing.T) { + service, ruleStore, _, ac := initServiceWithData(t) + ac.CanWriteAllRulesFunc = func(ctx context.Context, user identity.Requester) (bool, error) { + return false, nil + } + ac.AuthorizeRuleChangesFunc = func(ctx context.Context, user identity.Requester, change *store.GroupDelta) error { + assert.Equal(t, u, user) + assert.Equal(t, groupKey1, change.GroupKey) + assert.ElementsMatch(t, rules1, change.AffectedGroups[groupKey1]) + assert.Empty(t, change.Update) + assert.Empty(t, change.New) + assert.Len(t, change.Delete, len(rules1)) + return nil + } + + err := service.DeleteRuleGroups(context.Background(), u, models.ProvenanceAPI, filterOpts) + require.NoError(t, err) + + require.Len(t, ac.Calls, 2) + assert.Equal(t, "CanWriteAllRules", ac.Calls[0].Method) + assert.Equal(t, "AuthorizeRuleGroupWrite", ac.Calls[1].Method) + + deletes := getDeletedRules(t, ruleStore) + require.Len(t, deletes, 1) + require.ElementsMatch(t, getUIDs(rules1), deletes[0].uids) + }) + }) + }) + + t.Run("when deleting multiple groups from multiple namespaces", func(t *testing.T) { + filterOpts := &FilterOptions{ + NamespaceUIDs: []string{"namespace1", "namespace2"}, + RuleGroups: []string{"group1", "group2"}, + } + + t.Run("should delete all matching groups from correct org", func(t *testing.T) { + service, ruleStore, _, ac := initServiceWithData(t) + ac.CanWriteAllRulesFunc = func(ctx context.Context, user identity.Requester) (bool, error) { + return true, nil + } + + err := service.DeleteRuleGroups(context.Background(), u, models.ProvenanceAPI, filterOpts) + require.NoError(t, err) + + deletes := getDeletedRules(t, ruleStore) + require.Len(t, deletes, 2) + require.ElementsMatch( + t, + slices.Concat(getUIDs(rules1), getUIDs(rules2)), + slices.Concat(deletes[0].uids, deletes[1].uids), + ) + }) + }) + + t.Run("when filtering by imported Prometheus rules", func(t *testing.T) { + filterOpts := &FilterOptions{ + ImportedPrometheusRule: util.Pointer(true), + NamespaceUIDs: []string{"namespace1"}, + } + + t.Run("when the group is not imported", func(t *testing.T) { + filterOpts.RuleGroups = []string{groupKey1.RuleGroup} + service, _, _, ac := initServiceWithData(t) + ac.CanWriteAllRulesFunc = func(ctx context.Context, user identity.Requester) (bool, error) { + return true, nil + } + + err := service.DeleteRuleGroups(context.Background(), u, models.ProvenanceAPI, filterOpts) + require.ErrorIs(t, err, models.ErrAlertRuleGroupNotFound) + }) + + t.Run("when the group is imported", func(t *testing.T) { + importedGroup := models.AlertRuleGroupKey{ + OrgID: orgID1, + NamespaceUID: "namespace1", + RuleGroup: "newgroup", + } + importedRules := gen.With( + gen.WithGroupKey(importedGroup), + gen.WithPrometheusOriginalRuleDefinition("something"), + ).GenerateManyRef(2) + filterOpts.RuleGroups = []string{importedGroup.RuleGroup} + service, ruleStore, _, ac := initServiceWithData(t) + ruleStore.Rules[orgID1] = append(ruleStore.Rules[orgID1], importedRules...) + ac.CanWriteAllRulesFunc = func(ctx context.Context, user identity.Requester) (bool, error) { + return true, nil + } + + err := service.DeleteRuleGroups(context.Background(), u, models.ProvenanceAPI, filterOpts) + require.NoError(t, err) + deletes := getDeletedRules(t, ruleStore) + require.Len(t, deletes, 1) + require.ElementsMatch(t, getUIDs(importedRules), deletes[0].uids) + }) + }) + + t.Run("with no matching rule groups", func(t *testing.T) { + filterOpts := &FilterOptions{ + NamespaceUIDs: []string{"non-existent"}, + RuleGroups: []string{"non-existent"}, + } + + service, ruleStore, _, ac := initServiceWithData(t) + ac.CanWriteAllRulesFunc = func(ctx context.Context, user identity.Requester) (bool, error) { + return true, nil + } + + err := service.DeleteRuleGroups(context.Background(), u, models.ProvenanceAPI, filterOpts) + require.ErrorIs(t, err, models.ErrAlertRuleGroupNotFound) + + deletes := getDeletedRules(t, ruleStore) + require.Empty(t, deletes) + }) +} + func TestProvisiongWithFullpath(t *testing.T) { tracer := tracing.InitializeTracerForTest() inProcBus := bus.ProvideBus(tracer) @@ -1696,6 +1919,31 @@ func getDeleteQueries(ruleStore *fakes.RuleStore) []fakes.GenericRecordedQuery { return result } +type deleteRuleOperation struct { + orgID int64 + uids []string +} + +func getDeletedRules(t *testing.T, ruleStore *fakes.RuleStore) []deleteRuleOperation { + t.Helper() + + queries := getDeleteQueries(ruleStore) + operations := make([]deleteRuleOperation, 0, len(queries)) + for _, q := range queries { + orgID, ok := q.Params[0].(int64) + require.True(t, ok, "orgID parameter should be int64") + + uids, ok := q.Params[1].([]string) + require.True(t, ok, "uids parameter should be []string") + + operations = append(operations, deleteRuleOperation{ + orgID: orgID, + uids: uids, + }) + } + return operations +} + func createAlertRuleService(t *testing.T, folderService folder.Service) AlertRuleService { t.Helper() sqlStore := db.InitTestDB(t) diff --git a/pkg/services/ngalert/store/deltas.go b/pkg/services/ngalert/store/deltas.go index a7b00d27adf..d59980604f1 100644 --- a/pkg/services/ngalert/store/deltas.go +++ b/pkg/services/ngalert/store/deltas.go @@ -221,15 +221,13 @@ func CalculateRuleUpdate(ctx context.Context, ruleReader RuleReader, rule *model return calculateChanges(ctx, ruleReader, rule.GetGroupKey(), existingGroupRules, newGroup) } -// CalculateRuleGroupDelete calculates GroupDelta that reflects an operation of removing entire group -func CalculateRuleGroupDelete(ctx context.Context, ruleReader RuleReader, groupKey models.AlertRuleGroupKey) (*GroupDelta, error) { - // List all rules in the group. - q := models.ListAlertRulesQuery{ - OrgID: groupKey.OrgID, - NamespaceUIDs: []string{groupKey.NamespaceUID}, - RuleGroups: []string{groupKey.RuleGroup}, +// CalculateRuleGroupsDelete calculates []*GroupDelta that reflects an operation of removing multiple groups +func CalculateRuleGroupsDelete(ctx context.Context, ruleReader RuleReader, orgID int64, query *models.ListAlertRulesQuery) ([]*GroupDelta, error) { + if query == nil { + query = &models.ListAlertRulesQuery{} } - ruleList, err := ruleReader.ListAlertRules(ctx, &q) + query.OrgID = orgID + ruleList, err := ruleReader.ListAlertRules(ctx, query) if err != nil { return nil, err } @@ -237,14 +235,40 @@ func CalculateRuleGroupDelete(ctx context.Context, ruleReader RuleReader, groupK return nil, models.ErrAlertRuleGroupNotFound.Errorf("") } - delta := &GroupDelta{ - GroupKey: groupKey, - Delete: ruleList, - AffectedGroups: map[models.AlertRuleGroupKey]models.RulesGroup{ - groupKey: ruleList, - }, + groups := models.GroupByAlertRuleGroupKey(ruleList) + deltas := make([]*GroupDelta, 0, len(groups)) + for groupKey := range groups { + delta := &GroupDelta{ + GroupKey: groupKey, + Delete: groups[groupKey], + AffectedGroups: map[models.AlertRuleGroupKey]models.RulesGroup{ + groupKey: groups[groupKey], + }, + } + if err != nil { + return nil, err + } + deltas = append(deltas, delta) } - return delta, nil + + return deltas, nil +} + +// CalculateRuleGroupDelete calculates GroupDelta that reflects an operation of removing entire group +func CalculateRuleGroupDelete(ctx context.Context, ruleReader RuleReader, groupKey models.AlertRuleGroupKey) (*GroupDelta, error) { + q := &models.ListAlertRulesQuery{ + NamespaceUIDs: []string{groupKey.NamespaceUID}, + RuleGroups: []string{groupKey.RuleGroup}, + } + deltas, err := CalculateRuleGroupsDelete(ctx, ruleReader, groupKey.OrgID, q) + if err != nil { + return nil, err + } + if len(deltas) != 1 { + return nil, fmt.Errorf("expected to get a single group delta, got %d", len(deltas)) + } + + return deltas[0], nil } // CalculateRuleDelete calculates GroupDelta that reflects an operation of removing a rule from the group. diff --git a/pkg/services/ngalert/store/deltas_test.go b/pkg/services/ngalert/store/deltas_test.go index fde5a8e252f..fc27fbe9af2 100644 --- a/pkg/services/ngalert/store/deltas_test.go +++ b/pkg/services/ngalert/store/deltas_test.go @@ -428,6 +428,91 @@ func TestCalculateAutomaticChanges(t *testing.T) { }) } +func TestCalculateRuleGroupsDelete(t *testing.T) { + orgId := int64(rand.Int31()) + gen := models.RuleGen + + t.Run("returns ErrAlertRuleGroupNotFound when namespace has no rules", func(t *testing.T) { + fakeStore := fakes.NewRuleStore(t) + otherRules := gen.With(gen.WithOrgID(orgId), gen.WithNamespaceUID("ns-1")).GenerateManyRef(3) + fakeStore.Rules[orgId] = otherRules + + query := &models.ListAlertRulesQuery{ + NamespaceUIDs: []string{"ns-2"}, + } + deltas, err := CalculateRuleGroupsDelete(context.Background(), fakeStore, orgId, query) + require.ErrorIs(t, err, models.ErrAlertRuleGroupNotFound) + require.Nil(t, deltas) + }) + + t.Run("returns deltas for all affected groups in namespace", func(t *testing.T) { + fakeStore := fakes.NewRuleStore(t) + folder := randFolder() + + // Create rules in two groups in target namespace + group1Key := models.AlertRuleGroupKey{ + OrgID: orgId, + NamespaceUID: folder.UID, + RuleGroup: util.GenerateShortUID(), + } + group2Key := models.AlertRuleGroupKey{ + OrgID: orgId, + NamespaceUID: folder.UID, + RuleGroup: util.GenerateShortUID(), + } + + group1Rules := gen.With(gen.WithGroupKey(group1Key)).GenerateManyRef(3) + group2Rules := gen.With(gen.WithGroupKey(group2Key)).GenerateManyRef(2) + allNamespaceRules := append(group1Rules, group2Rules...) + + // Create rules in different namespace + otherRules := gen.With(gen.WithOrgID(orgId), gen.WithNamespaceUIDNotIn(folder.UID)).GenerateManyRef(3) + + fakeStore.Rules[orgId] = append(allNamespaceRules, otherRules...) + + query := &models.ListAlertRulesQuery{ + NamespaceUIDs: []string{folder.UID}, + } + + deltas, err := CalculateRuleGroupsDelete(context.Background(), fakeStore, orgId, query) + require.NoError(t, err) + + require.Len(t, deltas, 2, "expected deltas for two groups") + + // Verify each group's delta + for _, delta := range deltas { + require.True(t, delta.GroupKey == group1Key || delta.GroupKey == group2Key) + require.Empty(t, delta.Update) + require.Empty(t, delta.New) + + require.Contains(t, delta.AffectedGroups, delta.GroupKey) + if delta.GroupKey == group1Key { + require.ElementsMatch(t, group1Rules, delta.Delete) + require.ElementsMatch(t, group1Rules, delta.AffectedGroups[delta.GroupKey]) + } else { + require.ElementsMatch(t, group2Rules, delta.Delete) + require.ElementsMatch(t, group2Rules, delta.AffectedGroups[delta.GroupKey]) + } + } + }) + + t.Run("fails if store returns error", func(t *testing.T) { + fakeStore := fakes.NewRuleStore(t) + expectedErr := errors.New("store error") + fakeStore.Hook = func(cmd any) error { + switch cmd.(type) { + case models.ListAlertRulesQuery: + return expectedErr + } + return nil + } + + deltas, err := CalculateRuleGroupsDelete(context.Background(), fakeStore, orgId, nil) + require.ErrorIs(t, err, expectedErr) + require.Nil(t, deltas) + }) +} + func TestCalculateRuleGroupDelete(t *testing.T) { gen := models.RuleGen fakeStore := fakes.NewRuleStore(t) @@ -449,13 +534,13 @@ func TestCalculateRuleGroupDelete(t *testing.T) { require.NoError(t, err) assert.Equal(t, groupKey, delta.GroupKey) - assert.EqualValues(t, groupRules, delta.Delete) + assert.ElementsMatch(t, groupRules, delta.Delete) assert.Empty(t, delta.Update) assert.Empty(t, delta.New) assert.Len(t, delta.AffectedGroups, 1) - assert.Equal(t, models.RulesGroup(groupRules), delta.AffectedGroups[delta.GroupKey]) + assert.ElementsMatch(t, groupRules, delta.AffectedGroups[delta.GroupKey]) }) } diff --git a/pkg/services/ngalert/tests/fakes/rules.go b/pkg/services/ngalert/tests/fakes/rules.go index 2fa4714b19d..728ae6bd76f 100644 --- a/pkg/services/ngalert/tests/fakes/rules.go +++ b/pkg/services/ngalert/tests/fakes/rules.go @@ -214,6 +214,15 @@ func (f *RuleStore) ListAlertRules(_ context.Context, q *models.ListAlertRulesQu if len(q.RuleUIDs) > 0 && !slices.Contains(q.RuleUIDs, r.UID) { continue } + if q.ImportedPrometheusRule != nil { + hasOriginalRuleDefinition := r.PrometheusRuleDefinition() != "" + if *q.ImportedPrometheusRule && !hasOriginalRuleDefinition { + continue + } + if !*q.ImportedPrometheusRule && hasOriginalRuleDefinition { + continue + } + } ruleList = append(ruleList, r) } @@ -308,12 +317,21 @@ func (f *RuleStore) InsertAlertRules(_ context.Context, _ *models.UserUID, q []m defer f.mtx.Unlock() f.RecordedOps = append(f.RecordedOps, q) ids := make([]models.AlertRuleKeyWithId, 0, len(q)) + rulesPerOrg := map[int64][]models.AlertRule{} for _, rule := range q { ids = append(ids, models.AlertRuleKeyWithId{ AlertRuleKey: rule.GetKey(), ID: rand.Int63(), }) + rulesPerOrg[rule.OrgID] = append(rulesPerOrg[rule.OrgID], rule) } + + for orgID, rules := range rulesPerOrg { + for _, rule := range rules { + f.Rules[orgID] = append(f.Rules[orgID], &rule) + } + } + if err := f.Hook(q); err != nil { return ids, err } diff --git a/pkg/tests/api/alerting/api_convert_prometheus_test.go b/pkg/tests/api/alerting/api_convert_prometheus_test.go index 674d708250f..c92d5f8e428 100644 --- a/pkg/tests/api/alerting/api_convert_prometheus_test.go +++ b/pkg/tests/api/alerting/api_convert_prometheus_test.go @@ -1,6 +1,7 @@ package alerting import ( + "encoding/json" "net/http" "testing" "time" @@ -8,6 +9,7 @@ import ( prommodel "github.com/prometheus/common/model" "github.com/stretchr/testify/require" + "github.com/grafana/grafana/pkg/expr" "github.com/grafana/grafana/pkg/services/datasources" apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" "github.com/grafana/grafana/pkg/services/org" @@ -100,7 +102,7 @@ func TestIntegrationConvertPrometheusEndpoints(t *testing.T) { testinfra.SQLiteIntegrationTest(t) // Setup Grafana and its Database - dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ + dir, gpath := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, EnableUnifiedAlerting: true, DisableAnonymous: true, @@ -108,7 +110,7 @@ func TestIntegrationConvertPrometheusEndpoints(t *testing.T) { EnableFeatureToggles: []string{"alertingConversionAPI"}, }) - grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path) + grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, gpath) // Create users to make authenticated requests createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ @@ -169,6 +171,111 @@ func TestIntegrationConvertPrometheusEndpoints(t *testing.T) { _, status, raw := viewerClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup1, nil) requireStatusCode(t, http.StatusForbidden, status, raw) }) + + t.Run("delete one rule group", func(t *testing.T) { + _, status, body := apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup1, nil) + requireStatusCode(t, http.StatusAccepted, status, body) + _, status, body = apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup2, nil) + requireStatusCode(t, http.StatusAccepted, status, body) + _, status, body = apiClient.ConvertPrometheusPostRuleGroup(t, namespace2, ds.Body.Datasource.UID, promGroup3, nil) + requireStatusCode(t, http.StatusAccepted, status, body) + + apiClient.ConvertPrometheusDeleteRuleGroup(t, namespace1, promGroup1.Name) + + // Check that the promGroup2 and promGroup3 are still there + namespaces := apiClient.ConvertPrometheusGetAllRules(t) + expectedNamespaces := map[string][]apimodels.PrometheusRuleGroup{ + namespace1: {promGroup2}, + namespace2: {promGroup3}, + } + require.Equal(t, expectedNamespaces, namespaces) + + // Delete the second namespace + apiClient.ConvertPrometheusDeleteNamespace(t, namespace2) + + // Check that only the first namespace is left + namespaces = apiClient.ConvertPrometheusGetAllRules(t) + expectedNamespaces = map[string][]apimodels.PrometheusRuleGroup{ + namespace1: {promGroup2}, + } + require.Equal(t, expectedNamespaces, namespaces) + }) +} + +func TestIntegrationConvertPrometheusEndpoints_Conflict(t *testing.T) { + testinfra.SQLiteIntegrationTest(t) + + // Setup Grafana and its Database + dir, gpath := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ + DisableLegacyAlerting: true, + EnableUnifiedAlerting: true, + DisableAnonymous: true, + AppModeProduction: true, + EnableFeatureToggles: []string{"alertingConversionAPI"}, + }) + + grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, gpath) + + // Create users to make authenticated requests + createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ + DefaultOrgRole: string(org.RoleAdmin), + Password: "password", + Login: "admin", + }) + apiClient := newAlertingApiClient(grafanaListedAddr, "admin", "password") + + createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ + DefaultOrgRole: string(org.RoleViewer), + Password: "password", + Login: "viewer", + }) + + namespace1 := "test-namespace-1" + + ds := apiClient.CreateDatasource(t, datasources.DS_PROMETHEUS) + + t.Run("cannot overwrite a rule group with different provenance", func(t *testing.T) { + // Create a rule group using the provisioning API and then try to overwrite it + // using the Prometheus Conversion API. It should fail because the provenance + // we set for rules in these two APIs is different and we check that when updating. + provisionedRuleGroup := apimodels.AlertRuleGroup{ + Title: promGroup1.Name, + Interval: 60, + FolderUID: namespace1, + Rules: []apimodels.ProvisionedAlertRule{ + { + Title: "Rule1", + OrgID: 1, + RuleGroup: promGroup1.Name, + Condition: "A", + NoDataState: apimodels.Alerting, + ExecErrState: apimodels.AlertingErrState, + For: prommodel.Duration(time.Duration(60) * time.Second), + Data: []apimodels.AlertQuery{ + { + RefID: "A", + RelativeTimeRange: apimodels.RelativeTimeRange{ + From: apimodels.Duration(time.Duration(5) * time.Hour), + To: apimodels.Duration(time.Duration(3) * time.Hour), + }, + DatasourceUID: expr.DatasourceUID, + Model: json.RawMessage([]byte(`{"type":"math","expression":"2 + 3 \u003e 1"}`)), + }, + }, + }, + }, + } + + // Create the folder + apiClient.CreateFolder(t, namespace1, namespace1) + // Create rule in the root folder using another API + _, status, response := apiClient.CreateOrUpdateRuleGroupProvisioning(t, provisionedRuleGroup) + require.Equalf(t, http.StatusOK, status, response) + + // Should fail to post the group + _, status, body := apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup1, nil) + requireStatusCode(t, http.StatusConflict, status, body) + }) } func TestIntegrationConvertPrometheusEndpoints_CreatePausedRules(t *testing.T) { diff --git a/pkg/tests/api/alerting/testing.go b/pkg/tests/api/alerting/testing.go index 6594eaa4bb6..6290339dd24 100644 --- a/pkg/tests/api/alerting/testing.go +++ b/pkg/tests/api/alerting/testing.go @@ -1146,6 +1146,22 @@ func (a apiClient) ConvertPrometheusGetAllRules(t *testing.T) map[string][]apimo return result } +func (a apiClient) ConvertPrometheusDeleteRuleGroup(t *testing.T, namespaceTitle, groupName string) { + t.Helper() + req, err := http.NewRequest(http.MethodDelete, fmt.Sprintf("%s/api/convert/prometheus/config/v1/rules/%s/%s", a.url, namespaceTitle, groupName), nil) + require.NoError(t, err) + _, status, raw := sendRequestJSON[apimodels.ConvertPrometheusResponse](t, req, http.StatusAccepted) + requireStatusCode(t, http.StatusAccepted, status, raw) +} + +func (a apiClient) ConvertPrometheusDeleteNamespace(t *testing.T, namespaceTitle string) { + t.Helper() + req, err := http.NewRequest(http.MethodDelete, fmt.Sprintf("%s/api/convert/prometheus/config/v1/rules/%s", a.url, namespaceTitle), nil) + require.NoError(t, err) + _, status, raw := sendRequestJSON[apimodels.ConvertPrometheusResponse](t, req, http.StatusAccepted) + requireStatusCode(t, http.StatusAccepted, status, raw) +} + func sendRequestRaw(t *testing.T, req *http.Request) ([]byte, int, error) { t.Helper() client := &http.Client{} diff --git a/public/api-merged.json b/public/api-merged.json index 9ddc287f6f6..dc455b6a36f 100644 --- a/public/api-merged.json +++ b/public/api-merged.json @@ -22771,7 +22771,6 @@ } }, "gettableAlerts": { - "description": "GettableAlerts gettable alerts", "type": "array", "items": { "type": "object", diff --git a/public/openapi3.json b/public/openapi3.json index 8f339a39b59..fabc90f92cf 100644 --- a/public/openapi3.json +++ b/public/openapi3.json @@ -12838,7 +12838,6 @@ "type": "object" }, "gettableAlerts": { - "description": "GettableAlerts gettable alerts", "items": { "$ref": "#/components/schemas/gettableAlert" }, From 8a988d6b5a148d4374c5eb158bf295c563f53daf Mon Sep 17 00:00:00 2001 From: Ezequiel Victorero Date: Thu, 27 Feb 2025 09:14:37 -0300 Subject: [PATCH 06/74] Playlists: Add support for back button (#101374) --- .../app/features/playlist/PlaylistSrv.test.ts | 26 ++++++++++++- public/app/features/playlist/PlaylistSrv.ts | 38 +++++++++++++------ 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/public/app/features/playlist/PlaylistSrv.test.ts b/public/app/features/playlist/PlaylistSrv.test.ts index 687b5e39156..3620f3a1e02 100644 --- a/public/app/features/playlist/PlaylistSrv.test.ts +++ b/public/app/features/playlist/PlaylistSrv.test.ts @@ -1,4 +1,3 @@ -// @ts-ignore import { Store } from 'redux'; import configureMockStore from 'redux-mock-store'; @@ -139,4 +138,29 @@ describe('PlaylistSrv', () => { expect((srv as any).validPlaylistUrl).toBe('/url/to/bbb'); expect(srv.state.isPlaying).toBe(true); }); + + it('should replace playlist start page in history when starting playlist', async () => { + // Start at playlists page + locationService.push('/playlists'); + + // Navigate to playlist start page + locationService.push('/playlists/play/foo'); + + // Start the playlist + await srv.start('foo'); + + // Get history entries + const history = locationService.getHistory(); + const entries = (history as unknown as { entries: Location[] }).entries; + + // The current entry should be the first dashboard + expect(entries[entries.length - 1].pathname).toBe('/url/to/aaa'); + + // The previous entry should be the playlists page, not the start page + expect(entries[entries.length - 2].pathname).toBe('/playlists'); + + // Verify the start page (/playlists/play/foo) is not in history + const hasStartPage = entries.some((entry: { pathname: string }) => entry.pathname === '/playlists/play/foo'); + expect(hasStartPage).toBe(false); + }); }); diff --git a/public/app/features/playlist/PlaylistSrv.ts b/public/app/features/playlist/PlaylistSrv.ts index d11f817a369..99b839c857c 100644 --- a/public/app/features/playlist/PlaylistSrv.ts +++ b/public/app/features/playlist/PlaylistSrv.ts @@ -39,6 +39,28 @@ export class PlaylistSrv extends StateManagerBase { this.api = getPlaylistAPI(); } + private navigateToDashboard(replaceHistoryEntry = false) { + const url = this.urls[this.index]; + const queryParams = locationService.getSearchObject(); + const filteredParams = pickBy(queryParams, (value: unknown, key: string) => queryParamsToPreserve[key]); + const nextDashboardUrl = locationUtil.stripBaseFromUrl(url); + + this.index++; + this.validPlaylistUrl = nextDashboardUrl; + this.nextTimeoutId = setTimeout(() => this.next(), this.interval); + + const urlWithParams = nextDashboardUrl + '?' + urlUtil.toUrlParams(filteredParams); + + // When starting the playlist from the PlaylistStartPage component using the playlist URL, we want to replace the + // history entry to support the back button + // When starting the playlist from the playlist modal, we want to push a new history entry + if (replaceHistoryEntry) { + locationService.getHistory().replace(urlWithParams); + } else { + locationService.push(urlWithParams); + } + } + next() { clearTimeout(this.nextTimeoutId); @@ -55,16 +77,7 @@ export class PlaylistSrv extends StateManagerBase { this.index = 0; } - const url = this.urls[this.index]; - const queryParams = locationService.getSearchObject(); - const filteredParams = pickBy(queryParams, (value: unknown, key: string) => queryParamsToPreserve[key]); - const nextDashboardUrl = locationUtil.stripBaseFromUrl(url); - - this.index++; - this.validPlaylistUrl = nextDashboardUrl; - this.nextTimeoutId = setTimeout(() => this.next(), this.interval); - - locationService.push(nextDashboardUrl + '?' + urlUtil.toUrlParams(filteredParams)); + this.navigateToDashboard(); } prev() { @@ -115,7 +128,10 @@ export class PlaylistSrv extends StateManagerBase { this.urls = urls; this.setState({ isPlaying: true }); - this.next(); + + // Replace current history entry with first dashboard instead of pushing + // this is to avoid the back button to go back to the playlist start page which causes a redirection + this.navigateToDashboard(true); return; } From f79ce08e5090fa33e112a08bfcc1cc94b6d8cff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 27 Feb 2025 13:42:22 +0100 Subject: [PATCH 07/74] Dashboard: Outline using EditableElement interface (#101076) --- .../edit-pane/DashboardEditPane.tsx | 9 +- .../edit-pane/DashboardEditPaneSplitter.tsx | 60 +++---- .../edit-pane/DashboardEditableElement.tsx | 7 +- .../edit-pane/DashboardOutline.tsx | 159 ++++++++++++++++++ .../edit-pane/ElementEditPane.tsx | 3 +- .../edit-pane/ElementSelection.ts | 23 +-- .../MultiSelectedObjectsEditableElement.tsx | 8 +- .../MultiSelectedVizPanelsEditableElement.tsx | 8 +- .../edit-pane/VizPanelEditableElement.tsx | 11 +- .../dashboard-scene/edit-pane/shared.ts | 50 ++++++ .../SceneGridRowEditableElement.tsx | 149 ++++++++++++++++ .../scene/layout-rows/RowItem.tsx | 7 +- .../scene/layout-rows/RowItems.tsx | 7 +- .../scene/layout-tabs/TabItem.tsx | 7 +- .../scene/layout-tabs/TabItems.tsx | 7 +- .../scene/types/EditableDashboardElement.ts | 13 +- .../MultiSelectedEditableDashboardElement.ts | 8 +- public/locales/en-US/grafana.json | 25 ++- public/locales/pseudo-LOCALE/grafana.json | 25 ++- 19 files changed, 509 insertions(+), 77 deletions(-) create mode 100644 public/app/features/dashboard-scene/edit-pane/DashboardOutline.tsx create mode 100644 public/app/features/dashboard-scene/scene/layout-default/SceneGridRowEditableElement.tsx diff --git a/public/app/features/dashboard-scene/edit-pane/DashboardEditPane.tsx b/public/app/features/dashboard-scene/edit-pane/DashboardEditPane.tsx index fbaf5aa5260..51cd262b24a 100644 --- a/public/app/features/dashboard-scene/edit-pane/DashboardEditPane.tsx +++ b/public/app/features/dashboard-scene/edit-pane/DashboardEditPane.tsx @@ -18,6 +18,7 @@ import { isInCloneChain } from '../utils/clone'; import { getDashboardSceneFor } from '../utils/utils'; import { DashboardAddPane } from './DashboardAddPane'; +import { DashboardOutline } from './DashboardOutline'; import { ElementEditPane } from './ElementEditPane'; import { ElementSelection } from './ElementSelection'; import { useEditableElement } from './useEditableElement'; @@ -181,6 +182,8 @@ export function DashboardEditPaneRenderer({ editPane, isCollapsed, onToggleColla return null; } + const { typeId } = editableElement.getEditableElementInfo(); + if (isCollapsed) { return ( <> @@ -197,7 +200,7 @@ export function DashboardEditPaneRenderer({ editPane, isCollapsed, onToggleColla {openOverlay && ( - + )} @@ -225,8 +228,8 @@ export function DashboardEditPaneRenderer({ editPane, isCollapsed, onToggleColla
{tab === 'add' && } - {tab === 'configure' && } - {tab === 'outline' &&
} + {tab === 'configure' && } + {tab === 'outline' && }
); diff --git a/public/app/features/dashboard-scene/edit-pane/DashboardEditPaneSplitter.tsx b/public/app/features/dashboard-scene/edit-pane/DashboardEditPaneSplitter.tsx index b2fc279ccde..f51540115c5 100644 --- a/public/app/features/dashboard-scene/edit-pane/DashboardEditPaneSplitter.tsx +++ b/public/app/features/dashboard-scene/edit-pane/DashboardEditPaneSplitter.tsx @@ -73,38 +73,40 @@ export function DashboardEditPaneSplitter({ dashboard, isEditing, body, controls return (
-
{ - if (evt.shiftKey) { - return; - } + +
{ + if (evt.shiftKey) { + return; + } - editPane.clearSelection(); - }} - > - -
{controls}
-
-
- {body} + editPane.clearSelection(); + }} + > + +
{controls}
+
+
+ {body} +
-
- {isEditing && ( - <> -
-
- 0} - /> -
- - )} + {isEditing && ( + <> +
+
+ 0} + /> +
+ + )} +
); } diff --git a/public/app/features/dashboard-scene/edit-pane/DashboardEditableElement.tsx b/public/app/features/dashboard-scene/edit-pane/DashboardEditableElement.tsx index 4699e8c1c3f..77255075393 100644 --- a/public/app/features/dashboard-scene/edit-pane/DashboardEditableElement.tsx +++ b/public/app/features/dashboard-scene/edit-pane/DashboardEditableElement.tsx @@ -7,14 +7,17 @@ import { OptionsPaneItemDescriptor } from 'app/features/dashboard/components/Pan import { DashboardScene } from '../scene/DashboardScene'; import { useLayoutCategory } from '../scene/layouts-shared/DashboardLayoutSelector'; -import { EditableDashboardElement } from '../scene/types/EditableDashboardElement'; +import { EditableDashboardElement, EditableDashboardElementInfo } from '../scene/types/EditableDashboardElement'; export class DashboardEditableElement implements EditableDashboardElement { public readonly isEditableDashboardElement = true; - public readonly typeName = 'Dashboard'; public constructor(private dashboard: DashboardScene) {} + public getEditableElementInfo(): EditableDashboardElementInfo { + return { typeId: 'dashboard', icon: 'apps', name: t('dashboard.edit-pane.elements.dashboard', 'Dashboard') }; + } + public useEditPaneOptions(): OptionsPaneCategoryDescriptor[] { const dashboard = this.dashboard; diff --git a/public/app/features/dashboard-scene/edit-pane/DashboardOutline.tsx b/public/app/features/dashboard-scene/edit-pane/DashboardOutline.tsx new file mode 100644 index 00000000000..4f302a638fd --- /dev/null +++ b/public/app/features/dashboard-scene/edit-pane/DashboardOutline.tsx @@ -0,0 +1,159 @@ +import { css, cx } from '@emotion/css'; +import { useMemo, useState } from 'react'; + +import { GrafanaTheme2 } from '@grafana/data'; +import { SceneObject, VizPanel } from '@grafana/scenes'; +import { Box, Icon, IconButton, Stack, Text, useElementSelection, useStyles2 } from '@grafana/ui'; +import { t, Trans } from 'app/core/internationalization'; + +import { DashboardGridItem } from '../scene/layout-default/DashboardGridItem'; +import { isInCloneChain } from '../utils/clone'; +import { getDashboardSceneFor } from '../utils/utils'; + +import { DashboardEditPane } from './DashboardEditPane'; +import { getEditableElementFor, hasEditableElement } from './shared'; + +export interface Props { + editPane: DashboardEditPane; +} + +export function DashboardOutline({ editPane }: Props) { + const dashboard = getDashboardSceneFor(editPane); + + return ( + + + + ); +} + +function DashboardOutlineNode({ sceneObject, expandable }: { sceneObject: SceneObject; expandable: boolean }) { + const [isExpanded, setIsExpanded] = useState(true); + const { key } = sceneObject.useState(); + const styles = useStyles2(getStyles); + const { isSelected, onSelect } = useElementSelection(key); + const isCloned = useMemo(() => isInCloneChain(key!), [key]); + const editableElement = useMemo(() => getEditableElementFor(sceneObject)!, [sceneObject]); + + const children = collectEditableElementChildren(sceneObject); + const elementInfo = editableElement.getEditableElementInfo(); + + return ( + <> + + {expandable && ( + setIsExpanded(!isExpanded)} + aria-label={ + isExpanded + ? t('dashboard.outline.tree.item.collapse', 'Collapse item') + : t('dashboard.outline.tree.item.expand', 'Expand item') + } + /> + )} + + + {expandable && isExpanded && ( +
+ {children.length > 0 ? ( + children.map((child) => ( + + )) + ) : ( + + (empty) + + )} +
+ )} + + ); +} + +function getStyles(theme: GrafanaTheme2) { + return { + container: css({ + display: 'flex', + flexDirection: 'column', + gap: theme.spacing(1), + marginLeft: theme.spacing(1), + paddingLeft: theme.spacing(1.5), + borderLeft: `1px solid ${theme.colors.border.medium}`, + }), + nodeButton: css({ + boxShadow: 'none', + border: 'none', + background: 'transparent', + padding: theme.spacing(0.25, 1), + borderRadius: theme.shape.radius.default, + display: 'flex', + alignItems: 'center', + gap: theme.spacing(1), + overflow: 'hidden', + '&:hover': { + backgroundColor: theme.colors.action.hover, + }, + '> span': { + whiteSpace: 'nowrap', + overflow: 'hidden', + textOverflow: 'ellipsis', + }, + }), + nodeButtonSelected: css({ + color: theme.colors.primary.text, + }), + nodeButtonClone: css({ + color: theme.colors.text.secondary, + cursor: 'not-allowed', + }), + }; +} + +interface EditableElementConfig { + sceneObject: SceneObject; + expandable: boolean; +} + +function collectEditableElementChildren( + sceneObject: SceneObject, + children: EditableElementConfig[] = [] +): EditableElementConfig[] { + sceneObject.forEachChild((child) => { + if (child instanceof DashboardGridItem) { + // DashboardGridItem is a special case as it can contain repeated panels + // In this case, we want to show the repeated panels as separate items, otherwise show the body panel + if (child.state.repeatedPanels?.length) { + children.push(...child.state.repeatedPanels.map((panel) => ({ sceneObject: panel, expandable: false }))); + } else { + children.push({ sceneObject: child.state.body, expandable: false }); + } + } else if (child instanceof VizPanel) { + children.push({ sceneObject: child, expandable: false }); + } else if (hasEditableElement(child)) { + children.push({ sceneObject: child, expandable: true }); + } else { + collectEditableElementChildren(child, children); + } + }); + + return children; +} diff --git a/public/app/features/dashboard-scene/edit-pane/ElementEditPane.tsx b/public/app/features/dashboard-scene/edit-pane/ElementEditPane.tsx index 16adfe8004a..47cd84ade4b 100644 --- a/public/app/features/dashboard-scene/edit-pane/ElementEditPane.tsx +++ b/public/app/features/dashboard-scene/edit-pane/ElementEditPane.tsx @@ -14,13 +14,14 @@ export interface Props { export function ElementEditPane({ element }: Props) { const categories = element.useEditPaneOptions ? element.useEditPaneOptions() : []; const styles = useStyles2(getStyles); + const elementInfo = element.getEditableElementInfo(); return ( {element.renderActions && ( diff --git a/public/app/features/dashboard-scene/edit-pane/ElementSelection.ts b/public/app/features/dashboard-scene/edit-pane/ElementSelection.ts index cecd28020cf..2141781408d 100644 --- a/public/app/features/dashboard-scene/edit-pane/ElementSelection.ts +++ b/public/app/features/dashboard-scene/edit-pane/ElementSelection.ts @@ -1,15 +1,14 @@ import { SceneObject, SceneObjectRef, VizPanel } from '@grafana/scenes'; import { ElementSelectionContextItem } from '@grafana/ui'; -import { DashboardScene } from '../scene/DashboardScene'; import { isBulkActionElement } from '../scene/types/BulkActionElement'; import { EditableDashboardElement, isEditableDashboardElement } from '../scene/types/EditableDashboardElement'; import { MultiSelectedEditableDashboardElement } from '../scene/types/MultiSelectedEditableDashboardElement'; -import { DashboardEditableElement } from './DashboardEditableElement'; import { MultiSelectedObjectsEditableElement } from './MultiSelectedObjectsEditableElement'; import { MultiSelectedVizPanelsEditableElement } from './MultiSelectedVizPanelsEditableElement'; import { VizPanelEditableElement } from './VizPanelEditableElement'; +import { getEditableElementFor } from './shared'; export class ElementSelection { private selectedObjects?: Map>; @@ -121,24 +120,7 @@ export class ElementSelection { private createSingleSelectedElement(): EditableDashboardElement | undefined { const sceneObj = this.selectedObjects?.values().next().value?.resolve(); - - if (!sceneObj) { - return undefined; - } - - if (isEditableDashboardElement(sceneObj)) { - return sceneObj; - } - - if (sceneObj instanceof VizPanel) { - return new VizPanelEditableElement(sceneObj); - } - - if (sceneObj instanceof DashboardScene) { - return new DashboardEditableElement(sceneObj); - } - - return undefined; + return getEditableElementFor(sceneObj); } private createMultiSelectedElement(): MultiSelectedEditableDashboardElement | undefined { @@ -161,6 +143,7 @@ export class ElementSelection { } const bulkActionElements = []; + for (const sceneObject of sceneObjects) { if (sceneObject instanceof VizPanel) { const editableElement = new VizPanelEditableElement(sceneObject); diff --git a/public/app/features/dashboard-scene/edit-pane/MultiSelectedObjectsEditableElement.tsx b/public/app/features/dashboard-scene/edit-pane/MultiSelectedObjectsEditableElement.tsx index 3278deb3a17..a55b5f0d8c9 100644 --- a/public/app/features/dashboard-scene/edit-pane/MultiSelectedObjectsEditableElement.tsx +++ b/public/app/features/dashboard-scene/edit-pane/MultiSelectedObjectsEditableElement.tsx @@ -2,20 +2,24 @@ import { ReactNode } from 'react'; import { v4 as uuidv4 } from 'uuid'; import { Stack, Text, Button } from '@grafana/ui'; -import { Trans } from 'app/core/internationalization'; +import { t, Trans } from 'app/core/internationalization'; import { BulkActionElement } from '../scene/types/BulkActionElement'; +import { EditableDashboardElementInfo } from '../scene/types/EditableDashboardElement'; import { MultiSelectedEditableDashboardElement } from '../scene/types/MultiSelectedEditableDashboardElement'; export class MultiSelectedObjectsEditableElement implements MultiSelectedEditableDashboardElement { public readonly isMultiSelectedEditableDashboardElement = true; - public readonly typeName = 'Objects'; public readonly key: string; constructor(private _elements: BulkActionElement[]) { this.key = uuidv4(); } + public getEditableElementInfo(): EditableDashboardElementInfo { + return { name: t('dashboard.edit-pane.elements.objects', 'Objects'), typeId: 'objects', icon: 'folder' }; + } + public renderActions(): ReactNode { return ( diff --git a/public/app/features/dashboard-scene/edit-pane/MultiSelectedVizPanelsEditableElement.tsx b/public/app/features/dashboard-scene/edit-pane/MultiSelectedVizPanelsEditableElement.tsx index 259ae9d91cc..afa29772adc 100644 --- a/public/app/features/dashboard-scene/edit-pane/MultiSelectedVizPanelsEditableElement.tsx +++ b/public/app/features/dashboard-scene/edit-pane/MultiSelectedVizPanelsEditableElement.tsx @@ -3,20 +3,24 @@ import { v4 as uuidv4 } from 'uuid'; import { VizPanel } from '@grafana/scenes'; import { Button, Stack, Text } from '@grafana/ui'; -import { Trans } from 'app/core/internationalization'; +import { t, Trans } from 'app/core/internationalization'; +import { EditableDashboardElementInfo } from '../scene/types/EditableDashboardElement'; import { MultiSelectedEditableDashboardElement } from '../scene/types/MultiSelectedEditableDashboardElement'; import { dashboardSceneGraph } from '../utils/dashboardSceneGraph'; export class MultiSelectedVizPanelsEditableElement implements MultiSelectedEditableDashboardElement { public readonly isMultiSelectedEditableDashboardElement = true; - public readonly typeName = 'Panels'; public readonly key: string; constructor(private _panels: VizPanel[]) { this.key = uuidv4(); } + public getEditableElementInfo(): EditableDashboardElementInfo { + return { name: t('dashboard.edit-pane.elements.panels', 'Panels'), typeId: 'panels', icon: 'folder' }; + } + renderActions(): ReactNode { return ( diff --git a/public/app/features/dashboard-scene/edit-pane/VizPanelEditableElement.tsx b/public/app/features/dashboard-scene/edit-pane/VizPanelEditableElement.tsx index 4d97803b8db..c20c61113fa 100644 --- a/public/app/features/dashboard-scene/edit-pane/VizPanelEditableElement.tsx +++ b/public/app/features/dashboard-scene/edit-pane/VizPanelEditableElement.tsx @@ -14,15 +14,22 @@ import { } from '../panel-edit/getPanelFrameOptions'; import { BulkActionElement } from '../scene/types/BulkActionElement'; import { isDashboardLayoutItem } from '../scene/types/DashboardLayoutItem'; -import { EditableDashboardElement } from '../scene/types/EditableDashboardElement'; +import { EditableDashboardElement, EditableDashboardElementInfo } from '../scene/types/EditableDashboardElement'; import { dashboardSceneGraph } from '../utils/dashboardSceneGraph'; export class VizPanelEditableElement implements EditableDashboardElement, BulkActionElement { public readonly isEditableDashboardElement = true; - public readonly typeName = 'Panel'; public constructor(private panel: VizPanel) {} + public getEditableElementInfo(): EditableDashboardElementInfo { + return { + typeId: 'panel', + icon: 'chart-line', + name: sceneGraph.interpolate(this.panel, this.panel.state.title, undefined, 'text'), + }; + } + public useEditPaneOptions(): OptionsPaneCategoryDescriptor[] { const panel = this.panel; const layoutElement = panel.parent!; diff --git a/public/app/features/dashboard-scene/edit-pane/shared.ts b/public/app/features/dashboard-scene/edit-pane/shared.ts index 59ee48dde75..72c44d5dc2b 100644 --- a/public/app/features/dashboard-scene/edit-pane/shared.ts +++ b/public/app/features/dashboard-scene/edit-pane/shared.ts @@ -1,5 +1,55 @@ import { useSessionStorage } from 'react-use'; +import { SceneGridRow, SceneObject, VizPanel } from '@grafana/scenes'; + +import { DashboardScene } from '../scene/DashboardScene'; +import { SceneGridRowEditableElement } from '../scene/layout-default/SceneGridRowEditableElement'; +import { EditableDashboardElement, isEditableDashboardElement } from '../scene/types/EditableDashboardElement'; + +import { DashboardEditableElement } from './DashboardEditableElement'; +import { VizPanelEditableElement } from './VizPanelEditableElement'; + export function useEditPaneCollapsed() { return useSessionStorage('grafana.dashboards.edit-pane.isCollapsed', false); } + +export function getEditableElementFor(sceneObj: SceneObject | undefined): EditableDashboardElement | undefined { + if (!sceneObj) { + return undefined; + } + + if (isEditableDashboardElement(sceneObj)) { + return sceneObj; + } + + if (sceneObj instanceof VizPanel) { + return new VizPanelEditableElement(sceneObj); + } + + if (sceneObj instanceof SceneGridRow) { + return new SceneGridRowEditableElement(sceneObj); + } + + if (sceneObj instanceof DashboardScene) { + return new DashboardEditableElement(sceneObj); + } + + return undefined; +} + +export function hasEditableElement(sceneObj: SceneObject | undefined): boolean { + if (!sceneObj) { + return false; + } + + if ( + isEditableDashboardElement(sceneObj) || + sceneObj instanceof VizPanel || + sceneObj instanceof SceneGridRow || + sceneObj instanceof DashboardScene + ) { + return true; + } + + return false; +} diff --git a/public/app/features/dashboard-scene/scene/layout-default/SceneGridRowEditableElement.tsx b/public/app/features/dashboard-scene/scene/layout-default/SceneGridRowEditableElement.tsx new file mode 100644 index 00000000000..497b4087da9 --- /dev/null +++ b/public/app/features/dashboard-scene/scene/layout-default/SceneGridRowEditableElement.tsx @@ -0,0 +1,149 @@ +import { ReactNode, useMemo } from 'react'; + +import { selectors } from '@grafana/e2e-selectors'; +import { sceneGraph, SceneGridRow, VizPanel } from '@grafana/scenes'; +import { Alert, Button, Input, TextLink } from '@grafana/ui'; +import { t, Trans } from 'app/core/internationalization'; +import { OptionsPaneCategoryDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor'; +import { OptionsPaneItemDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor'; +import { RepeatRowSelect2 } from 'app/features/dashboard/components/RepeatRowSelect/RepeatRowSelect'; +import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard/constants'; +import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource'; + +import { getDashboardSceneFor, getLayoutManagerFor, getQueryRunnerFor } from '../../utils/utils'; +import { DashboardScene } from '../DashboardScene'; +import { BulkActionElement } from '../types/BulkActionElement'; +import { EditableDashboardElement, EditableDashboardElementInfo } from '../types/EditableDashboardElement'; + +import { DefaultGridLayoutManager } from './DefaultGridLayoutManager'; +import { RowRepeaterBehavior } from './RowRepeaterBehavior'; + +export class SceneGridRowEditableElement implements EditableDashboardElement, BulkActionElement { + public readonly isEditableDashboardElement = true; + + public constructor(private _row: SceneGridRow) {} + + public getEditableElementInfo(): EditableDashboardElementInfo { + return { + typeId: 'panel', + icon: 'line-alt', + name: sceneGraph.interpolate(this._row, this._row.state.title, undefined, 'text'), + }; + } + + public useEditPaneOptions(): OptionsPaneCategoryDescriptor[] { + const row = this._row; + + const rowOptions = useMemo(() => { + return new OptionsPaneCategoryDescriptor({ + title: t('dashboard.default-layout.row-options.title', 'Row options'), + id: 'row-options', + isOpenDefault: true, + }).addItem( + new OptionsPaneItemDescriptor({ + title: t('dashboard.default-layout.row-options.form.title', 'Title'), + render: () => , + }) + ); + }, [row]); + + const rowRepeatOptions = useMemo(() => { + const dashboard = getDashboardSceneFor(row); + + return new OptionsPaneCategoryDescriptor({ + title: t('dashboard.default-layout.row-options.repeat.title', 'Repeat options'), + id: 'row-repeat-options', + isOpenDefault: true, + }).addItem( + new OptionsPaneItemDescriptor({ + title: t('dashboard.default-layout.row-options.repeat.variable.title', 'Variable'), + render: () => , + }) + ); + }, [row]); + + return [rowOptions, rowRepeatOptions]; + } + + public onDelete() { + const layoutManager = getLayoutManagerFor(this._row); + + if (layoutManager instanceof DefaultGridLayoutManager) { + layoutManager.removeRow(this._row); + } + } + + public renderActions(): ReactNode { + return ( + <> + ; } - if (installState === InstallState.UPGRADE) { + if (installState === PluginStatus.UPDATE) { return ; } return ''; } -function getInstallState(installedVersion?: string, version?: string): InstallState { +function getInstallState(installedVersion?: string, version?: string): PluginStatus { if (!installedVersion || !version || !valid(installedVersion) || !valid(version)) { - return InstallState.INSTALL; + return PluginStatus.INSTALL; } - return gt(installedVersion, version) ? InstallState.DOWNGRADE : InstallState.UPGRADE; + return gt(installedVersion, version) ? PluginStatus.DOWNGRADE : PluginStatus.UPDATE; } -function getButtonHiddenState(installState: InstallState, isPreinstalled: { found: boolean; withVersion: boolean }) { +function getButtonHiddenState(installState: PluginStatus, isPreinstalled: { found: boolean; withVersion: boolean }) { // Default state for initial install - if (installState === InstallState.INSTALL) { + if (installState === PluginStatus.INSTALL) { return false; } // Handle downgrade case - if (installState === InstallState.DOWNGRADE) { + if (installState === PluginStatus.DOWNGRADE) { return isPreinstalled.found && Boolean(config.featureToggles.preinstallAutoUpdate); } diff --git a/public/app/features/plugins/admin/state/actions.ts b/public/app/features/plugins/admin/state/actions.ts index eab93de18fa..e08e7241c42 100644 --- a/public/app/features/plugins/admin/state/actions.ts +++ b/public/app/features/plugins/admin/state/actions.ts @@ -19,7 +19,7 @@ import { } from '../api'; import { STATE_PREFIX } from '../constants'; import { mapLocalToCatalog, mergeLocalsAndRemotes, updatePanels } from '../helpers'; -import { CatalogPlugin, RemotePlugin, LocalPlugin, InstancePlugin, ProvisionedPlugin } from '../types'; +import { CatalogPlugin, RemotePlugin, LocalPlugin, InstancePlugin, ProvisionedPlugin, PluginStatus } from '../types'; // Fetches export const fetchAll = createAsyncThunk(`${STATE_PREFIX}/fetchAll`, async (_, thunkApi) => { @@ -188,17 +188,23 @@ export const install = createAsyncThunk< { id: string; version?: string; - isUpdating?: boolean; + installType?: PluginStatus; } ->(`${STATE_PREFIX}/install`, async ({ id, version, isUpdating = false }, thunkApi) => { - const changes = isUpdating - ? { isInstalled: true, installedVersion: version, hasUpdate: false } - : { isInstalled: true, installedVersion: version }; +>(`${STATE_PREFIX}/install`, async ({ id, version, installType = PluginStatus.INSTALL }, thunkApi) => { + const changes: Partial = { isInstalled: true, installedVersion: version }; + + if (installType === PluginStatus.UPDATE) { + changes.hasUpdate = false; + } + if (installType === PluginStatus.DOWNGRADE) { + changes.hasUpdate = true; + } + try { await installPlugin(id, version); await updatePanels(); - if (isUpdating) { + if (installType !== PluginStatus.INSTALL) { invalidatePluginInCache(id); } diff --git a/public/app/features/plugins/admin/state/hooks.ts b/public/app/features/plugins/admin/state/hooks.ts index da0ba859a3a..457f2f1d73e 100644 --- a/public/app/features/plugins/admin/state/hooks.ts +++ b/public/app/features/plugins/admin/state/hooks.ts @@ -4,7 +4,7 @@ import { PluginError, PluginType } from '@grafana/data'; import { useDispatch, useSelector } from 'app/types'; import { sortPlugins, Sorters, isPluginUpdatable } from '../helpers'; -import { CatalogPlugin } from '../types'; +import { CatalogPlugin, PluginStatus } from '../types'; import { fetchAll, fetchDetails, fetchRemotePlugins, install, uninstall, fetchAllLocal, unsetInstall } from './actions'; import { @@ -64,7 +64,7 @@ export const useGetErrors = (filterByPluginType?: PluginType): PluginError[] => export const useInstall = () => { const dispatch = useDispatch(); - return (id: string, version?: string, isUpdating?: boolean) => dispatch(install({ id, version, isUpdating })); + return (id: string, version?: string, installType?: PluginStatus) => dispatch(install({ id, version, installType })); }; export const useUnsetInstall = () => { diff --git a/public/app/features/plugins/admin/types.ts b/public/app/features/plugins/admin/types.ts index f3d5783ae3c..96e1d2451d2 100644 --- a/public/app/features/plugins/admin/types.ts +++ b/public/app/features/plugins/admin/types.ts @@ -257,6 +257,7 @@ export enum PluginStatus { UNINSTALL = 'UNINSTALL', UPDATE = 'UPDATE', REINSTALL = 'REINSTALL', + DOWNGRADE = 'DOWNGRADE', } export enum PluginTabLabels { From 5e61ec12580d780f088230dd8a865b98a58af500 Mon Sep 17 00:00:00 2001 From: Leonor Oliveira <9090754+leonorfmartins@users.noreply.github.com> Date: Thu, 27 Feb 2025 15:17:50 +0100 Subject: [PATCH 13/74] Prevent wrong type conversion (#101349) --- pkg/registry/apis/folders/legacy_storage.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/registry/apis/folders/legacy_storage.go b/pkg/registry/apis/folders/legacy_storage.go index 0c96769a942..34dcaa9a73b 100644 --- a/pkg/registry/apis/folders/legacy_storage.go +++ b/pkg/registry/apis/folders/legacy_storage.go @@ -116,7 +116,7 @@ func (s *legacyStorage) List(ctx context.Context, options *internalversion.ListO } list.Items = append(list.Items, *r) } - if len(list.Items) >= int(paging.limit) { + if int64(len(list.Items)) >= paging.limit { list.Continue = paging.GetNextPageToken() } return list, nil From f8b63c364b65f1c6a5e6eeed07a90ae1ddbc5389 Mon Sep 17 00:00:00 2001 From: Leonor Oliveira <9090754+leonorfmartins@users.noreply.github.com> Date: Thu, 27 Feb 2025 15:18:02 +0100 Subject: [PATCH 14/74] [CodeQL] Fix wrong type conversion (#101353) * [CodeQL] Fix wrong type conversion * Use AtyoI --- pkg/services/dashboardversion/dashverimpl/dashver.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pkg/services/dashboardversion/dashverimpl/dashver.go b/pkg/services/dashboardversion/dashverimpl/dashver.go index 6130ea6e279..27bcbb845d1 100644 --- a/pkg/services/dashboardversion/dashverimpl/dashver.go +++ b/pkg/services/dashboardversion/dashverimpl/dashver.go @@ -334,10 +334,9 @@ func getRestoreVersion(msg string) (int, error) { return 0, nil } - ver, err := strconv.ParseInt(parts[1], 10, 64) + ver, err := strconv.Atoi(parts[1]) if err != nil { return 0, err } - - return int(ver), nil + return ver, nil } From 980332ae75795e55cfb66b02c687b954747c7d68 Mon Sep 17 00:00:00 2001 From: Sonia Aguilar <33540275+soniaAguilarPeiron@users.noreply.github.com> Date: Thu, 27 Feb 2025 15:20:07 +0100 Subject: [PATCH 15/74] Alerting: Fix exporting new rule with a new group (#101404) Fix exporting new rule with a new group --- .../rule-editor/alert-rule-form/ModifyExportRuleForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/ModifyExportRuleForm.tsx b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/ModifyExportRuleForm.tsx index 72093ecc490..71c049e661b 100644 --- a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/ModifyExportRuleForm.tsx +++ b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/ModifyExportRuleForm.tsx @@ -168,7 +168,7 @@ export const getPayloadToExport = ( } else { // we have to create a new group with the updated rule return { - name: existingGroup?.name ?? '', + name: existingGroup?.name ?? formValues.group, rules: [updatedRule], }; } From 98dd977fabd06a6ef650c3f2d8894fe428dee541 Mon Sep 17 00:00:00 2001 From: Sonia Aguilar <33540275+soniaAguilarPeiron@users.noreply.github.com> Date: Thu, 27 Feb 2025 15:23:40 +0100 Subject: [PATCH 16/74] Alerting: Fix KeyValueMap input bug (#101367) * fix KeyValueMap input bug * add translations --- .betterer.results | 6 +- .../form/fields/KeyValueMapInput.tsx | 77 +++++++++++++------ public/locales/en-US/grafana.json | 4 + public/locales/pseudo-LOCALE/grafana.json | 4 + 4 files changed, 62 insertions(+), 29 deletions(-) diff --git a/.betterer.results b/.betterer.results index 5e04d7cf375..f6c07dd6633 100644 --- a/.betterer.results +++ b/.betterer.results @@ -1982,10 +1982,8 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "6"] ], "public/app/features/alerting/unified/components/receivers/form/fields/KeyValueMapInput.tsx:5381": [ - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "3"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "1"] ], "public/app/features/alerting/unified/components/receivers/form/fields/OptionField.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], diff --git a/public/app/features/alerting/unified/components/receivers/form/fields/KeyValueMapInput.tsx b/public/app/features/alerting/unified/components/receivers/form/fields/KeyValueMapInput.tsx index 5a1bccdd34e..b69a9dce091 100644 --- a/public/app/features/alerting/unified/components/receivers/form/fields/KeyValueMapInput.tsx +++ b/public/app/features/alerting/unified/components/receivers/form/fields/KeyValueMapInput.tsx @@ -1,8 +1,9 @@ import { css } from '@emotion/css'; -import { useEffect, useState } from 'react'; +import { useState } from 'react'; import { GrafanaTheme2 } from '@grafana/data'; -import { Button, Input, useStyles2 } from '@grafana/ui'; +import { Button, Input, Stack, useStyles2 } from '@grafana/ui'; +import { Trans, t } from 'app/core/internationalization'; import { ActionIcon } from '../../../rules/ActionIcon'; @@ -15,7 +16,7 @@ interface Props { export const KeyValueMapInput = ({ value, onChange, readOnly = false }: Props) => { const styles = useStyles2(getStyles); const [pairs, setPairs] = useState(recordToPairs(value)); - useEffect(() => setPairs(recordToPairs(value)), [value]); + const [currentNewPair, setCurrentNewPair] = useState<[string, string] | undefined>(undefined); const emitChange = (pairs: Array<[string, string]>) => { onChange(pairsToRecord(pairs)); @@ -30,15 +31,6 @@ export const KeyValueMapInput = ({ value, onChange, readOnly = false }: Props) = } }; - const updatePair = (values: [string, string], index: number) => { - const old = pairs[index]; - const newPairs = pairs.map((pair, i) => (i === index ? values : pair)); - setPairs(newPairs); - if (values[0] || old[0]) { - emitChange(newPairs); - } - }; - return (
{!!pairs.length && ( @@ -54,22 +46,18 @@ export const KeyValueMapInput = ({ value, onChange, readOnly = false }: Props) = {pairs.map(([key, value], index) => ( - updatePair([e.currentTarget.value, value], index)} - /> + - updatePair([key, e.currentTarget.value], index)} - /> + {!readOnly && ( - deleteItem(index)} /> + deleteItem(index)} + /> )} @@ -77,6 +65,44 @@ export const KeyValueMapInput = ({ value, onChange, readOnly = false }: Props) = )} + {currentNewPair && ( + + + + + + + + +
+ setCurrentNewPair([e.currentTarget.value, currentNewPair[1]])} + /> + + setCurrentNewPair([currentNewPair[0], e.currentTarget.value])} + /> + + + { + setPairs([...pairs, currentNewPair]); + setCurrentNewPair(undefined); + emitChange([...pairs, currentNewPair]); + }} + /> + setCurrentNewPair(undefined)} + /> + +
+ )} {!readOnly && ( )}
diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index e014860e85c..a064ce993a6 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -315,6 +315,10 @@ "empty-state": { "title": "You don't have any contact points yet" }, + "key-value-map": { + "add": "Add", + "confirm-add": "Confirm to add" + }, "last-delivery-attempt": "Last delivery attempt", "last-delivery-failed": "Last delivery attempt failed", "no-contact-points-found": "No contact points found", diff --git a/public/locales/pseudo-LOCALE/grafana.json b/public/locales/pseudo-LOCALE/grafana.json index cb3c713ad28..317a107f796 100644 --- a/public/locales/pseudo-LOCALE/grafana.json +++ b/public/locales/pseudo-LOCALE/grafana.json @@ -315,6 +315,10 @@ "empty-state": { "title": "Ÿőū đőʼn'ŧ ĥävę äʼny čőʼnŧäčŧ pőįʼnŧş yęŧ" }, + "key-value-map": { + "add": "Åđđ", + "confirm-add": "Cőʼnƒįřm ŧő äđđ" + }, "last-delivery-attempt": "Ŀäşŧ đęľįvęřy äŧŧęmpŧ", "last-delivery-failed": "Ŀäşŧ đęľįvęřy äŧŧęmpŧ ƒäįľęđ", "no-contact-points-found": "Ńő čőʼnŧäčŧ pőįʼnŧş ƒőūʼnđ", From 2ec8b0b45b5a93d9c36169f24b60028ae88c78a8 Mon Sep 17 00:00:00 2001 From: Kevin Minehart <5140827+kminehart@users.noreply.github.com> Date: Thu, 27 Feb 2025 09:00:00 -0600 Subject: [PATCH 17/74] CI: Create the frontend test workflow in GHA (#101256) * Create the frontend test workflow * Give .github/workflows/test-frontend to frontend platform group * Remove file filter * rename workflow * frontend unit tests * add yarn install * update CODEOWNERS * Run on 8 core machines? * use parallelization? * add sharding * update package.json to allow sharding jest * update workflow name * yarn generate-apis * update naming --- .github/CODEOWNERS | 1 + .github/workflows/frontend-unit-tests.yml | 29 +++++++++++++++++++++++ package.json | 2 +- 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/frontend-unit-tests.yml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 4e3ca236ebf..64363540c79 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -813,6 +813,7 @@ embed.go @grafana/grafana-as-code /.github/workflows/trivy-scan.yml @grafana/grafana-backend-services-squad /.github/workflows/changelog.yml @zserge /.github/workflows/actions/changelog @zserge +/.github/workflows/frontend-unit-tests.yml @grafana/grafana-frontend-platform # Generated files not requiring owner approval /packages/grafana-data/src/types/featureToggles.gen.ts @grafanabot diff --git a/.github/workflows/frontend-unit-tests.yml b/.github/workflows/frontend-unit-tests.yml new file mode 100644 index 00000000000..495bb647233 --- /dev/null +++ b/.github/workflows/frontend-unit-tests.yml @@ -0,0 +1,29 @@ +name: Frontend tests +on: + pull_request: + push: + branches: + - main + - release-*.*.* + +jobs: + test-frontend: + runs-on: ubuntu-latest-8-cores + name: "Unit tests (${{ matrix.chunk }} / 8)" + strategy: + fail-fast: true + matrix: + chunk: [1, 2, 3, 4, 5, 6, 7, 8] + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: 'yarn' + cache-dependency-path: 'yarn.lock' + - run: yarn install --immutable --check-cache + - run: yarn run test:ci + env: + TEST_MAX_WORKERS: 2 + TEST_SHARD: ${{ matrix.chunk }} + TEST_SHARD_TOTAL: 8 diff --git a/package.json b/package.json index 3eb2cbbeabf..a07f4835a14 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "lint": "yarn run lint:ts && yarn run lint:sass", "lint:ts": "eslint ./ ./public/app/extensions/ --cache --no-error-on-unmatched-pattern", "lint:sass": "yarn stylelint '{public/sass,packages}/**/*.scss' --cache", - "test:ci": "mkdir -p reports/junit && JEST_JUNIT_OUTPUT_DIR=reports/junit jest --ci --reporters=default --reporters=jest-junit -w ${TEST_MAX_WORKERS:-100%}", + "test:ci": "mkdir -p reports/junit && JEST_JUNIT_OUTPUT_DIR=reports/junit jest --ci --reporters=default --reporters=jest-junit -w ${TEST_MAX_WORKERS:-100%} --shard=${TEST_SHARD:-1}/${TEST_SHARD_TOTAL:-1}", "lint:fix": "yarn lint:ts --fix", "packages:build": "nx run-many -t build --projects='tag:scope:package'", "packages:clean": "rimraf ./npm-artifacts && nx run-many -t clean --projects='tag:scope:package' --maxParallel=100", From 9beaa3e1d146674370abe094e0933eca618d2aac Mon Sep 17 00:00:00 2001 From: Jack Westbrook Date: Thu, 27 Feb 2025 16:30:21 +0100 Subject: [PATCH 18/74] CI: Update renovate storybook config (#101424) ci(renovate): when bumping storybook always update package.json so e2e ci step runs --- .github/renovate.json5 | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index a782ac2c0a0..43a537f2fa1 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -32,6 +32,7 @@ extends: ["schedule:monthly"], groupName: "Storybook updates", matchPackageNames: ["/^@?storybook/"], + rangeStrategy: "bump", }, { groupName: "React Aria", From 908f4ff357c296a21bf05f4383dbe1bc1d2fa5e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C5=A0tibran=C3=BD?= Date: Thu, 27 Feb 2025 16:33:26 +0100 Subject: [PATCH 19/74] Use enterprise imports for pro builds as well. (#101423) --- pkg/extensions/enterprise_imports.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/extensions/enterprise_imports.go b/pkg/extensions/enterprise_imports.go index f0b4c12f7ec..7e96faa86ac 100644 --- a/pkg/extensions/enterprise_imports.go +++ b/pkg/extensions/enterprise_imports.go @@ -1,5 +1,5 @@ -//go:build enterprise -// +build enterprise +//go:build enterprise || pro +// +build enterprise pro package extensions From 843d876f1688115565949536d1d642fc4b6e6601 Mon Sep 17 00:00:00 2001 From: Eric Leijonmarck Date: Thu, 27 Feb 2025 15:34:15 +0000 Subject: [PATCH 20/74] Anon: Deprecation notice for Editor, Admin anonymous org role usage (#101411) * deprecation notice for anonymous org role usage * exclude viewer --- pkg/setting/setting_anonymous.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkg/setting/setting_anonymous.go b/pkg/setting/setting_anonymous.go index 057b82e73a4..53e0830eb86 100644 --- a/pkg/setting/setting_anonymous.go +++ b/pkg/setting/setting_anonymous.go @@ -14,7 +14,12 @@ func (cfg *Cfg) readAnonymousSettings() { anonSettings := AnonymousSettings{} anonSettings.Enabled = anonSection.Key("enabled").MustBool(false) anonSettings.OrgName = valueAsString(anonSection, "org_name", "") + // Deprecated: + // only viewer role is supported anonSettings.OrgRole = valueAsString(anonSection, "org_role", "") + if anonSettings.OrgRole != "Viewer" { + cfg.Logger.Warn("auth.anonymous.org_role is deprecated, only viewer role is supported") + } anonSettings.HideVersion = anonSection.Key("hide_version").MustBool(false) anonSettings.DeviceLimit = anonSection.Key("device_limit").MustInt64(0) cfg.Anonymous = anonSettings From ef86582dfca33243e202ffb966bce2f8ca4ffc27 Mon Sep 17 00:00:00 2001 From: Alexander Akhmetov Date: Thu, 27 Feb 2025 17:20:49 +0100 Subject: [PATCH 21/74] Alerting: API paths for cortextool to import Loki rules (#101409) Alerting: Legacy rules paths for cortextool --- pkg/services/ngalert/api/authorization.go | 14 +- .../ngalert/api/authorization_test.go | 2 +- .../generated_base_api_convert_prometheus.go | 108 ++++ .../ngalert/api/prometheus_conversion.go | 26 + pkg/services/ngalert/api/tooling/api.json | 4 +- .../definitions/convert_prometheus_api.go | 95 +++- pkg/services/ngalert/api/tooling/post.json | 252 ++++++++- pkg/services/ngalert/api/tooling/spec.json | 252 ++++++++- .../alerting/api_convert_prometheus_test.go | 506 ++++++++++-------- pkg/tests/api/alerting/testing.go | 43 +- public/api-merged.json | 1 + public/openapi3.json | 1 + 12 files changed, 1049 insertions(+), 255 deletions(-) diff --git a/pkg/services/ngalert/api/authorization.go b/pkg/services/ngalert/api/authorization.go index a1cedae4b73..4dce6e33015 100644 --- a/pkg/services/ngalert/api/authorization.go +++ b/pkg/services/ngalert/api/authorization.go @@ -125,26 +125,32 @@ func (api *API) authorize(method, path string) web.Handler { // convert/prometheus API paths case http.MethodGet + "/api/convert/prometheus/config/v1/rules/{NamespaceTitle}/{Group}", - http.MethodGet + "/api/convert/prometheus/config/v1/rules/{NamespaceTitle}": + http.MethodGet + "/api/convert/api/prom/rules/{NamespaceTitle}/{Group}", + http.MethodGet + "/api/convert/prometheus/config/v1/rules/{NamespaceTitle}", + http.MethodGet + "/api/convert/api/prom/rules/{NamespaceTitle}": eval = ac.EvalAll( ac.EvalPermission(ac.ActionAlertingRuleRead), ac.EvalPermission(dashboards.ActionFoldersRead), ) - case http.MethodGet + "/api/convert/prometheus/config/v1/rules": + case http.MethodGet + "/api/convert/prometheus/config/v1/rules", + http.MethodGet + "/api/convert/api/prom/rules": eval = ac.EvalAll( ac.EvalPermission(ac.ActionAlertingRuleRead), ac.EvalPermission(dashboards.ActionFoldersRead), ) - case http.MethodPost + "/api/convert/prometheus/config/v1/rules/{NamespaceTitle}": + case http.MethodPost + "/api/convert/prometheus/config/v1/rules/{NamespaceTitle}", + http.MethodPost + "/api/convert/api/prom/rules/{NamespaceTitle}": eval = ac.EvalAll( ac.EvalPermission(ac.ActionAlertingRuleCreate), ac.EvalPermission(ac.ActionAlertingProvisioningSetStatus), ) case http.MethodDelete + "/api/convert/prometheus/config/v1/rules/{NamespaceTitle}/{Group}", - http.MethodDelete + "/api/convert/prometheus/config/v1/rules/{NamespaceTitle}": + http.MethodDelete + "/api/convert/api/prom/rules/{NamespaceTitle}/{Group}", + http.MethodDelete + "/api/convert/prometheus/config/v1/rules/{NamespaceTitle}", + http.MethodDelete + "/api/convert/api/prom/rules/{NamespaceTitle}": eval = ac.EvalAny( ac.EvalAll( ac.EvalPermission(ac.ActionAlertingRuleRead), diff --git a/pkg/services/ngalert/api/authorization_test.go b/pkg/services/ngalert/api/authorization_test.go index 13b0f24c36c..993a72d3ef7 100644 --- a/pkg/services/ngalert/api/authorization_test.go +++ b/pkg/services/ngalert/api/authorization_test.go @@ -41,7 +41,7 @@ func TestAuthorize(t *testing.T) { } paths[p] = methods } - require.Len(t, paths, 63) + require.Len(t, paths, 66) ac := acmock.New() api := &API{AccessControl: ac, FeatureManager: featuremgmt.WithFeatures()} diff --git a/pkg/services/ngalert/api/generated_base_api_convert_prometheus.go b/pkg/services/ngalert/api/generated_base_api_convert_prometheus.go index 3f2e0566295..2ee728172c9 100644 --- a/pkg/services/ngalert/api/generated_base_api_convert_prometheus.go +++ b/pkg/services/ngalert/api/generated_base_api_convert_prometheus.go @@ -19,6 +19,12 @@ import ( ) type ConvertPrometheusApi interface { + RouteConvertPrometheusCortexDeleteNamespace(*contextmodel.ReqContext) response.Response + RouteConvertPrometheusCortexDeleteRuleGroup(*contextmodel.ReqContext) response.Response + RouteConvertPrometheusCortexGetNamespace(*contextmodel.ReqContext) response.Response + RouteConvertPrometheusCortexGetRuleGroup(*contextmodel.ReqContext) response.Response + RouteConvertPrometheusCortexGetRules(*contextmodel.ReqContext) response.Response + RouteConvertPrometheusCortexPostRuleGroup(*contextmodel.ReqContext) response.Response RouteConvertPrometheusDeleteNamespace(*contextmodel.ReqContext) response.Response RouteConvertPrometheusDeleteRuleGroup(*contextmodel.ReqContext) response.Response RouteConvertPrometheusGetNamespace(*contextmodel.ReqContext) response.Response @@ -27,6 +33,36 @@ type ConvertPrometheusApi interface { RouteConvertPrometheusPostRuleGroup(*contextmodel.ReqContext) response.Response } +func (f *ConvertPrometheusApiHandler) RouteConvertPrometheusCortexDeleteNamespace(ctx *contextmodel.ReqContext) response.Response { + // Parse Path Parameters + namespaceTitleParam := web.Params(ctx.Req)[":NamespaceTitle"] + return f.handleRouteConvertPrometheusCortexDeleteNamespace(ctx, namespaceTitleParam) +} +func (f *ConvertPrometheusApiHandler) RouteConvertPrometheusCortexDeleteRuleGroup(ctx *contextmodel.ReqContext) response.Response { + // Parse Path Parameters + namespaceTitleParam := web.Params(ctx.Req)[":NamespaceTitle"] + groupParam := web.Params(ctx.Req)[":Group"] + return f.handleRouteConvertPrometheusCortexDeleteRuleGroup(ctx, namespaceTitleParam, groupParam) +} +func (f *ConvertPrometheusApiHandler) RouteConvertPrometheusCortexGetNamespace(ctx *contextmodel.ReqContext) response.Response { + // Parse Path Parameters + namespaceTitleParam := web.Params(ctx.Req)[":NamespaceTitle"] + return f.handleRouteConvertPrometheusCortexGetNamespace(ctx, namespaceTitleParam) +} +func (f *ConvertPrometheusApiHandler) RouteConvertPrometheusCortexGetRuleGroup(ctx *contextmodel.ReqContext) response.Response { + // Parse Path Parameters + namespaceTitleParam := web.Params(ctx.Req)[":NamespaceTitle"] + groupParam := web.Params(ctx.Req)[":Group"] + return f.handleRouteConvertPrometheusCortexGetRuleGroup(ctx, namespaceTitleParam, groupParam) +} +func (f *ConvertPrometheusApiHandler) RouteConvertPrometheusCortexGetRules(ctx *contextmodel.ReqContext) response.Response { + return f.handleRouteConvertPrometheusCortexGetRules(ctx) +} +func (f *ConvertPrometheusApiHandler) RouteConvertPrometheusCortexPostRuleGroup(ctx *contextmodel.ReqContext) response.Response { + // Parse Path Parameters + namespaceTitleParam := web.Params(ctx.Req)[":NamespaceTitle"] + return f.handleRouteConvertPrometheusCortexPostRuleGroup(ctx, namespaceTitleParam) +} func (f *ConvertPrometheusApiHandler) RouteConvertPrometheusDeleteNamespace(ctx *contextmodel.ReqContext) response.Response { // Parse Path Parameters namespaceTitleParam := web.Params(ctx.Req)[":NamespaceTitle"] @@ -60,6 +96,78 @@ func (f *ConvertPrometheusApiHandler) RouteConvertPrometheusPostRuleGroup(ctx *c func (api *API) RegisterConvertPrometheusApiEndpoints(srv ConvertPrometheusApi, m *metrics.API) { api.RouteRegister.Group("", func(group routing.RouteRegister) { + group.Delete( + toMacaronPath("/api/convert/api/prom/rules/{NamespaceTitle}"), + requestmeta.SetOwner(requestmeta.TeamAlerting), + requestmeta.SetSLOGroup(requestmeta.SLOGroupHighSlow), + api.authorize(http.MethodDelete, "/api/convert/api/prom/rules/{NamespaceTitle}"), + metrics.Instrument( + http.MethodDelete, + "/api/convert/api/prom/rules/{NamespaceTitle}", + api.Hooks.Wrap(srv.RouteConvertPrometheusCortexDeleteNamespace), + m, + ), + ) + group.Delete( + toMacaronPath("/api/convert/api/prom/rules/{NamespaceTitle}/{Group}"), + requestmeta.SetOwner(requestmeta.TeamAlerting), + requestmeta.SetSLOGroup(requestmeta.SLOGroupHighSlow), + api.authorize(http.MethodDelete, "/api/convert/api/prom/rules/{NamespaceTitle}/{Group}"), + metrics.Instrument( + http.MethodDelete, + "/api/convert/api/prom/rules/{NamespaceTitle}/{Group}", + api.Hooks.Wrap(srv.RouteConvertPrometheusCortexDeleteRuleGroup), + m, + ), + ) + group.Get( + toMacaronPath("/api/convert/api/prom/rules/{NamespaceTitle}"), + requestmeta.SetOwner(requestmeta.TeamAlerting), + requestmeta.SetSLOGroup(requestmeta.SLOGroupHighSlow), + api.authorize(http.MethodGet, "/api/convert/api/prom/rules/{NamespaceTitle}"), + metrics.Instrument( + http.MethodGet, + "/api/convert/api/prom/rules/{NamespaceTitle}", + api.Hooks.Wrap(srv.RouteConvertPrometheusCortexGetNamespace), + m, + ), + ) + group.Get( + toMacaronPath("/api/convert/api/prom/rules/{NamespaceTitle}/{Group}"), + requestmeta.SetOwner(requestmeta.TeamAlerting), + requestmeta.SetSLOGroup(requestmeta.SLOGroupHighSlow), + api.authorize(http.MethodGet, "/api/convert/api/prom/rules/{NamespaceTitle}/{Group}"), + metrics.Instrument( + http.MethodGet, + "/api/convert/api/prom/rules/{NamespaceTitle}/{Group}", + api.Hooks.Wrap(srv.RouteConvertPrometheusCortexGetRuleGroup), + m, + ), + ) + group.Get( + toMacaronPath("/api/convert/api/prom/rules"), + requestmeta.SetOwner(requestmeta.TeamAlerting), + requestmeta.SetSLOGroup(requestmeta.SLOGroupHighSlow), + api.authorize(http.MethodGet, "/api/convert/api/prom/rules"), + metrics.Instrument( + http.MethodGet, + "/api/convert/api/prom/rules", + api.Hooks.Wrap(srv.RouteConvertPrometheusCortexGetRules), + m, + ), + ) + group.Post( + toMacaronPath("/api/convert/api/prom/rules/{NamespaceTitle}"), + requestmeta.SetOwner(requestmeta.TeamAlerting), + requestmeta.SetSLOGroup(requestmeta.SLOGroupHighSlow), + api.authorize(http.MethodPost, "/api/convert/api/prom/rules/{NamespaceTitle}"), + metrics.Instrument( + http.MethodPost, + "/api/convert/api/prom/rules/{NamespaceTitle}", + api.Hooks.Wrap(srv.RouteConvertPrometheusCortexPostRuleGroup), + m, + ), + ) group.Delete( toMacaronPath("/api/convert/prometheus/config/v1/rules/{NamespaceTitle}"), requestmeta.SetOwner(requestmeta.TeamAlerting), diff --git a/pkg/services/ngalert/api/prometheus_conversion.go b/pkg/services/ngalert/api/prometheus_conversion.go index 354f6de2a38..d48aa5444b9 100644 --- a/pkg/services/ngalert/api/prometheus_conversion.go +++ b/pkg/services/ngalert/api/prometheus_conversion.go @@ -20,6 +20,7 @@ func NewConvertPrometheusApi(svc *ConvertPrometheusSrv) *ConvertPrometheusApiHan } } +// mimirtool func (f *ConvertPrometheusApiHandler) handleRouteConvertPrometheusGetRules(ctx *contextmodel.ReqContext) response.Response { return f.svc.RouteConvertPrometheusGetRules(ctx) } @@ -54,3 +55,28 @@ func (f *ConvertPrometheusApiHandler) handleRouteConvertPrometheusPostRuleGroup( return f.svc.RouteConvertPrometheusPostRuleGroup(ctx, namespaceTitle, promGroup) } + +// cortextool +func (f *ConvertPrometheusApiHandler) handleRouteConvertPrometheusCortexGetRules(ctx *contextmodel.ReqContext) response.Response { + return f.handleRouteConvertPrometheusGetRules(ctx) +} + +func (f *ConvertPrometheusApiHandler) handleRouteConvertPrometheusCortexDeleteNamespace(ctx *contextmodel.ReqContext, namespaceTitle string) response.Response { + return f.handleRouteConvertPrometheusDeleteNamespace(ctx, namespaceTitle) +} + +func (f *ConvertPrometheusApiHandler) handleRouteConvertPrometheusCortexDeleteRuleGroup(ctx *contextmodel.ReqContext, namespaceTitle string, group string) response.Response { + return f.handleRouteConvertPrometheusDeleteRuleGroup(ctx, namespaceTitle, group) +} + +func (f *ConvertPrometheusApiHandler) handleRouteConvertPrometheusCortexGetNamespace(ctx *contextmodel.ReqContext, namespaceTitle string) response.Response { + return f.handleRouteConvertPrometheusGetNamespace(ctx, namespaceTitle) +} + +func (f *ConvertPrometheusApiHandler) handleRouteConvertPrometheusCortexGetRuleGroup(ctx *contextmodel.ReqContext, namespaceTitle string, group string) response.Response { + return f.handleRouteConvertPrometheusGetRuleGroup(ctx, namespaceTitle, group) +} + +func (f *ConvertPrometheusApiHandler) handleRouteConvertPrometheusCortexPostRuleGroup(ctx *contextmodel.ReqContext, namespaceTitle string) response.Response { + return f.handleRouteConvertPrometheusPostRuleGroup(ctx, namespaceTitle) +} diff --git a/pkg/services/ngalert/api/tooling/api.json b/pkg/services/ngalert/api/tooling/api.json index 0a2fb0af0d4..7fc77c7ce19 100644 --- a/pkg/services/ngalert/api/tooling/api.json +++ b/pkg/services/ngalert/api/tooling/api.json @@ -4493,7 +4493,6 @@ "type": "object" }, "URL": { - "description": "The general form represented is:\n\n[scheme:][//[userinfo@]host][/]path[?query][#fragment]\n\nURLs that do not start with a slash after the scheme are interpreted as:\n\nscheme:opaque[?query][#fragment]\n\nThe Host field contains the host and port subcomponents of the URL.\nWhen the port is present, it is separated from the host with a colon.\nWhen the host is an IPv6 address, it must be enclosed in square brackets:\n\"[fe80::1]:80\". The [net.JoinHostPort] function combines a host and port\ninto a string suitable for the Host field, adding square brackets to\nthe host when necessary.\n\nNote that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/.\nA consequence is that it is impossible to tell which slashes in the Path were\nslashes in the raw URL and which were %2f. This distinction is rarely important,\nbut when it is, the code should use the [URL.EscapedPath] method, which preserves\nthe original encoding of Path.\n\nThe RawPath field is an optional field which is only set when the default\nencoding of Path is different from the escaped path. See the EscapedPath method\nfor more details.\n\nURL's String method uses the EscapedPath method to obtain the path.", "properties": { "ForceQuery": { "type": "boolean" @@ -4529,7 +4528,7 @@ "$ref": "#/definitions/Userinfo" } }, - "title": "A URL represents a parsed URL (technically, a URI reference).", + "title": "URL is a custom URL type that allows validation at configuration load time.", "type": "object" }, "UpdateRuleGroupResponse": { @@ -4932,6 +4931,7 @@ "type": "object" }, "gettableAlerts": { + "description": "GettableAlerts gettable alerts", "items": { "$ref": "#/definitions/gettableAlert", "type": "object" diff --git a/pkg/services/ngalert/api/tooling/definitions/convert_prometheus_api.go b/pkg/services/ngalert/api/tooling/definitions/convert_prometheus_api.go index 9442ba9fc0f..f0202486e46 100644 --- a/pkg/services/ngalert/api/tooling/definitions/convert_prometheus_api.go +++ b/pkg/services/ngalert/api/tooling/definitions/convert_prometheus_api.go @@ -4,6 +4,7 @@ import ( "github.com/prometheus/common/model" ) +// Route for mimirtool // swagger:route GET /convert/prometheus/config/v1/rules convert_prometheus RouteConvertPrometheusGetRules // // Gets all Grafana-managed alert rules that were imported from Prometheus-compatible sources, grouped by namespace. @@ -16,6 +17,20 @@ import ( // 403: ForbiddenError // 404: NotFound +// Route for cortextool +// swagger:route GET /convert/api/prom/rules convert_prometheus RouteConvertPrometheusCortexGetRules +// +// Gets all Grafana-managed alert rules that were imported from Prometheus-compatible sources, grouped by namespace. +// +// Produces: +// - application/yaml +// +// Responses: +// 200: PrometheusNamespace +// 403: ForbiddenError +// 404: NotFound + +// Route for mimirtool // swagger:route GET /convert/prometheus/config/v1/rules/{NamespaceTitle} convert_prometheus RouteConvertPrometheusGetNamespace // // Gets Grafana-managed alert rules that were imported from Prometheus-compatible sources for a specified namespace (folder). @@ -28,6 +43,20 @@ import ( // 403: ForbiddenError // 404: NotFound +// Route for cortextool +// swagger:route GET /convert/api/prom/rules/{NamespaceTitle} convert_prometheus RouteConvertPrometheusCortexGetNamespace +// +// Gets Grafana-managed alert rules that were imported from Prometheus-compatible sources for a specified namespace (folder). +// +// Produces: +// - application/yaml +// +// Responses: +// 200: PrometheusNamespace +// 403: ForbiddenError +// 404: NotFound + +// Route for mimirtool // swagger:route GET /convert/prometheus/config/v1/rules/{NamespaceTitle}/{Group} convert_prometheus RouteConvertPrometheusGetRuleGroup // // Gets a single rule group in Prometheus-compatible format if it was imported from a Prometheus-compatible source. @@ -40,6 +69,20 @@ import ( // 403: ForbiddenError // 404: NotFound +// Route for cortextool +// swagger:route GET /convert/api/prom/rules/{NamespaceTitle}/{Group} convert_prometheus RouteConvertPrometheusCortexGetRuleGroup +// +// Gets a single rule group in Prometheus-compatible format if it was imported from a Prometheus-compatible source. +// +// Produces: +// - application/yaml +// +// Responses: +// 200: PrometheusRuleGroup +// 403: ForbiddenError +// 404: NotFound + +// Route for mimirtool // swagger:route POST /convert/prometheus/config/v1/rules/{NamespaceTitle} convert_prometheus RouteConvertPrometheusPostRuleGroup // // Converts a Prometheus rule group into a Grafana rule group and creates or updates it within the specified namespace. @@ -59,6 +102,27 @@ import ( // Extensions: // x-raw-request: true +// Route for cortextool +// swagger:route POST /convert/api/prom/rules/{NamespaceTitle} convert_prometheus RouteConvertPrometheusCortexPostRuleGroup +// +// Converts a Prometheus rule group into a Grafana rule group and creates or updates it within the specified namespace. +// If the group already exists and was not imported from a Prometheus-compatible source initially, +// it will not be replaced and an error will be returned. +// +// Consumes: +// - application/yaml +// +// Produces: +// - application/json +// +// Responses: +// 202: ConvertPrometheusResponse +// 403: ForbiddenError +// +// Extensions: +// x-raw-request: true + +// Route for mimirtool // swagger:route DELETE /convert/prometheus/config/v1/rules/{NamespaceTitle} convert_prometheus RouteConvertPrometheusDeleteNamespace // // Deletes all rule groups that were imported from Prometheus-compatible sources within the specified namespace. @@ -70,6 +134,19 @@ import ( // 202: ConvertPrometheusResponse // 403: ForbiddenError +// Route for cortextool +// swagger:route DELETE /convert/api/prom/rules/{NamespaceTitle} convert_prometheus RouteConvertPrometheusCortexDeleteNamespace +// +// Deletes all rule groups that were imported from Prometheus-compatible sources within the specified namespace. +// +// Produces: +// - application/json +// +// Responses: +// 202: ConvertPrometheusResponse +// 403: ForbiddenError + +// Route for mimirtool // swagger:route DELETE /convert/prometheus/config/v1/rules/{NamespaceTitle}/{Group} convert_prometheus RouteConvertPrometheusDeleteRuleGroup // // Deletes a specific rule group if it was imported from a Prometheus-compatible source. @@ -81,7 +158,19 @@ import ( // 202: ConvertPrometheusResponse // 403: ForbiddenError -// swagger:parameters RouteConvertPrometheusPostRuleGroup +// Route for cortextool +// swagger:route DELETE /convert/api/prom/rules/{NamespaceTitle}/{Group} convert_prometheus RouteConvertPrometheusCortexDeleteRuleGroup +// +// Deletes a specific rule group if it was imported from a Prometheus-compatible source. +// +// Produces: +// - application/json +// +// Responses: +// 202: ConvertPrometheusResponse +// 403: ForbiddenError + +// swagger:parameters RouteConvertPrometheusPostRuleGroup RouteConvertPrometheusCortexPostRuleGroup type RouteConvertPrometheusPostRuleGroupParams struct { // in: path NamespaceTitle string @@ -119,7 +208,7 @@ type PrometheusRule struct { Record string `yaml:"record,omitempty"` } -// swagger:parameters RouteConvertPrometheusDeleteRuleGroup RouteConvertPrometheusGetRuleGroup +// swagger:parameters RouteConvertPrometheusDeleteRuleGroup RouteConvertPrometheusCortexDeleteRuleGroup RouteConvertPrometheusGetRuleGroup RouteConvertPrometheusCortexGetRuleGroup type RouteConvertPrometheusDeleteRuleGroupParams struct { // in: path NamespaceTitle string @@ -127,7 +216,7 @@ type RouteConvertPrometheusDeleteRuleGroupParams struct { Group string } -// swagger:parameters RouteConvertPrometheusDeleteNamespace RouteConvertPrometheusGetNamespace +// swagger:parameters RouteConvertPrometheusDeleteNamespace RouteConvertPrometheusCortexDeleteNamespace RouteConvertPrometheusGetNamespace RouteConvertPrometheusCortexGetNamespace type RouteConvertPrometheusDeleteNamespaceParams struct { // in: path NamespaceTitle string diff --git a/pkg/services/ngalert/api/tooling/post.json b/pkg/services/ngalert/api/tooling/post.json index b48c13e2d7e..ab2b7542381 100644 --- a/pkg/services/ngalert/api/tooling/post.json +++ b/pkg/services/ngalert/api/tooling/post.json @@ -4493,6 +4493,7 @@ "type": "object" }, "URL": { + "description": "The general form represented is:\n\n[scheme:][//[userinfo@]host][/]path[?query][#fragment]\n\nURLs that do not start with a slash after the scheme are interpreted as:\n\nscheme:opaque[?query][#fragment]\n\nThe Host field contains the host and port subcomponents of the URL.\nWhen the port is present, it is separated from the host with a colon.\nWhen the host is an IPv6 address, it must be enclosed in square brackets:\n\"[fe80::1]:80\". The [net.JoinHostPort] function combines a host and port\ninto a string suitable for the Host field, adding square brackets to\nthe host when necessary.\n\nNote that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/.\nA consequence is that it is impossible to tell which slashes in the Path were\nslashes in the raw URL and which were %2f. This distinction is rarely important,\nbut when it is, the code should use the [URL.EscapedPath] method, which preserves\nthe original encoding of Path.\n\nThe RawPath field is an optional field which is only set when the default\nencoding of Path is different from the escaped path. See the EscapedPath method\nfor more details.\n\nURL's String method uses the EscapedPath method to obtain the path.", "properties": { "ForceQuery": { "type": "boolean" @@ -4528,7 +4529,7 @@ "$ref": "#/definitions/Userinfo" } }, - "title": "URL is a custom URL type that allows validation at configuration load time.", + "title": "A URL represents a parsed URL (technically, a URI reference).", "type": "object" }, "UpdateRuleGroupResponse": { @@ -4770,6 +4771,7 @@ "type": "object" }, "alertGroups": { + "description": "AlertGroups alert groups", "items": { "$ref": "#/definitions/alertGroup", "type": "object" @@ -5056,6 +5058,7 @@ "type": "object" }, "gettableSilences": { + "description": "GettableSilences gettable silences", "items": { "$ref": "#/definitions/gettableSilence", "type": "object" @@ -6398,6 +6401,253 @@ ] } }, + "/convert/api/prom/rules": { + "get": { + "operationId": "RouteConvertPrometheusCortexGetRules", + "produces": [ + "application/yaml" + ], + "responses": { + "200": { + "description": "PrometheusNamespace", + "schema": { + "$ref": "#/definitions/PrometheusNamespace" + } + }, + "403": { + "description": "ForbiddenError", + "schema": { + "$ref": "#/definitions/ForbiddenError" + } + }, + "404": { + "description": "NotFound", + "schema": { + "$ref": "#/definitions/NotFound" + } + } + }, + "summary": "Gets all Grafana-managed alert rules that were imported from Prometheus-compatible sources, grouped by namespace.", + "tags": [ + "convert_prometheus" + ] + } + }, + "/convert/api/prom/rules/{NamespaceTitle}": { + "delete": { + "operationId": "RouteConvertPrometheusCortexDeleteNamespace", + "parameters": [ + { + "in": "path", + "name": "NamespaceTitle", + "required": true, + "type": "string" + } + ], + "produces": [ + "application/json" + ], + "responses": { + "202": { + "description": "ConvertPrometheusResponse", + "schema": { + "$ref": "#/definitions/ConvertPrometheusResponse" + } + }, + "403": { + "description": "ForbiddenError", + "schema": { + "$ref": "#/definitions/ForbiddenError" + } + } + }, + "summary": "Deletes all rule groups that were imported from Prometheus-compatible sources within the specified namespace.", + "tags": [ + "convert_prometheus" + ] + }, + "get": { + "operationId": "RouteConvertPrometheusCortexGetNamespace", + "parameters": [ + { + "in": "path", + "name": "NamespaceTitle", + "required": true, + "type": "string" + } + ], + "produces": [ + "application/yaml" + ], + "responses": { + "200": { + "description": "PrometheusNamespace", + "schema": { + "$ref": "#/definitions/PrometheusNamespace" + } + }, + "403": { + "description": "ForbiddenError", + "schema": { + "$ref": "#/definitions/ForbiddenError" + } + }, + "404": { + "description": "NotFound", + "schema": { + "$ref": "#/definitions/NotFound" + } + } + }, + "summary": "Gets Grafana-managed alert rules that were imported from Prometheus-compatible sources for a specified namespace (folder).", + "tags": [ + "convert_prometheus" + ] + }, + "post": { + "consumes": [ + "application/yaml" + ], + "description": "If the group already exists and was not imported from a Prometheus-compatible source initially,\nit will not be replaced and an error will be returned.", + "operationId": "RouteConvertPrometheusCortexPostRuleGroup", + "parameters": [ + { + "in": "path", + "name": "NamespaceTitle", + "required": true, + "type": "string" + }, + { + "in": "header", + "name": "x-grafana-alerting-datasource-uid", + "type": "string" + }, + { + "in": "header", + "name": "x-grafana-alerting-recording-rules-paused", + "type": "boolean" + }, + { + "in": "header", + "name": "x-grafana-alerting-alert-rules-paused", + "type": "boolean" + }, + { + "in": "body", + "name": "Body", + "schema": { + "$ref": "#/definitions/PrometheusRuleGroup" + } + } + ], + "produces": [ + "application/json" + ], + "responses": { + "202": { + "description": "ConvertPrometheusResponse", + "schema": { + "$ref": "#/definitions/ConvertPrometheusResponse" + } + }, + "403": { + "description": "ForbiddenError", + "schema": { + "$ref": "#/definitions/ForbiddenError" + } + } + }, + "summary": "Converts a Prometheus rule group into a Grafana rule group and creates or updates it within the specified namespace.", + "tags": [ + "convert_prometheus" + ], + "x-raw-request": "true" + } + }, + "/convert/api/prom/rules/{NamespaceTitle}/{Group}": { + "delete": { + "operationId": "RouteConvertPrometheusCortexDeleteRuleGroup", + "parameters": [ + { + "in": "path", + "name": "NamespaceTitle", + "required": true, + "type": "string" + }, + { + "in": "path", + "name": "Group", + "required": true, + "type": "string" + } + ], + "produces": [ + "application/json" + ], + "responses": { + "202": { + "description": "ConvertPrometheusResponse", + "schema": { + "$ref": "#/definitions/ConvertPrometheusResponse" + } + }, + "403": { + "description": "ForbiddenError", + "schema": { + "$ref": "#/definitions/ForbiddenError" + } + } + }, + "summary": "Deletes a specific rule group if it was imported from a Prometheus-compatible source.", + "tags": [ + "convert_prometheus" + ] + }, + "get": { + "operationId": "RouteConvertPrometheusCortexGetRuleGroup", + "parameters": [ + { + "in": "path", + "name": "NamespaceTitle", + "required": true, + "type": "string" + }, + { + "in": "path", + "name": "Group", + "required": true, + "type": "string" + } + ], + "produces": [ + "application/yaml" + ], + "responses": { + "200": { + "description": "PrometheusRuleGroup", + "schema": { + "$ref": "#/definitions/PrometheusRuleGroup" + } + }, + "403": { + "description": "ForbiddenError", + "schema": { + "$ref": "#/definitions/ForbiddenError" + } + }, + "404": { + "description": "NotFound", + "schema": { + "$ref": "#/definitions/NotFound" + } + } + }, + "summary": "Gets a single rule group in Prometheus-compatible format if it was imported from a Prometheus-compatible source.", + "tags": [ + "convert_prometheus" + ] + } + }, "/convert/prometheus/config/v1/rules": { "get": { "operationId": "RouteConvertPrometheusGetRules", diff --git a/pkg/services/ngalert/api/tooling/spec.json b/pkg/services/ngalert/api/tooling/spec.json index 571a497cc6b..1b251c81f29 100644 --- a/pkg/services/ngalert/api/tooling/spec.json +++ b/pkg/services/ngalert/api/tooling/spec.json @@ -1102,6 +1102,253 @@ } } }, + "/convert/api/prom/rules": { + "get": { + "produces": [ + "application/yaml" + ], + "tags": [ + "convert_prometheus" + ], + "summary": "Gets all Grafana-managed alert rules that were imported from Prometheus-compatible sources, grouped by namespace.", + "operationId": "RouteConvertPrometheusCortexGetRules", + "responses": { + "200": { + "description": "PrometheusNamespace", + "schema": { + "$ref": "#/definitions/PrometheusNamespace" + } + }, + "403": { + "description": "ForbiddenError", + "schema": { + "$ref": "#/definitions/ForbiddenError" + } + }, + "404": { + "description": "NotFound", + "schema": { + "$ref": "#/definitions/NotFound" + } + } + } + } + }, + "/convert/api/prom/rules/{NamespaceTitle}": { + "get": { + "produces": [ + "application/yaml" + ], + "tags": [ + "convert_prometheus" + ], + "summary": "Gets Grafana-managed alert rules that were imported from Prometheus-compatible sources for a specified namespace (folder).", + "operationId": "RouteConvertPrometheusCortexGetNamespace", + "parameters": [ + { + "type": "string", + "name": "NamespaceTitle", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "PrometheusNamespace", + "schema": { + "$ref": "#/definitions/PrometheusNamespace" + } + }, + "403": { + "description": "ForbiddenError", + "schema": { + "$ref": "#/definitions/ForbiddenError" + } + }, + "404": { + "description": "NotFound", + "schema": { + "$ref": "#/definitions/NotFound" + } + } + } + }, + "post": { + "description": "If the group already exists and was not imported from a Prometheus-compatible source initially,\nit will not be replaced and an error will be returned.", + "consumes": [ + "application/yaml" + ], + "produces": [ + "application/json" + ], + "tags": [ + "convert_prometheus" + ], + "summary": "Converts a Prometheus rule group into a Grafana rule group and creates or updates it within the specified namespace.", + "operationId": "RouteConvertPrometheusCortexPostRuleGroup", + "parameters": [ + { + "type": "string", + "name": "NamespaceTitle", + "in": "path", + "required": true + }, + { + "type": "string", + "name": "x-grafana-alerting-datasource-uid", + "in": "header" + }, + { + "type": "boolean", + "name": "x-grafana-alerting-recording-rules-paused", + "in": "header" + }, + { + "type": "boolean", + "name": "x-grafana-alerting-alert-rules-paused", + "in": "header" + }, + { + "name": "Body", + "in": "body", + "schema": { + "$ref": "#/definitions/PrometheusRuleGroup" + } + } + ], + "responses": { + "202": { + "description": "ConvertPrometheusResponse", + "schema": { + "$ref": "#/definitions/ConvertPrometheusResponse" + } + }, + "403": { + "description": "ForbiddenError", + "schema": { + "$ref": "#/definitions/ForbiddenError" + } + } + }, + "x-raw-request": "true" + }, + "delete": { + "produces": [ + "application/json" + ], + "tags": [ + "convert_prometheus" + ], + "summary": "Deletes all rule groups that were imported from Prometheus-compatible sources within the specified namespace.", + "operationId": "RouteConvertPrometheusCortexDeleteNamespace", + "parameters": [ + { + "type": "string", + "name": "NamespaceTitle", + "in": "path", + "required": true + } + ], + "responses": { + "202": { + "description": "ConvertPrometheusResponse", + "schema": { + "$ref": "#/definitions/ConvertPrometheusResponse" + } + }, + "403": { + "description": "ForbiddenError", + "schema": { + "$ref": "#/definitions/ForbiddenError" + } + } + } + } + }, + "/convert/api/prom/rules/{NamespaceTitle}/{Group}": { + "get": { + "produces": [ + "application/yaml" + ], + "tags": [ + "convert_prometheus" + ], + "summary": "Gets a single rule group in Prometheus-compatible format if it was imported from a Prometheus-compatible source.", + "operationId": "RouteConvertPrometheusCortexGetRuleGroup", + "parameters": [ + { + "type": "string", + "name": "NamespaceTitle", + "in": "path", + "required": true + }, + { + "type": "string", + "name": "Group", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "PrometheusRuleGroup", + "schema": { + "$ref": "#/definitions/PrometheusRuleGroup" + } + }, + "403": { + "description": "ForbiddenError", + "schema": { + "$ref": "#/definitions/ForbiddenError" + } + }, + "404": { + "description": "NotFound", + "schema": { + "$ref": "#/definitions/NotFound" + } + } + } + }, + "delete": { + "produces": [ + "application/json" + ], + "tags": [ + "convert_prometheus" + ], + "summary": "Deletes a specific rule group if it was imported from a Prometheus-compatible source.", + "operationId": "RouteConvertPrometheusCortexDeleteRuleGroup", + "parameters": [ + { + "type": "string", + "name": "NamespaceTitle", + "in": "path", + "required": true + }, + { + "type": "string", + "name": "Group", + "in": "path", + "required": true + } + ], + "responses": { + "202": { + "description": "ConvertPrometheusResponse", + "schema": { + "$ref": "#/definitions/ConvertPrometheusResponse" + } + }, + "403": { + "description": "ForbiddenError", + "schema": { + "$ref": "#/definitions/ForbiddenError" + } + } + } + } + }, "/convert/prometheus/config/v1/rules": { "get": { "produces": [ @@ -8434,8 +8681,9 @@ } }, "URL": { + "description": "The general form represented is:\n\n[scheme:][//[userinfo@]host][/]path[?query][#fragment]\n\nURLs that do not start with a slash after the scheme are interpreted as:\n\nscheme:opaque[?query][#fragment]\n\nThe Host field contains the host and port subcomponents of the URL.\nWhen the port is present, it is separated from the host with a colon.\nWhen the host is an IPv6 address, it must be enclosed in square brackets:\n\"[fe80::1]:80\". The [net.JoinHostPort] function combines a host and port\ninto a string suitable for the Host field, adding square brackets to\nthe host when necessary.\n\nNote that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/.\nA consequence is that it is impossible to tell which slashes in the Path were\nslashes in the raw URL and which were %2f. This distinction is rarely important,\nbut when it is, the code should use the [URL.EscapedPath] method, which preserves\nthe original encoding of Path.\n\nThe RawPath field is an optional field which is only set when the default\nencoding of Path is different from the escaped path. See the EscapedPath method\nfor more details.\n\nURL's String method uses the EscapedPath method to obtain the path.", "type": "object", - "title": "URL is a custom URL type that allows validation at configuration load time.", + "title": "A URL represents a parsed URL (technically, a URI reference).", "properties": { "ForceQuery": { "type": "boolean" @@ -8711,6 +8959,7 @@ } }, "alertGroups": { + "description": "AlertGroups alert groups", "type": "array", "items": { "type": "object", @@ -8997,6 +9246,7 @@ } }, "gettableSilences": { + "description": "GettableSilences gettable silences", "type": "array", "items": { "type": "object", diff --git a/pkg/tests/api/alerting/api_convert_prometheus_test.go b/pkg/tests/api/alerting/api_convert_prometheus_test.go index c92d5f8e428..cb248fba7f3 100644 --- a/pkg/tests/api/alerting/api_convert_prometheus_test.go +++ b/pkg/tests/api/alerting/api_convert_prometheus_test.go @@ -99,283 +99,315 @@ var ( ) func TestIntegrationConvertPrometheusEndpoints(t *testing.T) { - testinfra.SQLiteIntegrationTest(t) + runTest := func(t *testing.T, enableLokiPaths bool) { + testinfra.SQLiteIntegrationTest(t) - // Setup Grafana and its Database - dir, gpath := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ - DisableLegacyAlerting: true, - EnableUnifiedAlerting: true, - DisableAnonymous: true, - AppModeProduction: true, - EnableFeatureToggles: []string{"alertingConversionAPI"}, + // Setup Grafana and its Database + dir, gpath := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ + DisableLegacyAlerting: true, + EnableUnifiedAlerting: true, + DisableAnonymous: true, + AppModeProduction: true, + EnableFeatureToggles: []string{"alertingConversionAPI"}, + }) + + grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, gpath) + + // Create users to make authenticated requests + createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ + DefaultOrgRole: string(org.RoleAdmin), + Password: "password", + Login: "admin", + }) + apiClient := newAlertingApiClient(grafanaListedAddr, "admin", "password") + apiClient.prometheusConversionUseLokiPaths = enableLokiPaths + + createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ + DefaultOrgRole: string(org.RoleViewer), + Password: "password", + Login: "viewer", + }) + viewerClient := newAlertingApiClient(grafanaListedAddr, "viewer", "password") + + namespace1 := "test-namespace-1" + namespace2 := "test-namespace-2" + + ds := apiClient.CreateDatasource(t, datasources.DS_PROMETHEUS) + + t.Run("create rule groups and get them back", func(t *testing.T) { + _, status, body := apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup1, nil) + requireStatusCode(t, http.StatusAccepted, status, body) + _, status, body = apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup2, nil) + requireStatusCode(t, http.StatusAccepted, status, body) + + // create a third group in a different namespace + _, status, body = apiClient.ConvertPrometheusPostRuleGroup(t, namespace2, ds.Body.Datasource.UID, promGroup3, nil) + requireStatusCode(t, http.StatusAccepted, status, body) + + // And a non-provisioned rule in another namespace + namespace3UID := util.GenerateShortUID() + apiClient.CreateFolder(t, namespace3UID, "folder") + createRule(t, apiClient, namespace3UID) + + // Now get the first group + group1 := apiClient.ConvertPrometheusGetRuleGroupRules(t, namespace1, promGroup1.Name) + require.Equal(t, promGroup1, group1) + + // Get namespace1 + ns1 := apiClient.ConvertPrometheusGetNamespaceRules(t, namespace1) + expectedNs1 := map[string][]apimodels.PrometheusRuleGroup{ + namespace1: {promGroup1, promGroup2}, + } + require.Equal(t, expectedNs1, ns1) + + // Get all namespaces + namespaces := apiClient.ConvertPrometheusGetAllRules(t) + expectedNamespaces := map[string][]apimodels.PrometheusRuleGroup{ + namespace1: {promGroup1, promGroup2}, + namespace2: {promGroup3}, + } + require.Equal(t, expectedNamespaces, namespaces) + }) + + t.Run("without permissions to create folders cannot create rule groups either", func(t *testing.T) { + _, status, raw := viewerClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup1, nil) + requireStatusCode(t, http.StatusForbidden, status, raw) + }) + + t.Run("delete one rule group", func(t *testing.T) { + _, status, body := apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup1, nil) + requireStatusCode(t, http.StatusAccepted, status, body) + _, status, body = apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup2, nil) + requireStatusCode(t, http.StatusAccepted, status, body) + _, status, body = apiClient.ConvertPrometheusPostRuleGroup(t, namespace2, ds.Body.Datasource.UID, promGroup3, nil) + requireStatusCode(t, http.StatusAccepted, status, body) + + apiClient.ConvertPrometheusDeleteRuleGroup(t, namespace1, promGroup1.Name) + + // Check that the promGroup2 and promGroup3 are still there + namespaces := apiClient.ConvertPrometheusGetAllRules(t) + expectedNamespaces := map[string][]apimodels.PrometheusRuleGroup{ + namespace1: {promGroup2}, + namespace2: {promGroup3}, + } + require.Equal(t, expectedNamespaces, namespaces) + + // Delete the second namespace + apiClient.ConvertPrometheusDeleteNamespace(t, namespace2) + + // Check that only the first namespace is left + namespaces = apiClient.ConvertPrometheusGetAllRules(t) + expectedNamespaces = map[string][]apimodels.PrometheusRuleGroup{ + namespace1: {promGroup2}, + } + require.Equal(t, expectedNamespaces, namespaces) + }) + } + + t.Run("with the mimirtool paths", func(t *testing.T) { + runTest(t, false) }) - grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, gpath) - - // Create users to make authenticated requests - createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ - DefaultOrgRole: string(org.RoleAdmin), - Password: "password", - Login: "admin", - }) - apiClient := newAlertingApiClient(grafanaListedAddr, "admin", "password") - - createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ - DefaultOrgRole: string(org.RoleViewer), - Password: "password", - Login: "viewer", - }) - viewerClient := newAlertingApiClient(grafanaListedAddr, "viewer", "password") - - namespace1 := "test-namespace-1" - namespace2 := "test-namespace-2" - - ds := apiClient.CreateDatasource(t, datasources.DS_PROMETHEUS) - - t.Run("create rule groups and get them back", func(t *testing.T) { - _, status, body := apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup1, nil) - requireStatusCode(t, http.StatusAccepted, status, body) - _, status, body = apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup2, nil) - requireStatusCode(t, http.StatusAccepted, status, body) - - // create a third group in a different namespace - _, status, body = apiClient.ConvertPrometheusPostRuleGroup(t, namespace2, ds.Body.Datasource.UID, promGroup3, nil) - requireStatusCode(t, http.StatusAccepted, status, body) - - // And a non-provisioned rule in another namespace - namespace3UID := util.GenerateShortUID() - apiClient.CreateFolder(t, namespace3UID, "folder") - createRule(t, apiClient, namespace3UID) - - // Now get the first group - group1 := apiClient.ConvertPrometheusGetRuleGroupRules(t, namespace1, promGroup1.Name) - require.Equal(t, promGroup1, group1) - - // Get namespace1 - ns1 := apiClient.ConvertPrometheusGetNamespaceRules(t, namespace1) - expectedNs1 := map[string][]apimodels.PrometheusRuleGroup{ - namespace1: {promGroup1, promGroup2}, - } - require.Equal(t, expectedNs1, ns1) - - // Get all namespaces - namespaces := apiClient.ConvertPrometheusGetAllRules(t) - expectedNamespaces := map[string][]apimodels.PrometheusRuleGroup{ - namespace1: {promGroup1, promGroup2}, - namespace2: {promGroup3}, - } - require.Equal(t, expectedNamespaces, namespaces) - }) - - t.Run("without permissions to create folders cannot create rule groups either", func(t *testing.T) { - _, status, raw := viewerClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup1, nil) - requireStatusCode(t, http.StatusForbidden, status, raw) - }) - - t.Run("delete one rule group", func(t *testing.T) { - _, status, body := apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup1, nil) - requireStatusCode(t, http.StatusAccepted, status, body) - _, status, body = apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup2, nil) - requireStatusCode(t, http.StatusAccepted, status, body) - _, status, body = apiClient.ConvertPrometheusPostRuleGroup(t, namespace2, ds.Body.Datasource.UID, promGroup3, nil) - requireStatusCode(t, http.StatusAccepted, status, body) - - apiClient.ConvertPrometheusDeleteRuleGroup(t, namespace1, promGroup1.Name) - - // Check that the promGroup2 and promGroup3 are still there - namespaces := apiClient.ConvertPrometheusGetAllRules(t) - expectedNamespaces := map[string][]apimodels.PrometheusRuleGroup{ - namespace1: {promGroup2}, - namespace2: {promGroup3}, - } - require.Equal(t, expectedNamespaces, namespaces) - - // Delete the second namespace - apiClient.ConvertPrometheusDeleteNamespace(t, namespace2) - - // Check that only the first namespace is left - namespaces = apiClient.ConvertPrometheusGetAllRules(t) - expectedNamespaces = map[string][]apimodels.PrometheusRuleGroup{ - namespace1: {promGroup2}, - } - require.Equal(t, expectedNamespaces, namespaces) + t.Run("with the cortextool Loki paths", func(t *testing.T) { + runTest(t, true) }) } func TestIntegrationConvertPrometheusEndpoints_Conflict(t *testing.T) { - testinfra.SQLiteIntegrationTest(t) + runTest := func(t *testing.T, enableLokiPaths bool) { + testinfra.SQLiteIntegrationTest(t) - // Setup Grafana and its Database - dir, gpath := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ - DisableLegacyAlerting: true, - EnableUnifiedAlerting: true, - DisableAnonymous: true, - AppModeProduction: true, - EnableFeatureToggles: []string{"alertingConversionAPI"}, - }) + // Setup Grafana and its Database + dir, gpath := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ + DisableLegacyAlerting: true, + EnableUnifiedAlerting: true, + DisableAnonymous: true, + AppModeProduction: true, + EnableFeatureToggles: []string{"alertingConversionAPI"}, + }) - grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, gpath) + grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, gpath) - // Create users to make authenticated requests - createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ - DefaultOrgRole: string(org.RoleAdmin), - Password: "password", - Login: "admin", - }) - apiClient := newAlertingApiClient(grafanaListedAddr, "admin", "password") + // Create users to make authenticated requests + createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ + DefaultOrgRole: string(org.RoleAdmin), + Password: "password", + Login: "admin", + }) + apiClient := newAlertingApiClient(grafanaListedAddr, "admin", "password") + apiClient.prometheusConversionUseLokiPaths = enableLokiPaths - createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ - DefaultOrgRole: string(org.RoleViewer), - Password: "password", - Login: "viewer", - }) + createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ + DefaultOrgRole: string(org.RoleViewer), + Password: "password", + Login: "viewer", + }) - namespace1 := "test-namespace-1" + namespace1 := "test-namespace-1" - ds := apiClient.CreateDatasource(t, datasources.DS_PROMETHEUS) + ds := apiClient.CreateDatasource(t, datasources.DS_PROMETHEUS) - t.Run("cannot overwrite a rule group with different provenance", func(t *testing.T) { - // Create a rule group using the provisioning API and then try to overwrite it - // using the Prometheus Conversion API. It should fail because the provenance - // we set for rules in these two APIs is different and we check that when updating. - provisionedRuleGroup := apimodels.AlertRuleGroup{ - Title: promGroup1.Name, - Interval: 60, - FolderUID: namespace1, - Rules: []apimodels.ProvisionedAlertRule{ - { - Title: "Rule1", - OrgID: 1, - RuleGroup: promGroup1.Name, - Condition: "A", - NoDataState: apimodels.Alerting, - ExecErrState: apimodels.AlertingErrState, - For: prommodel.Duration(time.Duration(60) * time.Second), - Data: []apimodels.AlertQuery{ - { - RefID: "A", - RelativeTimeRange: apimodels.RelativeTimeRange{ - From: apimodels.Duration(time.Duration(5) * time.Hour), - To: apimodels.Duration(time.Duration(3) * time.Hour), + t.Run("cannot overwrite a rule group with different provenance", func(t *testing.T) { + // Create a rule group using the provisioning API and then try to overwrite it + // using the Prometheus Conversion API. It should fail because the provenance + // we set for rules in these two APIs is different and we check that when updating. + provisionedRuleGroup := apimodels.AlertRuleGroup{ + Title: promGroup1.Name, + Interval: 60, + FolderUID: namespace1, + Rules: []apimodels.ProvisionedAlertRule{ + { + Title: "Rule1", + OrgID: 1, + RuleGroup: promGroup1.Name, + Condition: "A", + NoDataState: apimodels.Alerting, + ExecErrState: apimodels.AlertingErrState, + For: prommodel.Duration(time.Duration(60) * time.Second), + Data: []apimodels.AlertQuery{ + { + RefID: "A", + RelativeTimeRange: apimodels.RelativeTimeRange{ + From: apimodels.Duration(time.Duration(5) * time.Hour), + To: apimodels.Duration(time.Duration(3) * time.Hour), + }, + DatasourceUID: expr.DatasourceUID, + Model: json.RawMessage([]byte(`{"type":"math","expression":"2 + 3 \u003e 1"}`)), }, - DatasourceUID: expr.DatasourceUID, - Model: json.RawMessage([]byte(`{"type":"math","expression":"2 + 3 \u003e 1"}`)), }, }, }, - }, - } + } - // Create the folder - apiClient.CreateFolder(t, namespace1, namespace1) - // Create rule in the root folder using another API - _, status, response := apiClient.CreateOrUpdateRuleGroupProvisioning(t, provisionedRuleGroup) - require.Equalf(t, http.StatusOK, status, response) + // Create the folder + apiClient.CreateFolder(t, namespace1, namespace1) + // Create rule in the root folder using another API + _, status, response := apiClient.CreateOrUpdateRuleGroupProvisioning(t, provisionedRuleGroup) + require.Equalf(t, http.StatusOK, status, response) - // Should fail to post the group - _, status, body := apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup1, nil) - requireStatusCode(t, http.StatusConflict, status, body) + // Should fail to post the group + _, status, body := apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup1, nil) + requireStatusCode(t, http.StatusConflict, status, body) + }) + } + + t.Run("with the mimirtool paths", func(t *testing.T) { + runTest(t, false) + }) + + t.Run("with the cortextool Loki paths", func(t *testing.T) { + runTest(t, true) }) } func TestIntegrationConvertPrometheusEndpoints_CreatePausedRules(t *testing.T) { - testinfra.SQLiteIntegrationTest(t) + runTest := func(t *testing.T, enableLokiPaths bool) { + testinfra.SQLiteIntegrationTest(t) - // Setup Grafana and its Database - dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ - DisableLegacyAlerting: true, - EnableUnifiedAlerting: true, - DisableAnonymous: true, - AppModeProduction: true, - EnableFeatureToggles: []string{"alertingConversionAPI"}, - }) + // Setup Grafana and its Database + dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ + DisableLegacyAlerting: true, + EnableUnifiedAlerting: true, + DisableAnonymous: true, + AppModeProduction: true, + EnableFeatureToggles: []string{"alertingConversionAPI"}, + }) - grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path) + grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path) - // Create users to make authenticated requests - createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ - DefaultOrgRole: string(org.RoleAdmin), - Password: "password", - Login: "admin", - }) - apiClient := newAlertingApiClient(grafanaListedAddr, "admin", "password") + // Create users to make authenticated requests + createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ + DefaultOrgRole: string(org.RoleAdmin), + Password: "password", + Login: "admin", + }) + apiClient := newAlertingApiClient(grafanaListedAddr, "admin", "password") - ds := apiClient.CreateDatasource(t, datasources.DS_PROMETHEUS) + ds := apiClient.CreateDatasource(t, datasources.DS_PROMETHEUS) - namespace1 := "test-namespace-1" + namespace1 := "test-namespace-1" - namespace1UID := util.GenerateShortUID() - apiClient.CreateFolder(t, namespace1UID, namespace1) + namespace1UID := util.GenerateShortUID() + apiClient.CreateFolder(t, namespace1UID, namespace1) - t.Run("when pausing header is set, rules should be paused", func(t *testing.T) { - tests := []struct { - name string - recordingPaused bool - alertPaused bool - }{ - { - name: "do not pause rules", - recordingPaused: false, - alertPaused: false, - }, - { - name: "pause recording rules", - recordingPaused: true, - alertPaused: false, - }, - { - name: "pause alert rules", - recordingPaused: false, - alertPaused: true, - }, - { - name: "pause both recording and alert rules", - recordingPaused: true, - alertPaused: true, - }, - } + t.Run("when pausing header is set, rules should be paused", func(t *testing.T) { + tests := []struct { + name string + recordingPaused bool + alertPaused bool + }{ + { + name: "do not pause rules", + recordingPaused: false, + alertPaused: false, + }, + { + name: "pause recording rules", + recordingPaused: true, + alertPaused: false, + }, + { + name: "pause alert rules", + recordingPaused: false, + alertPaused: true, + }, + { + name: "pause both recording and alert rules", + recordingPaused: true, + alertPaused: true, + }, + } - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - headers := map[string]string{} - if tc.recordingPaused { - headers["X-Grafana-Alerting-Recording-Rules-Paused"] = "true" - } - if tc.alertPaused { - headers["X-Grafana-Alerting-Alert-Rules-Paused"] = "true" - } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + headers := map[string]string{} + if tc.recordingPaused { + headers["X-Grafana-Alerting-Recording-Rules-Paused"] = "true" + } + if tc.alertPaused { + headers["X-Grafana-Alerting-Alert-Rules-Paused"] = "true" + } - apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup1, headers) + apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup1, headers) - gr, _, _ := apiClient.GetRulesGroupWithStatus(t, namespace1UID, promGroup1.Name) + gr, _, _ := apiClient.GetRulesGroupWithStatus(t, namespace1UID, promGroup1.Name) - require.Len(t, gr.Rules, 3) + require.Len(t, gr.Rules, 3) - pausedRecordingRules := 0 - pausedAlertRules := 0 + pausedRecordingRules := 0 + pausedAlertRules := 0 - for _, rule := range gr.Rules { - if rule.GrafanaManagedAlert.IsPaused { - if rule.GrafanaManagedAlert.Record != nil { - pausedRecordingRules++ - } else { - pausedAlertRules++ + for _, rule := range gr.Rules { + if rule.GrafanaManagedAlert.IsPaused { + if rule.GrafanaManagedAlert.Record != nil { + pausedRecordingRules++ + } else { + pausedAlertRules++ + } } } - } - if tc.recordingPaused { - require.Equal(t, 1, pausedRecordingRules) - } else { - require.Equal(t, 0, pausedRecordingRules) - } + if tc.recordingPaused { + require.Equal(t, 1, pausedRecordingRules) + } else { + require.Equal(t, 0, pausedRecordingRules) + } - if tc.alertPaused { - require.Equal(t, 2, pausedAlertRules) - } else { - require.Equal(t, 0, pausedAlertRules) - } - }) - } + if tc.alertPaused { + require.Equal(t, 2, pausedAlertRules) + } else { + require.Equal(t, 0, pausedAlertRules) + } + }) + } + }) + } + + t.Run("with the mimirtool paths", func(t *testing.T) { + runTest(t, false) + }) + + t.Run("with the cortextool Loki paths", func(t *testing.T) { + runTest(t, true) }) } diff --git a/pkg/tests/api/alerting/testing.go b/pkg/tests/api/alerting/testing.go index 6290339dd24..5e1e34f63bf 100644 --- a/pkg/tests/api/alerting/testing.go +++ b/pkg/tests/api/alerting/testing.go @@ -254,7 +254,8 @@ func convertGettableGrafanaRuleToPostable(gettable *apimodels.GettableGrafanaRul } type apiClient struct { - url string + url string + prometheusConversionUseLokiPaths bool } type LegacyApiClient struct { @@ -1121,7 +1122,13 @@ func (a apiClient) ConvertPrometheusPostRuleGroup(t *testing.T, namespaceTitle, func (a apiClient) ConvertPrometheusGetRuleGroupRules(t *testing.T, namespaceTitle, groupName string) apimodels.PrometheusRuleGroup { t.Helper() - req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/api/convert/prometheus/config/v1/rules/%s/%s", a.url, namespaceTitle, groupName), nil) + + path := "%s/api/convert/prometheus/config/v1/rules/%s/%s" + if a.prometheusConversionUseLokiPaths { + path = "%s/api/convert/api/prom/rules/%s/%s" + } + + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf(path, a.url, namespaceTitle, groupName), nil) require.NoError(t, err) rule, status, raw := sendRequestYAML[apimodels.PrometheusRuleGroup](t, req, http.StatusOK) requireStatusCode(t, http.StatusOK, status, raw) @@ -1130,7 +1137,13 @@ func (a apiClient) ConvertPrometheusGetRuleGroupRules(t *testing.T, namespaceTit func (a apiClient) ConvertPrometheusGetNamespaceRules(t *testing.T, namespaceTitle string) map[string][]apimodels.PrometheusRuleGroup { t.Helper() - req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/api/convert/prometheus/config/v1/rules/%s", a.url, namespaceTitle), nil) + + path := "%s/api/convert/prometheus/config/v1/rules/%s" + if a.prometheusConversionUseLokiPaths { + path = "%s/api/convert/api/prom/rules/%s" + } + + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf(path, a.url, namespaceTitle), nil) require.NoError(t, err) ns, status, raw := sendRequestYAML[map[string][]apimodels.PrometheusRuleGroup](t, req, http.StatusOK) requireStatusCode(t, http.StatusOK, status, raw) @@ -1139,7 +1152,13 @@ func (a apiClient) ConvertPrometheusGetNamespaceRules(t *testing.T, namespaceTit func (a apiClient) ConvertPrometheusGetAllRules(t *testing.T) map[string][]apimodels.PrometheusRuleGroup { t.Helper() - req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/api/convert/prometheus/config/v1/rules", a.url), nil) + + path := "%s/api/convert/prometheus/config/v1/rules" + if a.prometheusConversionUseLokiPaths { + path = "%s/api/convert/api/prom/rules" + } + + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf(path, a.url), nil) require.NoError(t, err) result, status, raw := sendRequestYAML[map[string][]apimodels.PrometheusRuleGroup](t, req, http.StatusOK) requireStatusCode(t, http.StatusOK, status, raw) @@ -1148,7 +1167,13 @@ func (a apiClient) ConvertPrometheusGetAllRules(t *testing.T) map[string][]apimo func (a apiClient) ConvertPrometheusDeleteRuleGroup(t *testing.T, namespaceTitle, groupName string) { t.Helper() - req, err := http.NewRequest(http.MethodDelete, fmt.Sprintf("%s/api/convert/prometheus/config/v1/rules/%s/%s", a.url, namespaceTitle, groupName), nil) + + path := "%s/api/convert/prometheus/config/v1/rules/%s/%s" + if a.prometheusConversionUseLokiPaths { + path = "%s/api/convert/api/prom/rules/%s/%s" + } + + req, err := http.NewRequest(http.MethodDelete, fmt.Sprintf(path, a.url, namespaceTitle, groupName), nil) require.NoError(t, err) _, status, raw := sendRequestJSON[apimodels.ConvertPrometheusResponse](t, req, http.StatusAccepted) requireStatusCode(t, http.StatusAccepted, status, raw) @@ -1156,7 +1181,13 @@ func (a apiClient) ConvertPrometheusDeleteRuleGroup(t *testing.T, namespaceTitle func (a apiClient) ConvertPrometheusDeleteNamespace(t *testing.T, namespaceTitle string) { t.Helper() - req, err := http.NewRequest(http.MethodDelete, fmt.Sprintf("%s/api/convert/prometheus/config/v1/rules/%s", a.url, namespaceTitle), nil) + + path := "%s/api/convert/prometheus/config/v1/rules/%s" + if a.prometheusConversionUseLokiPaths { + path = "%s/api/convert/api/prom/rules/%s" + } + + req, err := http.NewRequest(http.MethodDelete, fmt.Sprintf(path, a.url, namespaceTitle), nil) require.NoError(t, err) _, status, raw := sendRequestJSON[apimodels.ConvertPrometheusResponse](t, req, http.StatusAccepted) requireStatusCode(t, http.StatusAccepted, status, raw) diff --git a/public/api-merged.json b/public/api-merged.json index dc455b6a36f..9ddc287f6f6 100644 --- a/public/api-merged.json +++ b/public/api-merged.json @@ -22771,6 +22771,7 @@ } }, "gettableAlerts": { + "description": "GettableAlerts gettable alerts", "type": "array", "items": { "type": "object", diff --git a/public/openapi3.json b/public/openapi3.json index fabc90f92cf..8f339a39b59 100644 --- a/public/openapi3.json +++ b/public/openapi3.json @@ -12838,6 +12838,7 @@ "type": "object" }, "gettableAlerts": { + "description": "GettableAlerts gettable alerts", "items": { "$ref": "#/components/schemas/gettableAlert" }, From d78c646f93bb140a0b7790074c16aa7d76aa4940 Mon Sep 17 00:00:00 2001 From: Matias Chomicki Date: Thu, 27 Feb 2025 16:34:02 +0000 Subject: [PATCH 22/74] New Logs Panel: Log line menu (#101060) * Create LogLineMenu component * Fine tune icon width * LogLineMenu: Add placeholder options * utils: create reusable handleOpenLogsContextClick * LogLineMenu: add callbacks to menu items * LogListContext: create component * LogList: use log list context to connect menu callbacks * LogLine: add pinned style * Remove unused imports * LogLine: add unit test * LogLine: add menu test case * LogLineMenu: add unit test * LogLineMessage: add unit test * LogListContext: add unit test * Remove unused code * Extract translations * Fix handleOpenLogsContextClick * Chore: memoize styles * Virtualization: update node used for underflow detection * Use useStyles2 instead of manually memoizing * Virtualization: export getter instead of variable * Open context: move stopPropagation to the old panel code * Logs: add new container class --- public/app/features/explore/Logs/Logs.tsx | 13 ++- .../logs/components/LogRowMenuCell.tsx | 32 +----- .../logs/components/__mocks__/logRow.ts | 17 ++- .../logs/components/panel/InfiniteScroll.tsx | 5 +- .../logs/components/panel/LogLine.test.tsx | 105 ++++++++++++++++++ .../logs/components/panel/LogLine.tsx | 28 ++++- .../components/panel/LogLineMenu.test.tsx | 94 ++++++++++++++++ .../logs/components/panel/LogLineMenu.tsx | 102 +++++++++++++++++ .../components/panel/LogLineMessage.test.tsx | 32 ++++++ .../logs/components/panel/LogList.tsx | 83 ++++++++------ .../components/panel/LogListContext.test.tsx | 46 ++++++++ .../logs/components/panel/LogListContext.tsx | 33 ++++++ .../logs/components/panel/processing.ts | 2 +- .../logs/components/panel/virtualization.ts | 7 +- public/app/features/logs/utils.ts | 34 ++++++ public/locales/en-US/grafana.json | 8 ++ public/locales/pseudo-LOCALE/grafana.json | 8 ++ 17 files changed, 575 insertions(+), 74 deletions(-) create mode 100644 public/app/features/logs/components/panel/LogLine.test.tsx create mode 100644 public/app/features/logs/components/panel/LogLineMenu.test.tsx create mode 100644 public/app/features/logs/components/panel/LogLineMenu.tsx create mode 100644 public/app/features/logs/components/panel/LogLineMessage.test.tsx create mode 100644 public/app/features/logs/components/panel/LogListContext.test.tsx create mode 100644 public/app/features/logs/components/panel/LogListContext.tsx diff --git a/public/app/features/explore/Logs/Logs.tsx b/public/app/features/explore/Logs/Logs.tsx index 24bc46790a5..f5c6912b76f 100644 --- a/public/app/features/explore/Logs/Logs.tsx +++ b/public/app/features/explore/Logs/Logs.tsx @@ -1065,17 +1065,25 @@ const UnthemedLogs: React.FunctionComponent = (props: Props) => { )} {visualisationType === 'logs' && hasData && config.featureToggles.newLogsPanel && ( <> -
+
{logsContainerRef.current && ( void; - onPinToContentOutlineClick?: (row: LogRowModel, onOpenContext: (row: LogRowModel) => void) => void; addonBefore?: ReactNode[]; addonAfter?: ReactNode[]; } @@ -66,31 +66,9 @@ export const LogRowMenuCell = memo( e.stopPropagation(); }, []); const onShowContextClick = useCallback( - async (event: MouseEvent) => { + async (event: MouseEvent) => { event.stopPropagation(); - // if ctrl or meta key is pressed, open query in new Explore tab - if ( - getRowContextQuery && - (event.nativeEvent.ctrlKey || event.nativeEvent.metaKey || event.nativeEvent.shiftKey) - ) { - const win = window.open('about:blank'); - // for this request we don't want to use the cached filters from a context provider, but always want to refetch and clear - const query = await getRowContextQuery(row, undefined, false); - if (query && win) { - const url = urlUtil.renderUrl(locationUtil.assureBaseUrl(`${getConfig().appSubUrl}explore`), { - left: JSON.stringify({ - datasource: query.datasource, - queries: [query], - range: getDefaultTimeRange(), - }), - }); - win.location = url; - - return; - } - win?.close(); - } - onOpenContext(row); + handleOpenLogsContextClick(event, row, getRowContextQuery, onOpenContext); }, [onOpenContext, getRowContextQuery, row] ); diff --git a/public/app/features/logs/components/__mocks__/logRow.ts b/public/app/features/logs/components/__mocks__/logRow.ts index 0968f242a84..d7777eed731 100644 --- a/public/app/features/logs/components/__mocks__/logRow.ts +++ b/public/app/features/logs/components/__mocks__/logRow.ts @@ -1,4 +1,6 @@ -import { FieldType, LogLevel, LogRowModel, toDataFrame } from '@grafana/data'; +import { FieldType, LogLevel, LogRowModel, LogsSortOrder, toDataFrame } from '@grafana/data'; + +import { LogListModel, preProcessLogs, PreProcessOptions } from '../panel/processing'; export const createLogRow = (overrides?: Partial): LogRowModel => { const uid = overrides?.uid || '1'; @@ -36,3 +38,16 @@ export const createLogRow = (overrides?: Partial): LogRowModel => { ...overrides, }; }; + +export const createLogLine = ( + overrides?: Partial, + processOptions: PreProcessOptions = { + escape: false, + order: LogsSortOrder.Descending, + timeZone: 'browser', + wrap: false, + } +): LogListModel => { + const logs = preProcessLogs([createLogRow(overrides)], processOptions); + return logs[0]; +}; diff --git a/public/app/features/logs/components/panel/InfiniteScroll.tsx b/public/app/features/logs/components/panel/InfiniteScroll.tsx index 3790f5f0b0f..e09d67577e4 100644 --- a/public/app/features/logs/components/panel/InfiniteScroll.tsx +++ b/public/app/features/logs/components/panel/InfiniteScroll.tsx @@ -4,7 +4,7 @@ import { ListChildComponentProps, ListOnItemsRenderedProps } from 'react-window' import { AbsoluteTimeRange, LogsSortOrder, TimeRange } from '@grafana/data'; import { config, reportInteraction } from '@grafana/runtime'; -import { Spinner, useTheme2 } from '@grafana/ui'; +import { Spinner, useStyles2 } from '@grafana/ui'; import { t } from 'app/core/internationalization'; import { canScrollBottom, getVisibleRange, ScrollDirection, shouldLoadMore } from '../InfiniteScroll'; @@ -59,8 +59,7 @@ export const InfiniteScroll = ({ const lastEvent = useRef(null); const countRef = useRef(0); const lastLogOfPage = useRef([]); - const theme = useTheme2(); - const styles = getStyles(theme); + const styles = useStyles2(getStyles); useEffect(() => { // Logs have not changed, ignore effect diff --git a/public/app/features/logs/components/panel/LogLine.test.tsx b/public/app/features/logs/components/panel/LogLine.test.tsx new file mode 100644 index 00000000000..15640f13ea8 --- /dev/null +++ b/public/app/features/logs/components/panel/LogLine.test.tsx @@ -0,0 +1,105 @@ +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import { createTheme } from '@grafana/data'; + +import { LOG_LINE_BODY_FIELD_NAME } from '../LogDetailsBody'; +import { createLogLine } from '../__mocks__/logRow'; + +import { getStyles, LogLine } from './LogLine'; +import { LogListModel } from './processing'; + +const theme = createTheme(); +const styles = getStyles(theme); + +describe('LogLine', () => { + let log: LogListModel; + beforeEach(() => { + log = createLogLine({ labels: { place: 'luna' } }); + }); + + test('Renders a log line', () => { + render( + + ); + expect(screen.getByText(log.timestamp)).toBeInTheDocument(); + expect(screen.getByText(log.body)).toBeInTheDocument(); + }); + + test('Renders a log line with no timestamp', () => { + render( + + ); + expect(screen.queryByText(log.timestamp)).not.toBeInTheDocument(); + expect(screen.getByText(log.body)).toBeInTheDocument(); + }); + + test('Renders a log line with displayed fields', () => { + render( + + ); + expect(screen.getByText(log.timestamp)).toBeInTheDocument(); + expect(screen.queryByText(log.body)).not.toBeInTheDocument(); + expect(screen.getByText('luna')).toBeInTheDocument(); + }); + + test('Renders a log line with body displayed fields', () => { + render( + + ); + expect(screen.getByText(log.timestamp)).toBeInTheDocument(); + expect(screen.getByText(log.body)).toBeInTheDocument(); + expect(screen.getByText('luna')).toBeInTheDocument(); + }); + + describe('Log line menu', () => { + test('Renders a log line menu', async () => { + render( + + ); + expect(screen.queryByText('Copy log line')).not.toBeInTheDocument(); + await userEvent.click(screen.getByLabelText('Log menu')); + expect(screen.getByText('Copy log line')).toBeInTheDocument(); + }); + }); +}); diff --git a/public/app/features/logs/components/panel/LogLine.tsx b/public/app/features/logs/components/panel/LogLine.tsx index d484675d424..58004ccc456 100644 --- a/public/app/features/logs/components/panel/LogLine.tsx +++ b/public/app/features/logs/components/panel/LogLine.tsx @@ -1,12 +1,15 @@ import { css } from '@emotion/css'; import { CSSProperties, useEffect, useRef } from 'react'; +import tinycolor from 'tinycolor2'; import { GrafanaTheme2 } from '@grafana/data'; import { LOG_LINE_BODY_FIELD_NAME } from '../LogDetailsBody'; +import { LogLineMenu } from './LogLineMenu'; +import { useLogIsPinned } from './LogListContext'; import { LogFieldDimension, LogListModel } from './processing'; -import { FIELD_GAP_MULTIPLIER, hasUnderOrOverflow } from './virtualization'; +import { FIELD_GAP_MULTIPLIER, hasUnderOrOverflow, getLineHeight } from './virtualization'; interface Props { displayedFields: string[]; @@ -32,6 +35,7 @@ export const LogLine = ({ wrapLogMessage, }: Props) => { const logLineRef = useRef(null); + const pinned = useLogIsPinned(log); useEffect(() => { if (!onOverflow || !logLineRef.current) { @@ -45,7 +49,12 @@ export const LogLine = ({ }, [index, log.uid, onOverflow, style.height]); return ( -
+
+
@@ -57,7 +66,7 @@ interface LogProps { displayedFields: string[]; log: LogListModel; showTime: boolean; - styles: ReturnType; + styles: LogLineStyles; } const Log = ({ displayedFields, log, showTime, styles }: LogProps) => { @@ -67,7 +76,7 @@ const Log = ({ displayedFields, log, showTime, styles }: LogProps) => { {log.displayLevel} {displayedFields.length > 0 ? ( displayedFields.map((field) => ( - + {getDisplayedFieldValue(field, log)} )) @@ -111,6 +120,9 @@ export const getStyles = (theme: GrafanaTheme2) => { return { logLine: css({ color: theme.colors.text.primary, + display: 'flex', + gap: theme.spacing(0.5), + flexDirection: 'row', fontFamily: theme.typography.fontFamilyMonospace, fontSize: theme.typography.fontSize, wordBreak: 'break-all', @@ -129,6 +141,14 @@ export const getStyles = (theme: GrafanaTheme2) => { }, }, }), + pinnedLogLine: css({ + backgroundColor: tinycolor(theme.colors.info.transparent).setAlpha(0.25).toString(), + }), + menuIcon: css({ + height: getLineHeight(), + margin: 0, + padding: theme.spacing(0, 0, 0, 0.5), + }), logLineMessage: css({ fontFamily: theme.typography.fontFamily, textAlign: 'center', diff --git a/public/app/features/logs/components/panel/LogLineMenu.test.tsx b/public/app/features/logs/components/panel/LogLineMenu.test.tsx new file mode 100644 index 00000000000..27c8b78f9b9 --- /dev/null +++ b/public/app/features/logs/components/panel/LogLineMenu.test.tsx @@ -0,0 +1,94 @@ +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import { createTheme } from '@grafana/data'; + +import { createLogLine } from '../__mocks__/logRow'; + +import { getStyles } from './LogLine'; +import { LogLineMenu } from './LogLineMenu'; +import { LogListContext } from './LogListContext'; +import { LogListModel } from './processing'; + +const theme = createTheme(); +const styles = getStyles(theme); + +describe('LogLineMenu', () => { + let log: LogListModel; + beforeEach(() => { + log = createLogLine({ labels: { place: 'luna' }, rowId: '1' }); + }); + + test('Renders the component', async () => { + render(); + expect(screen.queryByText('Copy log line')).not.toBeInTheDocument(); + await userEvent.click(screen.getByLabelText('Log menu')); + expect(screen.getByText('Copy log line')).toBeInTheDocument(); + }); + + describe('Options', () => { + test('Allows to copy a permalink', async () => { + const onPermalinkClick = jest.fn(); + render( + + + + ); + await userEvent.click(screen.getByLabelText('Log menu')); + await userEvent.click(screen.getByText('Copy link to log line')); + expect(onPermalinkClick).toHaveBeenCalledTimes(1); + }); + + test('Allows to open show context', async () => { + const onOpenContext = jest.fn(); + const logSupportsContext = jest.fn().mockReturnValue(true); + const getRowContextQuery = jest.fn(); + render( + + + + ); + await userEvent.click(screen.getByLabelText('Log menu')); + await userEvent.click(screen.getByText('Show context')); + expect(onOpenContext).toHaveBeenCalledTimes(1); + }); + + test('Uses logSupportsContext to control the display of show context', async () => { + const onOpenContext = jest.fn(); + const logSupportsContext = jest.fn().mockReturnValue(false); + const getRowContextQuery = jest.fn(); + render( + + + + ); + await userEvent.click(screen.getByLabelText('Log menu')); + expect(screen.queryByText('Show context')).not.toBeInTheDocument(); + }); + + test('Allows to pin log line', async () => { + const onPinLine = jest.fn(); + render( + + + + ); + await userEvent.click(screen.getByLabelText('Log menu')); + await userEvent.click(screen.getByText('Pin log')); + expect(onPinLine).toHaveBeenCalledTimes(1); + }); + + test('Allows to unpin log line', async () => { + const onUnpinLine = jest.fn(); + render( + + + + ); + await userEvent.click(screen.getByLabelText('Log menu')); + expect(screen.queryByText('Pin log')).not.toBeInTheDocument(); + await userEvent.click(screen.getByText('Unpin log')); + expect(onUnpinLine).toHaveBeenCalledTimes(1); + }); + }); +}); diff --git a/public/app/features/logs/components/panel/LogLineMenu.tsx b/public/app/features/logs/components/panel/LogLineMenu.tsx new file mode 100644 index 00000000000..b10c2f17ec6 --- /dev/null +++ b/public/app/features/logs/components/panel/LogLineMenu.tsx @@ -0,0 +1,102 @@ +import { useCallback, useMemo, useRef, MouseEvent } from 'react'; + +import { LogRowContextOptions, LogRowModel } from '@grafana/data'; +import { DataQuery } from '@grafana/schema'; +import { Dropdown, IconButton, Menu } from '@grafana/ui'; +import { t } from 'app/core/internationalization'; + +import { copyText, handleOpenLogsContextClick } from '../../utils'; + +import { LogLineStyles } from './LogLine'; +import { useLogIsPinned, useLogListContext } from './LogListContext'; +import { LogListModel } from './processing'; + +export type GetRowContextQueryFn = ( + row: LogRowModel, + options?: LogRowContextOptions, + cacheFilters?: boolean +) => Promise; + +interface Props { + log: LogListModel; + styles: LogLineStyles; +} + +export const LogLineMenu = ({ log, styles }: Props) => { + const { getRowContextQuery, onOpenContext, onPermalinkClick, onPinLine, onUnpinLine, logSupportsContext } = + useLogListContext(); + const pinned = useLogIsPinned(log); + const menuRef = useRef(null); + + const copyLogLine = useCallback(() => { + copyText(log.entry, menuRef); + }, [log.entry]); + + const copyLinkToLogLine = useCallback(() => { + onPermalinkClick?.(log); + }, [log, onPermalinkClick]); + + const shouldlogSupportsContext = useMemo( + () => (logSupportsContext ? logSupportsContext(log) : false), + [log, logSupportsContext] + ); + + const showContext = useCallback( + async (event: MouseEvent) => { + handleOpenLogsContextClick(event, log, getRowContextQuery, (log: LogRowModel) => onOpenContext?.(log, () => {})); + }, + [onOpenContext, getRowContextQuery, log] + ); + + const togglePinning = useCallback(() => { + if (pinned) { + onUnpinLine?.(log); + } else { + onPinLine?.(log); + } + }, [log, onPinLine, onUnpinLine, pinned]); + + const menu = useCallback( + () => ( + + + {onPermalinkClick && log.rowId !== undefined && log.uid && ( + + )} + {(shouldlogSupportsContext || onPinLine || onUnpinLine) && } + {shouldlogSupportsContext && ( + + )} + {!pinned && onPinLine && ( + + )} + {pinned && onUnpinLine && ( + + )} + + ), + [ + copyLinkToLogLine, + copyLogLine, + log.rowId, + log.uid, + onPermalinkClick, + onPinLine, + onUnpinLine, + pinned, + shouldlogSupportsContext, + showContext, + togglePinning, + ] + ); + + return ( + + + + ); +}; diff --git a/public/app/features/logs/components/panel/LogLineMessage.test.tsx b/public/app/features/logs/components/panel/LogLineMessage.test.tsx new file mode 100644 index 00000000000..0034dac14aa --- /dev/null +++ b/public/app/features/logs/components/panel/LogLineMessage.test.tsx @@ -0,0 +1,32 @@ +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import { createTheme } from '@grafana/data'; + +import { getStyles } from './LogLine'; +import { LogLineMessage } from './LogLineMessage'; + +const theme = createTheme(); +const styles = getStyles(theme); + +describe('LogLineMessage', () => { + test('Renders a log line message', () => { + render( + + Message + + ); + expect(screen.getByText('Message')).toBeInTheDocument(); + }); + + test('Renders a button with the message', async () => { + const handleClick = jest.fn(); + render( + + Message + + ); + await userEvent.click(screen.getByText('Message')); + expect(handleClick).toHaveBeenCalledTimes(1); + }); +}); diff --git a/public/app/features/logs/components/panel/LogList.tsx b/public/app/features/logs/components/panel/LogList.tsx index abc48cbe9ce..ae8234bd060 100644 --- a/public/app/features/logs/components/panel/LogList.tsx +++ b/public/app/features/logs/components/panel/LogList.tsx @@ -14,10 +14,12 @@ import { LogsSortOrder, TimeRange, } from '@grafana/data'; -import { useTheme2 } from '@grafana/ui'; +import { PopoverContent, useTheme2 } from '@grafana/ui'; import { InfiniteScroll } from './InfiniteScroll'; import { getGridTemplateColumns } from './LogLine'; +import { GetRowContextQueryFn } from './LogLineMenu'; +import { LogListContext } from './LogListContext'; import { preProcessLogs, LogListModel, calculateFieldDimensions, LogFieldDimension } from './processing'; import { getLogLineSize, @@ -36,9 +38,17 @@ interface Props { eventBus: EventBus; forceEscape?: boolean; getFieldLinks?: GetFieldLinksFn; + getRowContextQuery?: GetRowContextQueryFn; initialScrollPosition?: 'top' | 'bottom'; loadMore?: (range: AbsoluteTimeRange) => void; logs: LogRowModel[]; + logSupportsContext?: (row: LogRowModel) => boolean; + onPermalinkClick?: (row: LogRowModel) => Promise; + onPinLine?: (row: LogRowModel) => void; + onOpenContext?: (row: LogRowModel, onClose: () => void) => void; + onUnpinLine?: (row: LogRowModel) => void; + pinLineButtonTooltipTitle?: PopoverContent; + pinnedLogs?: string[]; showTime: boolean; sortOrder: LogsSortOrder; timeRange: TimeRange; @@ -61,6 +71,7 @@ export const LogList = ({ timeRange, timeZone, wrapLogMessage, + ...logListContext }: Props) => { const [processedLogs, setProcessedLogs] = useState([]); const [listHeight, setListHeight] = useState( @@ -134,40 +145,42 @@ export const LogList = ({ } return ( - - {({ getItemKey, itemCount, onItemsRendered, Renderer }) => ( - - {Renderer} - - )} - + + + {({ getItemKey, itemCount, onItemsRendered, Renderer }) => ( + + {Renderer} + + )} + + ); }; diff --git a/public/app/features/logs/components/panel/LogListContext.test.tsx b/public/app/features/logs/components/panel/LogListContext.test.tsx new file mode 100644 index 00000000000..3505c554797 --- /dev/null +++ b/public/app/features/logs/components/panel/LogListContext.test.tsx @@ -0,0 +1,46 @@ +import { renderHook } from '@testing-library/react'; +import { ReactNode } from 'react'; + +import { createLogLine } from '../__mocks__/logRow'; + +import { useLogListContextData, useLogListContext, useLogIsPinned, LogListContext } from './LogListContext'; + +const log = createLogLine({ rowId: 'yep' }); +const value = { + getRowContextQuery: jest.fn(), + logSupportsContext: jest.fn(), + onPermalinkClick: jest.fn(), + onPinLine: jest.fn(), + onOpenContext: jest.fn(), + onUnpinLine: jest.fn(), + pinLineButtonTooltipTitle: 'test', + pinnedLogs: ['yep'], +}; +const wrapper = ({ children }: { children: ReactNode }) => ( + {children} +); + +test('Provides the Log List Context data', () => { + const { result } = renderHook(() => useLogListContext(), { wrapper }); + + expect(result.current).toEqual(value); +}); + +test('Allows to access context attributes', () => { + const { result } = renderHook(() => useLogListContextData('pinnedLogs'), { wrapper }); + + expect(result.current).toEqual(value.pinnedLogs); +}); + +test('Allows to tell if a log is pinned', () => { + const { result } = renderHook(() => useLogIsPinned(log), { wrapper }); + + expect(result.current).toBe(true); +}); + +test('Allows to tell if a log is pinned', () => { + const otherLog = createLogLine({ rowId: 'nope' }); + const { result } = renderHook(() => useLogIsPinned(otherLog), { wrapper }); + + expect(result.current).toBe(false); +}); diff --git a/public/app/features/logs/components/panel/LogListContext.tsx b/public/app/features/logs/components/panel/LogListContext.tsx new file mode 100644 index 00000000000..9f654cf4dce --- /dev/null +++ b/public/app/features/logs/components/panel/LogListContext.tsx @@ -0,0 +1,33 @@ +import { createContext, useContext } from 'react'; + +import { LogRowModel } from '@grafana/data'; +import { PopoverContent } from '@grafana/ui'; + +import { GetRowContextQueryFn } from './LogLineMenu'; + +export interface LogListContextData { + getRowContextQuery?: GetRowContextQueryFn; + logSupportsContext?: (row: LogRowModel) => boolean; + onPermalinkClick?: (row: LogRowModel) => Promise; + onPinLine?: (row: LogRowModel) => void; + onOpenContext?: (row: LogRowModel, onClose: () => void) => void; + onUnpinLine?: (row: LogRowModel) => void; + pinLineButtonTooltipTitle?: PopoverContent; + pinnedLogs?: string[]; +} + +export const LogListContext = createContext({}); + +export const useLogListContextData = (key: keyof LogListContextData) => { + const data: LogListContextData = useContext(LogListContext); + return data[key]; +}; + +export const useLogListContext = (): LogListContextData => { + return useContext(LogListContext); +}; + +export const useLogIsPinned = (log: LogRowModel) => { + const { pinnedLogs } = useContext(LogListContext); + return pinnedLogs?.some((logId) => logId === log.rowId); +}; diff --git a/public/app/features/logs/components/panel/processing.ts b/public/app/features/logs/components/panel/processing.ts index 2d62db31370..ef2c2c81b12 100644 --- a/public/app/features/logs/components/panel/processing.ts +++ b/public/app/features/logs/components/panel/processing.ts @@ -20,7 +20,7 @@ export interface LogFieldDimension { width: number; } -interface PreProcessOptions { +export interface PreProcessOptions { escape: boolean; getFieldLinks?: GetFieldLinksFn; order: LogsSortOrder; diff --git a/public/app/features/logs/components/panel/virtualization.ts b/public/app/features/logs/components/panel/virtualization.ts index a367b41c050..873e7555c58 100644 --- a/public/app/features/logs/components/panel/virtualization.ts +++ b/public/app/features/logs/components/panel/virtualization.ts @@ -8,10 +8,13 @@ let gridSize = 8; let paddingBottom = gridSize * 0.75; let lineHeight = 22; let measurementMode: 'canvas' | 'dom' = 'canvas'; +const iconWidth = 24; // Controls the space between fields in the log line, timestamp, level, displayed fields, and log line body export const FIELD_GAP_MULTIPLIER = 1.5; +export const getLineHeight = () => lineHeight; + export function init(theme: GrafanaTheme2) { const font = `${theme.typography.fontSize}px ${theme.typography.fontFamilyMonospace}`; const letterSpacing = theme.typography.body.letterSpacing; @@ -193,7 +196,7 @@ export function hasUnderOrOverflow(element: HTMLDivElement, calculatedHeight?: n if (element.scrollHeight > height) { return element.scrollHeight; } - const child = element.firstChild; + const child = element.children[1]; if (child instanceof HTMLDivElement && child.clientHeight < height) { return child.clientHeight; } @@ -203,7 +206,7 @@ export function hasUnderOrOverflow(element: HTMLDivElement, calculatedHeight?: n const scrollBarWidth = getScrollbarWidth(); export function getLogContainerWidth(container: HTMLDivElement) { - return container.clientWidth - scrollBarWidth; + return container.clientWidth - scrollBarWidth - iconWidth; } export function getScrollbarWidth() { diff --git a/public/app/features/logs/utils.ts b/public/app/features/logs/utils.ts index c4a19c0aa6c..b55e2f7a3a2 100644 --- a/public/app/features/logs/utils.ts +++ b/public/app/features/logs/utils.ts @@ -1,4 +1,5 @@ import { countBy, chain } from 'lodash'; +import { MouseEvent } from 'react'; import { LogLevel, @@ -15,9 +16,14 @@ import { LogsVolumeType, NumericLogLevel, getFieldDisplayName, + getDefaultTimeRange, + locationUtil, + urlUtil, } from '@grafana/data'; +import { getConfig } from 'app/core/config'; import { getDataframeFields } from './components/logParser'; +import { GetRowContextQueryFn } from './components/panel/LogLineMenu'; /** * Returns the log level of a log line. @@ -303,6 +309,34 @@ export const copyText = async (text: string, buttonRef: React.MutableRefObject, + row: LogRowModel, + getRowContextQuery: GetRowContextQueryFn | undefined, + onOpenContext: (row: LogRowModel) => void +) { + // if ctrl or meta key is pressed, open query in new Explore tab + if (getRowContextQuery && (event.nativeEvent.ctrlKey || event.nativeEvent.metaKey || event.nativeEvent.shiftKey)) { + const win = window.open('about:blank'); + // for this request we don't want to use the cached filters from a context provider, but always want to refetch and clear + const query = await getRowContextQuery(row, undefined, false); + if (query && win) { + const url = urlUtil.renderUrl(locationUtil.assureBaseUrl(`${getConfig().appSubUrl}explore`), { + left: JSON.stringify({ + datasource: query.datasource, + queries: [query], + range: getDefaultTimeRange(), + }), + }); + win.location = url; + + return; + } + win?.close(); + } + onOpenContext(row); +} + export function getLogLevelInfo(dataFrame: DataFrame, allDataFrames: DataFrame[]) { const fieldCache = new FieldCache(dataFrame); const timeField = fieldCache.getFirstFieldOfType(FieldType.time); diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index a064ce993a6..fe2fea8fc02 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -2257,6 +2257,14 @@ "log-line": "Log line", "no-details": "No details available" }, + "log-line-menu": { + "copy-link": "Copy link to log line", + "copy-log": "Copy log line", + "icon-label": "Log menu", + "pin-to-outline": "Pin log", + "show-context": "Show context", + "unpin-from-outline": "Unpin log" + }, "log-row-message": { "ellipsis": "… ", "more": "more", diff --git a/public/locales/pseudo-LOCALE/grafana.json b/public/locales/pseudo-LOCALE/grafana.json index 317a107f796..d6af162cbf2 100644 --- a/public/locales/pseudo-LOCALE/grafana.json +++ b/public/locales/pseudo-LOCALE/grafana.json @@ -2257,6 +2257,14 @@ "log-line": "Ŀőģ ľįʼnę", "no-details": "Ńő đęŧäįľş äväįľäþľę" }, + "log-line-menu": { + "copy-link": "Cőpy ľįʼnĸ ŧő ľőģ ľįʼnę", + "copy-log": "Cőpy ľőģ ľįʼnę", + "icon-label": "Ŀőģ męʼnū", + "pin-to-outline": "Pįʼn ľőģ", + "show-context": "Ŝĥőŵ čőʼnŧęχŧ", + "unpin-from-outline": "Ůʼnpįʼn ľőģ" + }, "log-row-message": { "ellipsis": "… ", "more": "mőřę", From bc4be187afc29594887a0a6ba75e599fef40a2e4 Mon Sep 17 00:00:00 2001 From: Moustafa Baiou Date: Thu, 27 Feb 2025 15:29:51 -0500 Subject: [PATCH 23/74] Alerting: Fix evaluation of rules with no-op math expressions When you use a math expression with out any operators, the dataFrame pointer is identical between the expression result and the input query/expression. This was resulting in the values returned from an evaluation overshadowing each other, depending on the order of the processing of the result map. For example: ``` A: some_metric B: reduce of A C: math expression -> "${B}" D: Threshold evaluation of C -> "C > 0" ``` With a value of 1 for `some_metric`, might result in a evaluation result of one of the following (somewhat at random): 1. { B: 1, D: 1 } 2. { C: 1, D: 1} While you would expect to see: { B: 1, C: 1, D: 1 } --- pkg/services/ngalert/eval/eval.go | 2 +- pkg/services/ngalert/eval/eval_test.go | 513 ++++++++++++++----------- 2 files changed, 297 insertions(+), 218 deletions(-) diff --git a/pkg/services/ngalert/eval/eval.go b/pkg/services/ngalert/eval/eval.go index 683ce31bb1a..f5e968fda0b 100644 --- a/pkg/services/ngalert/eval/eval.go +++ b/pkg/services/ngalert/eval/eval.go @@ -501,7 +501,7 @@ func queryDataResponseToExecutionResults(c models.Condition, execResp *backend.Q if frame.Fields[0].Len() == 1 { v = frame.At(0, 0).(*float64) // type checked above } - captureFn(frame.RefID, frame.Fields[0].Labels, v) + captureFn(refID, frame.Fields[0].Labels, v) } if refID == c.Condition { diff --git a/pkg/services/ngalert/eval/eval_test.go b/pkg/services/ngalert/eval/eval_test.go index 6710737891b..bde445c732c 100644 --- a/pkg/services/ngalert/eval/eval_test.go +++ b/pkg/services/ngalert/eval/eval_test.go @@ -739,243 +739,322 @@ func TestEvaluate(t *testing.T) { resp backend.QueryDataResponse expected Results error string - }{{ - name: "is no data with no frames", - cond: models.Condition{ - Data: []models.AlertQuery{{ - RefID: "A", - DatasourceUID: "test", - }, { - RefID: "B", - DatasourceUID: expr.DatasourceUID, - }, { - RefID: "C", - DatasourceUID: expr.OldDatasourceUID, - }, { - RefID: "D", - DatasourceUID: expr.MLDatasourceUID, + }{ + { + name: "is no data with no frames", + cond: models.Condition{ + Data: []models.AlertQuery{{ + RefID: "A", + DatasourceUID: "test", + }, { + RefID: "B", + DatasourceUID: expr.DatasourceUID, + }, { + RefID: "C", + DatasourceUID: expr.OldDatasourceUID, + }, { + RefID: "D", + DatasourceUID: expr.MLDatasourceUID, + }}, + }, + resp: backend.QueryDataResponse{ + Responses: backend.Responses{ + "A": {Frames: nil}, + "B": {Frames: []*data.Frame{{Fields: nil}}}, + "C": {Frames: nil}, + "D": {Frames: []*data.Frame{{Fields: nil}}}, + }, + }, + expected: Results{{ + State: NoData, + Instance: data.Labels{ + "datasource_uid": "test", + "ref_id": "A", + }, }}, }, - resp: backend.QueryDataResponse{ - Responses: backend.Responses{ - "A": {Frames: nil}, - "B": {Frames: []*data.Frame{{Fields: nil}}}, - "C": {Frames: nil}, - "D": {Frames: []*data.Frame{{Fields: nil}}}, + { + name: "is no data for one frame with no fields", + cond: models.Condition{ + Data: []models.AlertQuery{{ + RefID: "A", + DatasourceUID: "test", + }}, }, - }, - expected: Results{{ - State: NoData, - Instance: data.Labels{ - "datasource_uid": "test", - "ref_id": "A", + resp: backend.QueryDataResponse{ + Responses: backend.Responses{ + "A": {Frames: []*data.Frame{{Fields: nil}}}, + }, }, - }}, - }, { - name: "is no data for one frame with no fields", - cond: models.Condition{ - Data: []models.AlertQuery{{ - RefID: "A", - DatasourceUID: "test", + expected: Results{{ + State: NoData, + Instance: data.Labels{ + "datasource_uid": "test", + "ref_id": "A", + }, }}, }, - resp: backend.QueryDataResponse{ - Responses: backend.Responses{ - "A": {Frames: []*data.Frame{{Fields: nil}}}, + { + name: "results contains captured values for exact label matches", + cond: models.Condition{ + Condition: "B", }, + resp: backend.QueryDataResponse{ + Responses: backend.Responses{ + "A": { + Frames: []*data.Frame{{ + RefID: "A", + Fields: []*data.Field{ + data.NewField( + "Value", + data.Labels{"foo": "bar"}, + []*float64{util.Pointer(10.0)}, + ), + }, + }}, + }, + "B": { + Frames: []*data.Frame{{ + RefID: "B", + Fields: []*data.Field{ + data.NewField( + "Value", + data.Labels{"foo": "bar"}, + []*float64{util.Pointer(1.0)}, + ), + }, + }}, + }, + }, + }, + expected: Results{{ + State: Alerting, + Instance: data.Labels{ + "foo": "bar", + }, + Values: map[string]NumberValueCapture{ + "A": { + Var: "A", + Labels: data.Labels{"foo": "bar"}, + Value: util.Pointer(10.0), + }, + "B": { + Var: "B", + Labels: data.Labels{"foo": "bar"}, + Value: util.Pointer(1.0), + }, + }, + EvaluationString: "[ var='A' labels={foo=bar} value=10 ], [ var='B' labels={foo=bar} value=1 ]", + }}, }, - expected: Results{{ - State: NoData, - Instance: data.Labels{ - "datasource_uid": "test", - "ref_id": "A", + { + name: "results contains captured values for subset of labels", + cond: models.Condition{ + Condition: "B", }, - }}, - }, { - name: "results contains captured values for exact label matches", - cond: models.Condition{ - Condition: "B", + resp: backend.QueryDataResponse{ + Responses: backend.Responses{ + "A": { + Frames: []*data.Frame{{ + RefID: "A", + Fields: []*data.Field{ + data.NewField( + "Value", + data.Labels{"foo": "bar"}, + []*float64{util.Pointer(10.0)}, + ), + }, + }}, + }, + "B": { + Frames: []*data.Frame{{ + RefID: "B", + Fields: []*data.Field{ + data.NewField( + "Value", + data.Labels{"foo": "bar", "bar": "baz"}, + []*float64{util.Pointer(1.0)}, + ), + }, + }}, + }, + }, + }, + expected: Results{{ + State: Alerting, + Instance: data.Labels{ + "foo": "bar", + "bar": "baz", + }, + Values: map[string]NumberValueCapture{ + "A": { + Var: "A", + Labels: data.Labels{"foo": "bar"}, + Value: util.Pointer(10.0), + }, + "B": { + Var: "B", + Labels: data.Labels{"foo": "bar", "bar": "baz"}, + Value: util.Pointer(1.0), + }, + }, + EvaluationString: "[ var='A' labels={foo=bar} value=10 ], [ var='B' labels={bar=baz, foo=bar} value=1 ]", + }}, }, - resp: backend.QueryDataResponse{ - Responses: backend.Responses{ - "A": { - Frames: []*data.Frame{{ - RefID: "A", - Fields: []*data.Field{ - data.NewField( - "Value", - data.Labels{"foo": "bar"}, - []*float64{util.Pointer(10.0)}, - ), - }, - }}, - }, - "B": { - Frames: []*data.Frame{{ - RefID: "B", - Fields: []*data.Field{ - data.NewField( - "Value", - data.Labels{"foo": "bar"}, - []*float64{util.Pointer(1.0)}, - ), - }, - }}, + { + name: "results contains error if condition frame has error", + cond: models.Condition{ + Condition: "B", + }, + resp: backend.QueryDataResponse{ + Responses: backend.Responses{ + "A": { + Frames: []*data.Frame{{ + RefID: "A", + Fields: []*data.Field{ + data.NewField( + "Value", + data.Labels{"foo": "bar"}, + []*float64{util.Pointer(10.0)}, + ), + }, + }}, + }, + "B": { + Frames: []*data.Frame{{ + RefID: "B", + Fields: []*data.Field{ + data.NewField( + "Value", + data.Labels{"foo": "bar", "bar": "baz"}, + []*float64{util.Pointer(1.0)}, + ), + }, + }}, + Error: errors.New("some frame error"), + }, }, }, + expected: Results{{ + State: Error, + Error: errors.New("some frame error"), + EvaluationString: "", + }}, }, - expected: Results{{ - State: Alerting, - Instance: data.Labels{ - "foo": "bar", + { + name: "results contain underlying error if condition frame has error that depends on another node", + cond: models.Condition{ + Condition: "B", }, - Values: map[string]NumberValueCapture{ - "A": { - Var: "A", - Labels: data.Labels{"foo": "bar"}, - Value: util.Pointer(10.0), - }, - "B": { - Var: "B", - Labels: data.Labels{"foo": "bar"}, - Value: util.Pointer(1.0), + resp: backend.QueryDataResponse{ + Responses: backend.Responses{ + "A": { + Frames: []*data.Frame{{ + RefID: "A", + Fields: []*data.Field{ + data.NewField( + "Value", + data.Labels{"foo": "bar"}, + []*float64{util.Pointer(10.0)}, + ), + }, + }}, + Error: errors.New("another error depends on me"), + }, + "B": { + Frames: []*data.Frame{{ + RefID: "B", + Fields: []*data.Field{ + data.NewField( + "Value", + data.Labels{"foo": "bar", "bar": "baz"}, + []*float64{util.Pointer(1.0)}, + ), + }, + }}, + Error: expr.MakeDependencyError("B", "A"), + }, }, }, - EvaluationString: "[ var='A' labels={foo=bar} value=10 ], [ var='B' labels={foo=bar} value=1 ]", - }}, - }, { - name: "results contains captured values for subset of labels", - cond: models.Condition{ - Condition: "B", + expected: Results{{ + State: Error, + Error: errors.New("another error depends on me"), + EvaluationString: "", + }}, }, - resp: backend.QueryDataResponse{ - Responses: backend.Responses{ - "A": { - Frames: []*data.Frame{{ - RefID: "A", - Fields: []*data.Field{ - data.NewField( - "Value", - data.Labels{"foo": "bar"}, - []*float64{util.Pointer(10.0)}, - ), - }, - }}, - }, - "B": { - Frames: []*data.Frame{{ - RefID: "B", - Fields: []*data.Field{ - data.NewField( - "Value", - data.Labels{"foo": "bar", "bar": "baz"}, - []*float64{util.Pointer(1.0)}, - ), - }, - }}, + { + name: "result values for all refIDs when a math no-op expression is used and two results share the same frame pointer", + cond: models.Condition{ + Condition: "C", + }, + resp: backend.QueryDataResponse{ + Responses: backend.Responses{ + "A": { + Frames: []*data.Frame{{ + RefID: "A", + Fields: []*data.Field{ + data.NewField( + "Value", + data.Labels{"foo": "bar"}, + []*float64{util.Pointer(10.0)}, + ), + }, + }}, + }, + "B": { + // in a math no-op expression the frame for B is the same as A + // e.g. A = some_query, B = `${A}` + Frames: []*data.Frame{{ + RefID: "A", + Fields: []*data.Field{ + data.NewField( + "Value", + data.Labels{"foo": "bar"}, + []*float64{util.Pointer(10.0)}, + ), + }, + }}, + }, + "C": { + Frames: []*data.Frame{{ + RefID: "C", + Fields: []*data.Field{ + data.NewField( + "Value", + data.Labels{"foo": "bar"}, + []*float64{util.Pointer(1.0)}, + ), + }, + }}, + }, }, }, + expected: Results{{ + State: Alerting, + Instance: data.Labels{ + "foo": "bar", + }, + Values: map[string]NumberValueCapture{ + "A": { + Var: "A", + Labels: data.Labels{"foo": "bar"}, + Value: util.Pointer(10.0), + }, + "B": { + Var: "B", + Labels: data.Labels{"foo": "bar"}, + Value: util.Pointer(10.0), + }, + "C": { + Var: "C", + Labels: data.Labels{"foo": "bar"}, + Value: util.Pointer(1.0), + }, + }, + EvaluationString: "[ var='A' labels={foo=bar} value=10 ], [ var='B' labels={foo=bar} value=10 ], [ var='C' labels={foo=bar} value=1 ]", + }}, }, - expected: Results{{ - State: Alerting, - Instance: data.Labels{ - "foo": "bar", - "bar": "baz", - }, - Values: map[string]NumberValueCapture{ - "A": { - Var: "A", - Labels: data.Labels{"foo": "bar"}, - Value: util.Pointer(10.0), - }, - "B": { - Var: "B", - Labels: data.Labels{"foo": "bar", "bar": "baz"}, - Value: util.Pointer(1.0), - }, - }, - EvaluationString: "[ var='A' labels={foo=bar} value=10 ], [ var='B' labels={bar=baz, foo=bar} value=1 ]", - }}, - }, { - name: "results contains error if condition frame has error", - cond: models.Condition{ - Condition: "B", - }, - resp: backend.QueryDataResponse{ - Responses: backend.Responses{ - "A": { - Frames: []*data.Frame{{ - RefID: "A", - Fields: []*data.Field{ - data.NewField( - "Value", - data.Labels{"foo": "bar"}, - []*float64{util.Pointer(10.0)}, - ), - }, - }}, - }, - "B": { - Frames: []*data.Frame{{ - RefID: "B", - Fields: []*data.Field{ - data.NewField( - "Value", - data.Labels{"foo": "bar", "bar": "baz"}, - []*float64{util.Pointer(1.0)}, - ), - }, - }}, - Error: errors.New("some frame error"), - }, - }, - }, - expected: Results{{ - State: Error, - Error: errors.New("some frame error"), - EvaluationString: "", - }}, - }, { - name: "results contain underlying error if condition frame has error that depends on another node", - cond: models.Condition{ - Condition: "B", - }, - resp: backend.QueryDataResponse{ - Responses: backend.Responses{ - "A": { - Frames: []*data.Frame{{ - RefID: "A", - Fields: []*data.Field{ - data.NewField( - "Value", - data.Labels{"foo": "bar"}, - []*float64{util.Pointer(10.0)}, - ), - }, - }}, - Error: errors.New("another error depends on me"), - }, - "B": { - Frames: []*data.Frame{{ - RefID: "B", - Fields: []*data.Field{ - data.NewField( - "Value", - data.Labels{"foo": "bar", "bar": "baz"}, - []*float64{util.Pointer(1.0)}, - ), - }, - }}, - Error: expr.MakeDependencyError("B", "A"), - }, - }, - }, - expected: Results{{ - State: Error, - Error: errors.New("another error depends on me"), - EvaluationString: "", - }}, - }} + } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { From 1d2f271c9550a07fac68b7f176c06e48ed2f0b7d Mon Sep 17 00:00:00 2001 From: aishyandapalli Date: Thu, 27 Feb 2025 15:24:35 -0800 Subject: [PATCH 24/74] VizTooltip: Pass `maxHeight` setting to Exemplar tooltips (#100478) Co-authored-by: Kristina Durivage Co-authored-by: Leon Sorokin --- .../visualization/data-hover/DataHoverView.tsx | 14 ++++++++++++-- .../visualization/data-hover/ExemplarHoverView.tsx | 9 ++++++--- .../app/plugins/panel/heatmap/HeatmapTooltip.tsx | 1 + public/app/plugins/panel/heatmap/module.tsx | 8 ++++++-- .../plugins/panel/timeseries/TimeSeriesPanel.tsx | 1 + .../panel/timeseries/plugins/ExemplarMarker.tsx | 5 ++++- .../panel/timeseries/plugins/ExemplarsPlugin.tsx | 6 ++++-- 7 files changed, 34 insertions(+), 10 deletions(-) diff --git a/public/app/features/visualization/data-hover/DataHoverView.tsx b/public/app/features/visualization/data-hover/DataHoverView.tsx index adc593a9a14..79785c94eb2 100644 --- a/public/app/features/visualization/data-hover/DataHoverView.tsx +++ b/public/app/features/visualization/data-hover/DataHoverView.tsx @@ -23,6 +23,7 @@ export interface Props { mode?: TooltipDisplayMode | null; header?: string; padding?: number; + maxHeight?: number; } export interface DisplayValue { @@ -92,7 +93,16 @@ export function getDisplayValuesAndLinks( return { displayValues, links }; } -export const DataHoverView = ({ data, rowIndex, columnIndex, sortOrder, mode, header, padding = 0 }: Props) => { +export const DataHoverView = ({ + data, + rowIndex, + columnIndex, + sortOrder, + mode, + header, + padding = 0, + maxHeight, +}: Props) => { const styles = useStyles2(getStyles, padding); if (!data || rowIndex == null) { @@ -108,7 +118,7 @@ export const DataHoverView = ({ data, rowIndex, columnIndex, sortOrder, mode, he const { displayValues, links } = dispValuesAndLinks; if (header === 'Exemplar') { - return ; + return ; } return ( diff --git a/public/app/features/visualization/data-hover/ExemplarHoverView.tsx b/public/app/features/visualization/data-hover/ExemplarHoverView.tsx index b353b08abba..b2f17d17333 100644 --- a/public/app/features/visualization/data-hover/ExemplarHoverView.tsx +++ b/public/app/features/visualization/data-hover/ExemplarHoverView.tsx @@ -11,10 +11,11 @@ export interface Props { displayValues: DisplayValue[]; links?: LinkModel[]; header?: string; + maxHeight?: number; } -export const ExemplarHoverView = ({ displayValues, links, header = 'Exemplar' }: Props) => { - const styles = useStyles2(getStyles); +export const ExemplarHoverView = ({ displayValues, links, header = 'Exemplar', maxHeight }: Props) => { + const styles = useStyles2(getStyles, 0, maxHeight); const time = displayValues.find((val) => val.name === 'Time'); displayValues = displayValues.filter((val) => val.name !== 'Time'); // time? @@ -49,7 +50,7 @@ export const ExemplarHoverView = ({ displayValues, links, header = 'Exemplar' }: ); }; -const getStyles = (theme: GrafanaTheme2, padding = 0) => { +const getStyles = (theme: GrafanaTheme2, padding = 0, maxHeight?: number) => { return { exemplarWrapper: css({ display: 'flex', @@ -79,6 +80,8 @@ const getStyles = (theme: GrafanaTheme2, padding = 0) => { gap: 4, borderTop: `1px solid ${theme.colors.border.medium}`, padding: theme.spacing(1), + overflowY: 'auto', + maxHeight: maxHeight, }), exemplarFooter: css({ display: 'flex', diff --git a/public/app/plugins/panel/heatmap/HeatmapTooltip.tsx b/public/app/plugins/panel/heatmap/HeatmapTooltip.tsx index 896dbeb1feb..d15b13cd50c 100644 --- a/public/app/plugins/panel/heatmap/HeatmapTooltip.tsx +++ b/public/app/plugins/panel/heatmap/HeatmapTooltip.tsx @@ -56,6 +56,7 @@ export const HeatmapTooltip = (props: HeatmapTooltipProps) => { rowIndex={props.dataIdxs[2]} header={'Exemplar'} padding={8} + maxHeight={props.maxHeight} /> ); } diff --git a/public/app/plugins/panel/heatmap/module.tsx b/public/app/plugins/panel/heatmap/module.tsx index 6ec45e27d9a..ff3dfb38214 100644 --- a/public/app/plugins/panel/heatmap/module.tsx +++ b/public/app/plugins/panel/heatmap/module.tsx @@ -1,4 +1,4 @@ -import { FieldConfigProperty, FieldType, identityOverrideProcessor, PanelPlugin } from '@grafana/data'; +import { DataFrame, FieldConfigProperty, FieldType, identityOverrideProcessor, PanelPlugin } from '@grafana/data'; import { config } from '@grafana/runtime'; import { AxisPlacement, @@ -442,7 +442,9 @@ export const plugin = new PanelPlugin(HeatmapPanel) settings: { integer: true, }, - showIf: (options) => options.tooltip?.mode === TooltipDisplayMode.Multi, + showIf: (options: Options, data: DataFrame[] | undefined, annotations: DataFrame[] | undefined) => + options.tooltip?.mode === TooltipDisplayMode.Multi || + annotations?.some((df) => df.meta?.custom?.resultType === 'exemplar'), }); category = ['Legend']; @@ -459,6 +461,8 @@ export const plugin = new PanelPlugin(HeatmapPanel) name: 'Color', defaultValue: defaultOptions.exemplars.color, category, + showIf: (options: Options, data: DataFrame[] | undefined, annotations: DataFrame[] | undefined) => + annotations?.some((df) => df.meta?.custom?.resultType === 'exemplar'), }); }) .setSuggestionsSupplier(new HeatmapSuggestionsSupplier()) diff --git a/public/app/plugins/panel/timeseries/TimeSeriesPanel.tsx b/public/app/plugins/panel/timeseries/TimeSeriesPanel.tsx index f8866b705f3..e4124886ce2 100644 --- a/public/app/plugins/panel/timeseries/TimeSeriesPanel.tsx +++ b/public/app/plugins/panel/timeseries/TimeSeriesPanel.tsx @@ -159,6 +159,7 @@ export const TimeSeriesPanel = ({ config={uplotConfig} exemplars={data.annotations} timeZone={timeZone} + maxHeight={options.tooltip.maxHeight} /> )} {((canEditThresholds && onThresholdsChange) || showThresholds) && ( diff --git a/public/app/plugins/panel/timeseries/plugins/ExemplarMarker.tsx b/public/app/plugins/panel/timeseries/plugins/ExemplarMarker.tsx index 54e79e06743..f41e5e3af7a 100644 --- a/public/app/plugins/panel/timeseries/plugins/ExemplarMarker.tsx +++ b/public/app/plugins/panel/timeseries/plugins/ExemplarMarker.tsx @@ -29,6 +29,7 @@ interface ExemplarMarkerProps { exemplarColor?: string; clickedExemplarFieldIndex: DataFrameFieldIndex | undefined; setClickedExemplarFieldIndex: React.Dispatch; + maxHeight?: number; } export const ExemplarMarker = ({ @@ -39,6 +40,7 @@ export const ExemplarMarker = ({ exemplarColor, clickedExemplarFieldIndex, setClickedExemplarFieldIndex, + maxHeight, }: ExemplarMarkerProps) => { const styles = useStyles2(getExemplarMarkerStyles); const [isOpen, setIsOpen] = useState(false); @@ -163,7 +165,7 @@ export const ExemplarMarker = ({ return (
{isLocked && } - +
); }, [ @@ -175,6 +177,7 @@ export const ExemplarMarker = ({ floatingStyles, getFloatingProps, refs.setFloating, + maxHeight, ]); const seriesColor = config diff --git a/public/app/plugins/panel/timeseries/plugins/ExemplarsPlugin.tsx b/public/app/plugins/panel/timeseries/plugins/ExemplarsPlugin.tsx index c741f821f88..673f2288dc7 100644 --- a/public/app/plugins/panel/timeseries/plugins/ExemplarsPlugin.tsx +++ b/public/app/plugins/panel/timeseries/plugins/ExemplarsPlugin.tsx @@ -18,9 +18,10 @@ interface ExemplarsPluginProps { exemplars: DataFrame[]; timeZone: TimeZone; visibleSeries?: VisibleExemplarLabels; + maxHeight?: number; } -export const ExemplarsPlugin = ({ exemplars, timeZone, config, visibleSeries }: ExemplarsPluginProps) => { +export const ExemplarsPlugin = ({ exemplars, timeZone, config, visibleSeries, maxHeight }: ExemplarsPluginProps) => { const plotInstance = useRef(); const [lockedExemplarFieldIndex, setLockedExemplarFieldIndex] = useState(); @@ -83,10 +84,11 @@ export const ExemplarsPlugin = ({ exemplars, timeZone, config, visibleSeries }: dataFrameFieldIndex={dataFrameFieldIndex} config={config} exemplarColor={markerColor} + maxHeight={maxHeight} /> ); }, - [config, timeZone, visibleSeries, setLockedExemplarFieldIndex, lockedExemplarFieldIndex] + [config, timeZone, visibleSeries, setLockedExemplarFieldIndex, lockedExemplarFieldIndex, maxHeight] ); return ( From 806c043e45020f887bfed0946ff1689b75921c6d Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Fri, 28 Feb 2025 08:41:08 +0300 Subject: [PATCH 25/74] UnifiedStorage: Rename Batch processing to Bulk (#101413) --- .../datamigrations/to_unified_storage.go | 4 +- .../pluginextensionv2/rendererv2.pb.go | 14 +- .../pluginextensionv2/sanitizer.pb.go | 14 +- .../secretsmanagerplugin/secretsmanager.pb.go | 14 +- pkg/registry/apis/dashboard/legacy/client.go | 6 +- pkg/registry/apis/dashboard/legacy/migrate.go | 50 +- pkg/registry/apis/dashboard/search_test.go | 2 +- pkg/services/authz/proto/v1/extention.pb.go | 14 +- .../store/proto/v1/alert_rule_state.pb.go | 14 +- pkg/storage/unified/apistore/store_test.go | 2 +- pkg/storage/unified/parquet/client.go | 36 +- pkg/storage/unified/parquet/reader.go | 24 +- pkg/storage/unified/parquet/writer.go | 24 +- .../unified/resource/{batch.go => bulk.go} | 70 +- pkg/storage/unified/resource/client.go | 12 +- pkg/storage/unified/resource/keys.go | 2 +- pkg/storage/unified/resource/resource.pb.go | 997 +++++++++--------- pkg/storage/unified/resource/resource.proto | 10 +- .../unified/resource/resource_grpc.pb.go | 92 +- pkg/storage/unified/resource/server.go | 2 +- pkg/storage/unified/sql/backend.go | 4 +- pkg/storage/unified/sql/{batch.go => bulk.go} | 83 +- .../sql/{batch_test.go => bulk_test.go} | 2 +- pkg/storage/unified/sql/notifier.go | 2 +- pkg/storage/unified/sql/notifier_sql.go | 15 +- pkg/storage/unified/sql/notifier_sql_test.go | 35 +- pkg/storage/unified/sql/service.go | 2 +- 27 files changed, 774 insertions(+), 772 deletions(-) rename pkg/storage/unified/resource/{batch.go => bulk.go} (78%) rename pkg/storage/unified/sql/{batch.go => bulk.go} (75%) rename pkg/storage/unified/sql/{batch_test.go => bulk_test.go} (95%) diff --git a/pkg/cmd/grafana-cli/commands/datamigrations/to_unified_storage.go b/pkg/cmd/grafana-cli/commands/datamigrations/to_unified_storage.go index 164ea45cd83..27e2fe15e05 100644 --- a/pkg/cmd/grafana-cli/commands/datamigrations/to_unified_storage.go +++ b/pkg/cmd/grafana-cli/commands/datamigrations/to_unified_storage.go @@ -199,11 +199,11 @@ func newUnifiedClient(cfg *setting.Cfg, sqlStore db.DB) (resource.ResourceClient }) } -func newParquetClient(file *os.File) (resource.BatchStoreClient, error) { +func newParquetClient(file *os.File) (resource.BulkStoreClient, error) { writer, err := parquet.NewParquetWriter(file) if err != nil { return nil, err } - client := parquet.NewBatchResourceWriterClient(writer) + client := parquet.NewBulkResourceWriterClient(writer) return client, nil } diff --git a/pkg/plugins/backendplugin/pluginextensionv2/rendererv2.pb.go b/pkg/plugins/backendplugin/pluginextensionv2/rendererv2.pb.go index 365cd67b137..d509ac74dde 100644 --- a/pkg/plugins/backendplugin/pluginextensionv2/rendererv2.pb.go +++ b/pkg/plugins/backendplugin/pluginextensionv2/rendererv2.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.1 +// protoc-gen-go v1.36.5 // protoc (unknown) // source: rendererv2.proto @@ -11,6 +11,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -394,7 +395,7 @@ func (x *RenderCSVResponse) GetFileName() string { var File_rendererv2_proto protoreflect.FileDescriptor -var file_rendererv2_proto_rawDesc = []byte{ +var file_rendererv2_proto_rawDesc = string([]byte{ 0x0a, 0x10, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x65, 0x72, 0x76, 0x32, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x11, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x76, 0x32, 0x22, 0x24, 0x0a, 0x0a, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4c, @@ -474,16 +475,16 @@ var file_rendererv2_proto_rawDesc = []byte{ 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x16, 0x5a, 0x14, 0x2e, 0x2f, 0x3b, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x76, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +}) var ( file_rendererv2_proto_rawDescOnce sync.Once - file_rendererv2_proto_rawDescData = file_rendererv2_proto_rawDesc + file_rendererv2_proto_rawDescData []byte ) func file_rendererv2_proto_rawDescGZIP() []byte { file_rendererv2_proto_rawDescOnce.Do(func() { - file_rendererv2_proto_rawDescData = protoimpl.X.CompressGZIP(file_rendererv2_proto_rawDescData) + file_rendererv2_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_rendererv2_proto_rawDesc), len(file_rendererv2_proto_rawDesc))) }) return file_rendererv2_proto_rawDescData } @@ -523,7 +524,7 @@ func file_rendererv2_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_rendererv2_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_rendererv2_proto_rawDesc), len(file_rendererv2_proto_rawDesc)), NumEnums: 0, NumMessages: 7, NumExtensions: 0, @@ -534,7 +535,6 @@ func file_rendererv2_proto_init() { MessageInfos: file_rendererv2_proto_msgTypes, }.Build() File_rendererv2_proto = out.File - file_rendererv2_proto_rawDesc = nil file_rendererv2_proto_goTypes = nil file_rendererv2_proto_depIdxs = nil } diff --git a/pkg/plugins/backendplugin/pluginextensionv2/sanitizer.pb.go b/pkg/plugins/backendplugin/pluginextensionv2/sanitizer.pb.go index 58920c8b379..2e76d7189ba 100644 --- a/pkg/plugins/backendplugin/pluginextensionv2/sanitizer.pb.go +++ b/pkg/plugins/backendplugin/pluginextensionv2/sanitizer.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.1 +// protoc-gen-go v1.36.5 // protoc (unknown) // source: sanitizer.proto @@ -11,6 +11,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -142,7 +143,7 @@ func (x *SanitizeResponse) GetSanitized() []byte { var File_sanitizer_proto protoreflect.FileDescriptor -var file_sanitizer_proto_rawDesc = []byte{ +var file_sanitizer_proto_rawDesc = string([]byte{ 0x0a, 0x0f, 0x73, 0x61, 0x6e, 0x69, 0x74, 0x69, 0x7a, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x11, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x76, 0x32, 0x22, 0x7f, 0x0a, 0x0f, 0x53, 0x61, 0x6e, 0x69, 0x74, 0x69, 0x7a, 0x65, @@ -166,16 +167,16 @@ var file_sanitizer_proto_rawDesc = []byte{ 0x61, 0x6e, 0x69, 0x74, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x15, 0x5a, 0x13, 0x2e, 0x3b, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x76, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +}) var ( file_sanitizer_proto_rawDescOnce sync.Once - file_sanitizer_proto_rawDescData = file_sanitizer_proto_rawDesc + file_sanitizer_proto_rawDescData []byte ) func file_sanitizer_proto_rawDescGZIP() []byte { file_sanitizer_proto_rawDescOnce.Do(func() { - file_sanitizer_proto_rawDescData = protoimpl.X.CompressGZIP(file_sanitizer_proto_rawDescData) + file_sanitizer_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_sanitizer_proto_rawDesc), len(file_sanitizer_proto_rawDesc))) }) return file_sanitizer_proto_rawDescData } @@ -204,7 +205,7 @@ func file_sanitizer_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_sanitizer_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_sanitizer_proto_rawDesc), len(file_sanitizer_proto_rawDesc)), NumEnums: 0, NumMessages: 2, NumExtensions: 0, @@ -215,7 +216,6 @@ func file_sanitizer_proto_init() { MessageInfos: file_sanitizer_proto_msgTypes, }.Build() File_sanitizer_proto = out.File - file_sanitizer_proto_rawDesc = nil file_sanitizer_proto_goTypes = nil file_sanitizer_proto_depIdxs = nil } diff --git a/pkg/plugins/backendplugin/secretsmanagerplugin/secretsmanager.pb.go b/pkg/plugins/backendplugin/secretsmanagerplugin/secretsmanager.pb.go index af94f0d501c..bdecccee0d8 100644 --- a/pkg/plugins/backendplugin/secretsmanagerplugin/secretsmanager.pb.go +++ b/pkg/plugins/backendplugin/secretsmanagerplugin/secretsmanager.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.1 +// protoc-gen-go v1.36.5 // protoc (unknown) // source: secretsmanager.proto @@ -11,6 +11,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -710,7 +711,7 @@ func (x *RenameSecretResponse) GetUserFriendlyError() string { var File_secretsmanager_proto protoreflect.FileDescriptor -var file_secretsmanager_proto_rawDesc = []byte{ +var file_secretsmanager_proto_rawDesc = string([]byte{ 0x0a, 0x14, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x22, 0x4d, 0x0a, 0x03, @@ -836,16 +837,16 @@ var file_secretsmanager_proto_rawDesc = []byte{ 0x65, 0x42, 0x19, 0x5a, 0x17, 0x2e, 0x2f, 0x3b, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +}) var ( file_secretsmanager_proto_rawDescOnce sync.Once - file_secretsmanager_proto_rawDescData = file_secretsmanager_proto_rawDesc + file_secretsmanager_proto_rawDescData []byte ) func file_secretsmanager_proto_rawDescGZIP() []byte { file_secretsmanager_proto_rawDescOnce.Do(func() { - file_secretsmanager_proto_rawDescData = protoimpl.X.CompressGZIP(file_secretsmanager_proto_rawDescData) + file_secretsmanager_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_secretsmanager_proto_rawDesc), len(file_secretsmanager_proto_rawDesc))) }) return file_secretsmanager_proto_rawDescData } @@ -904,7 +905,7 @@ func file_secretsmanager_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_secretsmanager_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_secretsmanager_proto_rawDesc), len(file_secretsmanager_proto_rawDesc)), NumEnums: 0, NumMessages: 14, NumExtensions: 0, @@ -915,7 +916,6 @@ func file_secretsmanager_proto_init() { MessageInfos: file_secretsmanager_proto_msgTypes, }.Build() File_secretsmanager_proto = out.File - file_secretsmanager_proto_rawDesc = nil file_secretsmanager_proto_goTypes = nil file_secretsmanager_proto_depIdxs = nil } diff --git a/pkg/registry/apis/dashboard/legacy/client.go b/pkg/registry/apis/dashboard/legacy/client.go index 77dc173b69f..db0b0403f6b 100644 --- a/pkg/registry/apis/dashboard/legacy/client.go +++ b/pkg/registry/apis/dashboard/legacy/client.go @@ -90,7 +90,7 @@ func (d *directResourceClient) Watch(ctx context.Context, in *resource.WatchRequ return nil, fmt.Errorf("watch not supported with direct resource client") } -// BatchProcess implements resource.ResourceClient. -func (d *directResourceClient) BatchProcess(ctx context.Context, opts ...grpc.CallOption) (resource.BatchStore_BatchProcessClient, error) { - return nil, fmt.Errorf("BatchProcess not supported with direct resource client") +// BulkProcess implements resource.ResourceClient. +func (d *directResourceClient) BulkProcess(ctx context.Context, opts ...grpc.CallOption) (resource.BulkStore_BulkProcessClient, error) { + return nil, fmt.Errorf("BulkProcess not supported with direct resource client") } diff --git a/pkg/registry/apis/dashboard/legacy/migrate.go b/pkg/registry/apis/dashboard/legacy/migrate.go index e18150e1cd1..27959d31785 100644 --- a/pkg/registry/apis/dashboard/legacy/migrate.go +++ b/pkg/registry/apis/dashboard/legacy/migrate.go @@ -25,7 +25,7 @@ import ( type MigrateOptions struct { Namespace string - Store resource.BatchStoreClient + Store resource.BulkStoreClient LargeObjects apistore.LargeObjectSupport BlobStore resource.BlobStoreClient Resources []schema.GroupResource @@ -36,7 +36,7 @@ type MigrateOptions struct { // Read from legacy and write into unified storage type LegacyMigrator interface { - Migrate(ctx context.Context, opts MigrateOptions) (*resource.BatchResponse, error) + Migrate(ctx context.Context, opts MigrateOptions) (*resource.BulkResponse, error) } // This can migrate Folders, Dashboards and LibraryPanels @@ -54,9 +54,9 @@ type BlobStoreInfo struct { } // migrate function -- works for a single kind -type migrator = func(ctx context.Context, orgId int64, opts MigrateOptions, stream resource.BatchStore_BatchProcessClient) (*BlobStoreInfo, error) +type migrator = func(ctx context.Context, orgId int64, opts MigrateOptions, stream resource.BulkStore_BulkProcessClient) (*BlobStoreInfo, error) -func (a *dashboardSqlAccess) Migrate(ctx context.Context, opts MigrateOptions) (*resource.BatchResponse, error) { +func (a *dashboardSqlAccess) Migrate(ctx context.Context, opts MigrateOptions) (*resource.BulkResponse, error) { info, err := authlib.ParseNamespace(opts.Namespace) if err != nil { return nil, err @@ -71,7 +71,7 @@ func (a *dashboardSqlAccess) Migrate(ctx context.Context, opts MigrateOptions) ( } migrators := []migrator{} - settings := resource.BatchSettings{ + settings := resource.BulkSettings{ RebuildCollection: true, SkipValidation: true, } @@ -111,7 +111,7 @@ func (a *dashboardSqlAccess) Migrate(ctx context.Context, opts MigrateOptions) ( } ctx = metadata.NewOutgoingContext(ctx, settings.ToMD()) - stream, err := opts.Store.BatchProcess(ctx) + stream, err := opts.Store.BulkProcess(ctx) if err != nil { return nil, err } @@ -132,7 +132,7 @@ func (a *dashboardSqlAccess) Migrate(ctx context.Context, opts MigrateOptions) ( return stream.CloseAndRecv() } -func (a *dashboardSqlAccess) countValues(ctx context.Context, opts MigrateOptions) (*resource.BatchResponse, error) { +func (a *dashboardSqlAccess) countValues(ctx context.Context, opts MigrateOptions) (*resource.BulkResponse, error) { sql, err := a.sql(ctx) if err != nil { return nil, err @@ -142,12 +142,12 @@ func (a *dashboardSqlAccess) countValues(ctx context.Context, opts MigrateOption return nil, err } orgId := ns.OrgID - rsp := &resource.BatchResponse{} + rsp := &resource.BulkResponse{} err = sql.DB.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { for _, res := range opts.Resources { switch fmt.Sprintf("%s/%s", res.Group, res.Resource) { case "folder.grafana.app/folders": - summary := &resource.BatchResponse_Summary{} + summary := &resource.BulkResponse_Summary{} summary.Group = folders.GROUP summary.Group = folders.RESOURCE _, err = sess.SQL("SELECT COUNT(*) FROM "+sql.Table("dashboard")+ @@ -155,7 +155,7 @@ func (a *dashboardSqlAccess) countValues(ctx context.Context, opts MigrateOption rsp.Summary = append(rsp.Summary, summary) case "dashboard.grafana.app/librarypanels": - summary := &resource.BatchResponse_Summary{} + summary := &resource.BulkResponse_Summary{} summary.Group = dashboard.GROUP summary.Resource = dashboard.LIBRARY_PANEL_RESOURCE _, err = sess.SQL("SELECT COUNT(*) FROM "+sql.Table("library_element")+ @@ -163,7 +163,7 @@ func (a *dashboardSqlAccess) countValues(ctx context.Context, opts MigrateOption rsp.Summary = append(rsp.Summary, summary) case "dashboard.grafana.app/dashboards": - summary := &resource.BatchResponse_Summary{} + summary := &resource.BulkResponse_Summary{} summary.Group = dashboard.GROUP summary.Resource = dashboard.DASHBOARD_RESOURCE rsp.Summary = append(rsp.Summary, summary) @@ -190,7 +190,7 @@ func (a *dashboardSqlAccess) countValues(ctx context.Context, opts MigrateOption return rsp, nil } -func (a *dashboardSqlAccess) migrateDashboards(ctx context.Context, orgId int64, opts MigrateOptions, stream resource.BatchStore_BatchProcessClient) (*BlobStoreInfo, error) { +func (a *dashboardSqlAccess) migrateDashboards(ctx context.Context, orgId int64, opts MigrateOptions, stream resource.BulkStore_BulkProcessClient) (*BlobStoreInfo, error) { query := &DashboardQuery{ OrgID: orgId, Limit: 100000000, @@ -229,7 +229,7 @@ func (a *dashboardSqlAccess) migrateDashboards(ctx context.Context, orgId int64, return blobs, err } - req := &resource.BatchRequest{ + req := &resource.BulkRequest{ Key: &resource.ResourceKey{ Namespace: opts.Namespace, Group: dashboard.GROUP, @@ -238,12 +238,12 @@ func (a *dashboardSqlAccess) migrateDashboards(ctx context.Context, orgId int64, }, Value: body, Folder: rows.row.FolderUID, - Action: resource.BatchRequest_ADDED, + Action: resource.BulkRequest_ADDED, } if dash.Generation > 1 { - req.Action = resource.BatchRequest_MODIFIED + req.Action = resource.BulkRequest_MODIFIED } else if dash.Generation < 0 { - req.Action = resource.BatchRequest_DELETED + req.Action = resource.BulkRequest_DELETED } // With large object support @@ -296,7 +296,7 @@ func (a *dashboardSqlAccess) migrateDashboards(ctx context.Context, orgId int64, return blobs, err } -func (a *dashboardSqlAccess) migrateFolders(ctx context.Context, orgId int64, opts MigrateOptions, stream resource.BatchStore_BatchProcessClient) (*BlobStoreInfo, error) { +func (a *dashboardSqlAccess) migrateFolders(ctx context.Context, orgId int64, opts MigrateOptions, stream resource.BulkStore_BulkProcessClient) (*BlobStoreInfo, error) { query := &DashboardQuery{ OrgID: orgId, Limit: 100000000, @@ -341,7 +341,7 @@ func (a *dashboardSqlAccess) migrateFolders(ctx context.Context, orgId int64, op return nil, err } - req := &resource.BatchRequest{ + req := &resource.BulkRequest{ Key: &resource.ResourceKey{ Namespace: opts.Namespace, Group: "folder.grafana.app", @@ -350,12 +350,12 @@ func (a *dashboardSqlAccess) migrateFolders(ctx context.Context, orgId int64, op }, Value: body, Folder: rows.row.FolderUID, - Action: resource.BatchRequest_ADDED, + Action: resource.BulkRequest_ADDED, } if dash.Generation > 1 { - req.Action = resource.BatchRequest_MODIFIED + req.Action = resource.BulkRequest_MODIFIED } else if dash.Generation < 0 { - req.Action = resource.BatchRequest_DELETED + req.Action = resource.BulkRequest_DELETED } opts.Progress(i, fmt.Sprintf("[v:%d] %s (%d)", dash.Generation, dash.Name, len(req.Value))) @@ -377,7 +377,7 @@ func (a *dashboardSqlAccess) migrateFolders(ctx context.Context, orgId int64, op return nil, err } -func (a *dashboardSqlAccess) migratePanels(ctx context.Context, orgId int64, opts MigrateOptions, stream resource.BatchStore_BatchProcessClient) (*BlobStoreInfo, error) { +func (a *dashboardSqlAccess) migratePanels(ctx context.Context, orgId int64, opts MigrateOptions, stream resource.BulkStore_BulkProcessClient) (*BlobStoreInfo, error) { opts.Progress(-1, "migrating library panels...") panels, err := a.GetLibraryPanels(ctx, LibraryPanelQuery{ OrgID: orgId, @@ -396,7 +396,7 @@ func (a *dashboardSqlAccess) migratePanels(ctx context.Context, orgId int64, opt return nil, err } - req := &resource.BatchRequest{ + req := &resource.BulkRequest{ Key: &resource.ResourceKey{ Namespace: opts.Namespace, Group: dashboard.GROUP, @@ -405,10 +405,10 @@ func (a *dashboardSqlAccess) migratePanels(ctx context.Context, orgId int64, opt }, Value: body, Folder: meta.GetFolder(), - Action: resource.BatchRequest_ADDED, + Action: resource.BulkRequest_ADDED, } if panel.Generation > 1 { - req.Action = resource.BatchRequest_MODIFIED + req.Action = resource.BulkRequest_MODIFIED } opts.Progress(i, fmt.Sprintf("[v:%d] %s (%d)", i, meta.GetName(), len(req.Value))) diff --git a/pkg/registry/apis/dashboard/search_test.go b/pkg/registry/apis/dashboard/search_test.go index de2658c28c1..16460c87a69 100644 --- a/pkg/registry/apis/dashboard/search_test.go +++ b/pkg/registry/apis/dashboard/search_test.go @@ -710,6 +710,6 @@ func (m *MockClient) ListRepositoryObjects(ctx context.Context, in *resource.Lis func (m *MockClient) IsHealthy(ctx context.Context, in *resource.HealthCheckRequest, opts ...grpc.CallOption) (*resource.HealthCheckResponse, error) { return nil, nil } -func (m *MockClient) BatchProcess(ctx context.Context, opts ...grpc.CallOption) (resource.BatchStore_BatchProcessClient, error) { +func (m *MockClient) BulkProcess(ctx context.Context, opts ...grpc.CallOption) (resource.BulkStore_BulkProcessClient, error) { return nil, nil } diff --git a/pkg/services/authz/proto/v1/extention.pb.go b/pkg/services/authz/proto/v1/extention.pb.go index 054f3b90051..9f155187ab5 100644 --- a/pkg/services/authz/proto/v1/extention.pb.go +++ b/pkg/services/authz/proto/v1/extention.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.1 +// protoc-gen-go v1.36.5 // protoc (unknown) // source: extention.proto @@ -14,6 +14,7 @@ import ( wrapperspb "google.golang.org/protobuf/types/known/wrapperspb" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -853,7 +854,7 @@ func (x *BatchCheckGroupResource) GetItems() map[string]bool { var File_extention_proto protoreflect.FileDescriptor -var file_extention_proto_rawDesc = []byte{ +var file_extention_proto_rawDesc = string([]byte{ 0x0a, 0x0f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, @@ -1006,16 +1007,16 @@ var file_extention_proto_rawDesc = []byte{ 0x67, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +}) var ( file_extention_proto_rawDescOnce sync.Once - file_extention_proto_rawDescData = file_extention_proto_rawDesc + file_extention_proto_rawDescData []byte ) func file_extention_proto_rawDescGZIP() []byte { file_extention_proto_rawDescOnce.Do(func() { - file_extention_proto_rawDescData = protoimpl.X.CompressGZIP(file_extention_proto_rawDescData) + file_extention_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_extention_proto_rawDesc), len(file_extention_proto_rawDesc))) }) return file_extention_proto_rawDescData } @@ -1081,7 +1082,7 @@ func file_extention_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_extention_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_extention_proto_rawDesc), len(file_extention_proto_rawDesc)), NumEnums: 0, NumMessages: 17, NumExtensions: 0, @@ -1092,7 +1093,6 @@ func file_extention_proto_init() { MessageInfos: file_extention_proto_msgTypes, }.Build() File_extention_proto = out.File - file_extention_proto_rawDesc = nil file_extention_proto_goTypes = nil file_extention_proto_depIdxs = nil } diff --git a/pkg/services/ngalert/store/proto/v1/alert_rule_state.pb.go b/pkg/services/ngalert/store/proto/v1/alert_rule_state.pb.go index e07a4bbdf04..bcfab58904f 100644 --- a/pkg/services/ngalert/store/proto/v1/alert_rule_state.pb.go +++ b/pkg/services/ngalert/store/proto/v1/alert_rule_state.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.1 +// protoc-gen-go v1.36.5 // protoc (unknown) // source: alert_rule_state.proto @@ -12,6 +12,7 @@ import ( timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -183,7 +184,7 @@ func (x *AlertInstances) GetInstances() []*AlertInstance { var File_alert_rule_state_proto protoreflect.FileDescriptor -var file_alert_rule_state_proto_rawDesc = []byte{ +var file_alert_rule_state_proto_rawDesc = string([]byte{ 0x0a, 0x16, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x6e, 0x67, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, @@ -239,16 +240,16 @@ var file_alert_rule_state_proto_rawDesc = []byte{ 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x6e, 0x67, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +}) var ( file_alert_rule_state_proto_rawDescOnce sync.Once - file_alert_rule_state_proto_rawDescData = file_alert_rule_state_proto_rawDesc + file_alert_rule_state_proto_rawDescData []byte ) func file_alert_rule_state_proto_rawDescGZIP() []byte { file_alert_rule_state_proto_rawDescOnce.Do(func() { - file_alert_rule_state_proto_rawDescData = protoimpl.X.CompressGZIP(file_alert_rule_state_proto_rawDescData) + file_alert_rule_state_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_alert_rule_state_proto_rawDesc), len(file_alert_rule_state_proto_rawDesc))) }) return file_alert_rule_state_proto_rawDescData } @@ -284,7 +285,7 @@ func file_alert_rule_state_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_alert_rule_state_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_alert_rule_state_proto_rawDesc), len(file_alert_rule_state_proto_rawDesc)), NumEnums: 0, NumMessages: 3, NumExtensions: 0, @@ -295,7 +296,6 @@ func file_alert_rule_state_proto_init() { MessageInfos: file_alert_rule_state_proto_msgTypes, }.Build() File_alert_rule_state_proto = out.File - file_alert_rule_state_proto_rawDesc = nil file_alert_rule_state_proto_goTypes = nil file_alert_rule_state_proto_depIdxs = nil } diff --git a/pkg/storage/unified/apistore/store_test.go b/pkg/storage/unified/apistore/store_test.go index 12d9629d311..b5ada26a95c 100644 --- a/pkg/storage/unified/apistore/store_test.go +++ b/pkg/storage/unified/apistore/store_test.go @@ -156,7 +156,7 @@ type resourceClientMock struct { resource.ResourceStoreClient resource.ResourceIndexClient resource.RepositoryIndexClient - resource.BatchStoreClient + resource.BulkStoreClient resource.BlobStoreClient resource.DiagnosticsClient } diff --git a/pkg/storage/unified/parquet/client.go b/pkg/storage/unified/parquet/client.go index 3b573bdb1f5..73342e944d6 100644 --- a/pkg/storage/unified/parquet/client.go +++ b/pkg/storage/unified/parquet/client.go @@ -12,29 +12,29 @@ import ( ) var ( - _ resource.BatchStoreClient = (*writerClient)(nil) - _ resource.BatchStore_BatchProcessClient = (*writerClient)(nil) + _ resource.BulkStoreClient = (*writerClient)(nil) + _ resource.BulkStore_BulkProcessClient = (*writerClient)(nil) - errUnimplemented = errors.New("not implemented (BatchResourceWriter as BatchStoreClient shim)") + errUnimplemented = errors.New("not implemented (BulkResourceWriter as BulkStoreClient shim)") ) type writerClient struct { - writer resource.BatchResourceWriter + writer resource.BulkResourceWriter ctx context.Context } -// NewBatchResourceWriterClient wraps a BatchResourceWriter so that it can be used as a ResourceStoreClient -func NewBatchResourceWriterClient(writer resource.BatchResourceWriter) *writerClient { +// NewBulkResourceWriterClient wraps a BulkResourceWriter so that it can be used as a ResourceStoreClient +func NewBulkResourceWriterClient(writer resource.BulkResourceWriter) *writerClient { return &writerClient{writer: writer} } -// Send implements resource.ResourceStore_BatchProcessClient. -func (w *writerClient) Send(req *resource.BatchRequest) error { +// Send implements resource.ResourceStore_BulkProcessClient. +func (w *writerClient) Send(req *resource.BulkRequest) error { return w.writer.Write(w.ctx, req.Key, req.Value) } -// BatchProcess implements resource.ResourceStoreClient. -func (w *writerClient) BatchProcess(ctx context.Context, opts ...grpc.CallOption) (resource.BatchStore_BatchProcessClient, error) { +// BulkProcess implements resource.ResourceStoreClient. +func (w *writerClient) BulkProcess(ctx context.Context, opts ...grpc.CallOption) (resource.BulkStore_BulkProcessClient, error) { if w.ctx != nil { return nil, fmt.Errorf("only one batch request supported") } @@ -42,37 +42,37 @@ func (w *writerClient) BatchProcess(ctx context.Context, opts ...grpc.CallOption return w, nil } -// CloseAndRecv implements resource.ResourceStore_BatchProcessClient. -func (w *writerClient) CloseAndRecv() (*resource.BatchResponse, error) { +// CloseAndRecv implements resource.ResourceStore_BulkProcessClient. +func (w *writerClient) CloseAndRecv() (*resource.BulkResponse, error) { return w.writer.CloseWithResults() } -// CloseSend implements resource.ResourceStore_BatchProcessClient. +// CloseSend implements resource.ResourceStore_BulkProcessClient. func (w *writerClient) CloseSend() error { return w.writer.Close() } -// Context implements resource.ResourceStore_BatchProcessClient. +// Context implements resource.ResourceStore_BulkProcessClient. func (w *writerClient) Context() context.Context { return w.ctx } -// Header implements resource.ResourceStore_BatchProcessClient. +// Header implements resource.ResourceStore_BulkProcessClient. func (w *writerClient) Header() (metadata.MD, error) { return nil, errUnimplemented } -// RecvMsg implements resource.ResourceStore_BatchProcessClient. +// RecvMsg implements resource.ResourceStore_BulkProcessClient. func (w *writerClient) RecvMsg(m any) error { return errUnimplemented } -// SendMsg implements resource.ResourceStore_BatchProcessClient. +// SendMsg implements resource.ResourceStore_BulkProcessClient. func (w *writerClient) SendMsg(m any) error { return errUnimplemented } -// Trailer implements resource.ResourceStore_BatchProcessClient. +// Trailer implements resource.ResourceStore_BulkProcessClient. func (w *writerClient) Trailer() metadata.MD { return nil } diff --git a/pkg/storage/unified/parquet/reader.go b/pkg/storage/unified/parquet/reader.go index 84695d07315..7e327aa8a6d 100644 --- a/pkg/storage/unified/parquet/reader.go +++ b/pkg/storage/unified/parquet/reader.go @@ -10,10 +10,10 @@ import ( ) var ( - _ resource.BatchRequestIterator = (*parquetReader)(nil) + _ resource.BulkRequestIterator = (*parquetReader)(nil) ) -func NewParquetReader(inputPath string, batchSize int64) (resource.BatchRequestIterator, error) { +func NewParquetReader(inputPath string, batchSize int64) (resource.BulkRequestIterator, error) { return newResourceReader(inputPath, batchSize) } @@ -39,17 +39,17 @@ type parquetReader struct { bufferIndex int rowGroupIDX int - req *resource.BatchRequest + req *resource.BulkRequest err error } -// Next implements resource.BatchRequestIterator. +// Next implements resource.BulkRequestIterator. func (r *parquetReader) Next() bool { r.req = nil for r.err == nil && r.reader != nil { if r.bufferIndex >= r.bufferSize && r.value.reader.HasNext() { r.bufferIndex = 0 - r.err = r.readBatch() + r.err = r.readBulk() if r.err != nil { return false } @@ -60,14 +60,14 @@ func (r *parquetReader) Next() bool { i := r.bufferIndex r.bufferIndex++ - r.req = &resource.BatchRequest{ + r.req = &resource.BulkRequest{ Key: &resource.ResourceKey{ Group: r.group.buffer[i].String(), Resource: r.resource.buffer[i].String(), Namespace: r.namespace.buffer[i].String(), Name: r.name.buffer[i].String(), }, - Action: resource.BatchRequest_Action(r.action.buffer[i]), + Action: resource.BulkRequest_Action(r.action.buffer[i]), Value: r.value.buffer[i].Bytes(), Folder: r.folder.buffer[i].String(), } @@ -87,12 +87,12 @@ func (r *parquetReader) Next() bool { return false } -// Request implements resource.BatchRequestIterator. -func (r *parquetReader) Request() *resource.BatchRequest { +// Request implements resource.BulkRequestIterator. +func (r *parquetReader) Request() *resource.BulkRequest { return r.req } -// RollbackRequested implements resource.BatchRequestIterator. +// RollbackRequested implements resource.BulkRequestIterator. func (r *parquetReader) RollbackRequested() bool { return r.err != nil } @@ -163,7 +163,7 @@ func newResourceReader(inputPath string, batchSize int64) (*parquetReader, error } // get the first batch - err = reader.readBatch() + err = reader.readBulk() if err != nil { _ = rdr.Close() return nil, err @@ -182,7 +182,7 @@ func (r *parquetReader) open(rgr *file.RowGroupReader) error { return nil } -func (r *parquetReader) readBatch() error { +func (r *parquetReader) readBulk() error { r.bufferIndex = 0 r.bufferSize = 0 for i, c := range r.columns { diff --git a/pkg/storage/unified/parquet/writer.go b/pkg/storage/unified/parquet/writer.go index 421946b71a7..2ea626a2a62 100644 --- a/pkg/storage/unified/parquet/writer.go +++ b/pkg/storage/unified/parquet/writer.go @@ -18,7 +18,7 @@ import ( ) var ( - _ resource.BatchResourceWriter = (*parquetWriter)(nil) + _ resource.BulkResourceWriter = (*parquetWriter)(nil) ) // Write resources into a parquet file @@ -28,8 +28,8 @@ func NewParquetWriter(f io.Writer) (*parquetWriter, error) { schema: newSchema(nil), buffer: 1024 * 10 * 100 * 10, // 10MB logger: logging.DefaultLogger.With("logger", "parquet.writer"), - rsp: &resource.BatchResponse{}, - summary: make(map[string]*resource.BatchResponse_Summary), + rsp: &resource.BulkResponse{}, + summary: make(map[string]*resource.BulkResponse_Summary), } props := parquet.NewWriterProperties( @@ -43,8 +43,8 @@ func NewParquetWriter(f io.Writer) (*parquetWriter, error) { return w, w.init() } -// ProcessBatch implements resource.BatchProcessingBackend. -func (w *parquetWriter) ProcessBatch(ctx context.Context, setting resource.BatchSettings, iter resource.BatchRequestIterator) *resource.BatchResponse { +// ProcessBulk implements resource.BulkProcessingBackend. +func (w *parquetWriter) ProcessBulk(ctx context.Context, setting resource.BulkSettings, iter resource.BulkRequestIterator) *resource.BulkResponse { defer func() { _ = w.Close() }() var err error @@ -66,7 +66,7 @@ func (w *parquetWriter) ProcessBatch(ctx context.Context, setting resource.Batch w.logger.Warn("error closing parquet file", "err", err) } if rsp == nil { - rsp = &resource.BatchResponse{} + rsp = &resource.BulkResponse{} } if err != nil { rsp.Error = resource.AsErrorResult(err) @@ -92,11 +92,11 @@ type parquetWriter struct { action *array.Int8Builder value *array.StringBuilder - rsp *resource.BatchResponse - summary map[string]*resource.BatchResponse_Summary + rsp *resource.BulkResponse + summary map[string]*resource.BulkResponse_Summary } -func (w *parquetWriter) CloseWithResults() (*resource.BatchResponse, error) { +func (w *parquetWriter) CloseWithResults() (*resource.BulkResponse, error) { err := w.Close() return w.rsp, err } @@ -181,14 +181,14 @@ func (w *parquetWriter) Write(ctx context.Context, key *resource.ResourceKey, va return w.flush() } - summary := w.summary[key.BatchID()] + summary := w.summary[key.NSGR()] if summary == nil { - summary = &resource.BatchResponse_Summary{ + summary = &resource.BulkResponse_Summary{ Namespace: key.Namespace, Group: key.Group, Resource: key.Resource, } - w.summary[key.BatchID()] = summary + w.summary[key.NSGR()] = summary w.rsp.Summary = append(w.rsp.Summary, summary) } summary.Count++ diff --git a/pkg/storage/unified/resource/batch.go b/pkg/storage/unified/resource/bulk.go similarity index 78% rename from pkg/storage/unified/resource/batch.go rename to pkg/storage/unified/resource/bulk.go index 6f4f449da1d..3c580559a55 100644 --- a/pkg/storage/unified/resource/batch.go +++ b/pkg/storage/unified/resource/bulk.go @@ -21,30 +21,30 @@ func grpcMetaValueIsTrue(vals []string) bool { return len(vals) == 1 && vals[0] == "true" } -type BatchRequestIterator interface { +type BulkRequestIterator interface { Next() bool // The next event we should process - Request() *BatchRequest + Request() *BulkRequest // Rollback requested RollbackRequested() bool } -type BatchProcessingBackend interface { - ProcessBatch(ctx context.Context, setting BatchSettings, iter BatchRequestIterator) *BatchResponse +type BulkProcessingBackend interface { + ProcessBulk(ctx context.Context, setting BulkSettings, iter BulkRequestIterator) *BulkResponse } -type BatchResourceWriter interface { +type BulkResourceWriter interface { io.Closer Write(ctx context.Context, key *ResourceKey, value []byte) error // Called when finished writing - CloseWithResults() (*BatchResponse, error) + CloseWithResults() (*BulkResponse, error) } -type BatchSettings struct { +type BulkSettings struct { // All requests will be within this namespace/group/resource Collection []*ResourceKey @@ -56,7 +56,7 @@ type BatchSettings struct { SkipValidation bool } -func (x *BatchSettings) ToMD() metadata.MD { +func (x *BulkSettings) ToMD() metadata.MD { md := make(metadata.MD) if len(x.Collection) > 0 { for _, v := range x.Collection { @@ -72,8 +72,8 @@ func (x *BatchSettings) ToMD() metadata.MD { return md } -func NewBatchSettings(md metadata.MD) (BatchSettings, error) { - settings := BatchSettings{} +func NewBulkSettings(md metadata.MD) (BulkSettings, error) { + settings := BulkSettings{} for k, v := range md { switch k { case grpcMetaKeyCollection: @@ -94,13 +94,13 @@ func NewBatchSettings(md metadata.MD) (BatchSettings, error) { return settings, nil } -// BatchWrite implements ResourceServer. +// BulkWrite implements ResourceServer. // All requests must be to the same NAMESPACE/GROUP/RESOURCE -func (s *server) BatchProcess(stream BatchStore_BatchProcessServer) error { +func (s *server) BulkProcess(stream BulkStore_BulkProcessServer) error { ctx := stream.Context() user, ok := authlib.AuthInfoFrom(ctx) if !ok || user == nil { - return stream.SendAndClose(&BatchResponse{ + return stream.SendAndClose(&BulkResponse{ Error: &ErrorResult{ Message: "no user found in context", Code: http.StatusUnauthorized, @@ -110,7 +110,7 @@ func (s *server) BatchProcess(stream BatchStore_BatchProcessServer) error { md, ok := metadata.FromIncomingContext(ctx) if !ok { - return stream.SendAndClose(&BatchResponse{ + return stream.SendAndClose(&BulkResponse{ Error: &ErrorResult{ Message: "unable to read metadata gRPC request", Code: http.StatusPreconditionFailed, @@ -121,9 +121,9 @@ func (s *server) BatchProcess(stream BatchStore_BatchProcessServer) error { checker: make(map[string]authlib.ItemChecker), // Can create stream: stream, } - settings, err := NewBatchSettings(md) + settings, err := NewBulkSettings(md) if err != nil { - return stream.SendAndClose(&BatchResponse{ + return stream.SendAndClose(&BulkResponse{ Error: &ErrorResult{ Message: "error reading settings", Reason: err.Error(), @@ -133,7 +133,7 @@ func (s *server) BatchProcess(stream BatchStore_BatchProcessServer) error { } if len(settings.Collection) < 1 { - return stream.SendAndClose(&BatchResponse{ + return stream.SendAndClose(&BulkResponse{ Error: &ErrorResult{ Message: "Missing target collection(s) in request header", Code: http.StatusBadRequest, @@ -154,7 +154,7 @@ func (s *server) BatchProcess(stream BatchStore_BatchProcessServer) error { Verb: utils.VerbDeleteCollection, }) if err != nil || !rsp.Allowed { - return stream.SendAndClose(&BatchResponse{ + return stream.SendAndClose(&BulkResponse{ Error: &ErrorResult{ Message: fmt.Sprintf("Requester must be able to: %s", utils.VerbDeleteCollection), Code: http.StatusForbidden, @@ -163,14 +163,14 @@ func (s *server) BatchProcess(stream BatchStore_BatchProcessServer) error { } // This will be called for each request -- with the folder ID - runner.checker[k.BatchID()], err = access.Compile(ctx, user, authlib.ListRequest{ + runner.checker[k.NSGR()], err = access.Compile(ctx, user, authlib.ListRequest{ Namespace: k.Namespace, Group: k.Group, Resource: k.Resource, Verb: utils.VerbCreate, }) if err != nil { - return stream.SendAndClose(&BatchResponse{ + return stream.SendAndClose(&BulkResponse{ Error: &ErrorResult{ Message: "Unable to check `create` permission", Code: http.StatusForbidden, @@ -179,17 +179,17 @@ func (s *server) BatchProcess(stream BatchStore_BatchProcessServer) error { } } } else { - return stream.SendAndClose(&BatchResponse{ + return stream.SendAndClose(&BulkResponse{ Error: &ErrorResult{ - Message: "Batch currently only supports RebuildCollection", + Message: "Bulk currently only supports RebuildCollection", Code: http.StatusBadRequest, }, }) } - backend, ok := s.backend.(BatchProcessingBackend) + backend, ok := s.backend.(BulkProcessingBackend) if !ok { - return stream.SendAndClose(&BatchResponse{ + return stream.SendAndClose(&BulkResponse{ Error: &ErrorResult{ Message: "The server backend does not support batch processing", Code: http.StatusNotImplemented, @@ -197,10 +197,10 @@ func (s *server) BatchProcess(stream BatchStore_BatchProcessServer) error { }) } - // BatchProcess requests - rsp := backend.ProcessBatch(ctx, settings, runner) + // BulkProcess requests + rsp := backend.ProcessBulk(ctx, settings, runner) if rsp == nil { - rsp = &BatchResponse{ + rsp = &BulkResponse{ Error: &ErrorResult{ Code: http.StatusInternalServerError, Message: "Nothing returned from process batch", @@ -233,18 +233,18 @@ func (s *server) BatchProcess(stream BatchStore_BatchProcessServer) error { } var ( - _ BatchRequestIterator = (*batchRunner)(nil) + _ BulkRequestIterator = (*batchRunner)(nil) ) type batchRunner struct { - stream BatchStore_BatchProcessServer + stream BulkStore_BulkProcessServer rollback bool - request *BatchRequest + request *BulkRequest err error checker map[string]authlib.ItemChecker } -// Next implements BatchRequestIterator. +// Next implements BulkRequestIterator. func (b *batchRunner) Next() bool { if b.rollback { return true @@ -265,7 +265,7 @@ func (b *batchRunner) Next() bool { if b.request != nil { key := b.request.Key - k := key.BatchID() + k := key.NSGR() checker, ok := b.checker[k] if !ok { b.err = fmt.Errorf("missing access control for: %s", k) @@ -279,15 +279,15 @@ func (b *batchRunner) Next() bool { return false } -// Request implements BatchRequestIterator. -func (b *batchRunner) Request() *BatchRequest { +// Request implements BulkRequestIterator. +func (b *batchRunner) Request() *BulkRequest { if b.rollback { return nil } return b.request } -// RollbackRequested implements BatchRequestIterator. +// RollbackRequested implements BulkRequestIterator. func (b *batchRunner) RollbackRequested() bool { if b.rollback { b.rollback = false // break iterator diff --git a/pkg/storage/unified/resource/client.go b/pkg/storage/unified/resource/client.go index e963655b019..b059b0b855a 100644 --- a/pkg/storage/unified/resource/client.go +++ b/pkg/storage/unified/resource/client.go @@ -25,7 +25,7 @@ type ResourceClient interface { ResourceStoreClient ResourceIndexClient RepositoryIndexClient - BatchStoreClient + BulkStoreClient BlobStoreClient DiagnosticsClient } @@ -35,7 +35,7 @@ type resourceClient struct { ResourceStoreClient ResourceIndexClient RepositoryIndexClient - BatchStoreClient + BulkStoreClient BlobStoreClient DiagnosticsClient } @@ -46,7 +46,7 @@ func NewLegacyResourceClient(channel *grpc.ClientConn) ResourceClient { ResourceStoreClient: NewResourceStoreClient(cc), ResourceIndexClient: NewResourceIndexClient(cc), RepositoryIndexClient: NewRepositoryIndexClient(cc), - BatchStoreClient: NewBatchStoreClient(cc), + BulkStoreClient: NewBulkStoreClient(cc), BlobStoreClient: NewBlobStoreClient(cc), DiagnosticsClient: NewDiagnosticsClient(cc), } @@ -62,7 +62,7 @@ func NewLocalResourceClient(server ResourceServer) ResourceClient { &ResourceIndex_ServiceDesc, &RepositoryIndex_ServiceDesc, &BlobStore_ServiceDesc, - &BatchStore_ServiceDesc, + &BulkStore_ServiceDesc, &Diagnostics_ServiceDesc, } { channel.RegisterService( @@ -85,7 +85,7 @@ func NewLocalResourceClient(server ResourceServer) ResourceClient { ResourceStoreClient: NewResourceStoreClient(cc), ResourceIndexClient: NewResourceIndexClient(cc), RepositoryIndexClient: NewRepositoryIndexClient(cc), - BatchStoreClient: NewBatchStoreClient(cc), + BulkStoreClient: NewBulkStoreClient(cc), BlobStoreClient: NewBlobStoreClient(cc), DiagnosticsClient: NewDiagnosticsClient(cc), } @@ -127,7 +127,7 @@ func NewRemoteResourceClient(tracer tracing.Tracer, conn *grpc.ClientConn, cfg R ResourceStoreClient: NewResourceStoreClient(cc), ResourceIndexClient: NewResourceIndexClient(cc), BlobStoreClient: NewBlobStoreClient(cc), - BatchStoreClient: NewBatchStoreClient(cc), + BulkStoreClient: NewBulkStoreClient(cc), RepositoryIndexClient: NewRepositoryIndexClient(cc), DiagnosticsClient: NewDiagnosticsClient(cc), }, nil diff --git a/pkg/storage/unified/resource/keys.go b/pkg/storage/unified/resource/keys.go index d323e107ea1..80e8fe21f1f 100644 --- a/pkg/storage/unified/resource/keys.go +++ b/pkg/storage/unified/resource/keys.go @@ -75,7 +75,7 @@ func (x *ResourceKey) ReadSearchID(v string) error { } // The namespace/group/resource -func (x *ResourceKey) BatchID() string { +func (x *ResourceKey) NSGR() string { var sb strings.Builder if x.Namespace == "" { sb.WriteString(clusterNamespace) diff --git a/pkg/storage/unified/resource/resource.pb.go b/pkg/storage/unified/resource/resource.pb.go index 6116d89be9b..7cc91fbafa4 100644 --- a/pkg/storage/unified/resource/resource.pb.go +++ b/pkg/storage/unified/resource/resource.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.4 +// protoc-gen-go v1.36.5 // protoc (unknown) // source: resource.proto @@ -174,26 +174,26 @@ func (WatchEvent_Type) EnumDescriptor() ([]byte, []int) { return file_resource_proto_rawDescGZIP(), []int{18, 0} } -type BatchRequest_Action int32 +type BulkRequest_Action int32 const ( // will be an error - BatchRequest_UNKNOWN BatchRequest_Action = 0 + BulkRequest_UNKNOWN BulkRequest_Action = 0 // Matches Watch event enum - BatchRequest_ADDED BatchRequest_Action = 1 - BatchRequest_MODIFIED BatchRequest_Action = 2 - BatchRequest_DELETED BatchRequest_Action = 3 + BulkRequest_ADDED BulkRequest_Action = 1 + BulkRequest_MODIFIED BulkRequest_Action = 2 + BulkRequest_DELETED BulkRequest_Action = 3 ) -// Enum value maps for BatchRequest_Action. +// Enum value maps for BulkRequest_Action. var ( - BatchRequest_Action_name = map[int32]string{ + BulkRequest_Action_name = map[int32]string{ 0: "UNKNOWN", 1: "ADDED", 2: "MODIFIED", 3: "DELETED", } - BatchRequest_Action_value = map[string]int32{ + BulkRequest_Action_value = map[string]int32{ "UNKNOWN": 0, "ADDED": 1, "MODIFIED": 2, @@ -201,30 +201,30 @@ var ( } ) -func (x BatchRequest_Action) Enum() *BatchRequest_Action { - p := new(BatchRequest_Action) +func (x BulkRequest_Action) Enum() *BulkRequest_Action { + p := new(BulkRequest_Action) *p = x return p } -func (x BatchRequest_Action) String() string { +func (x BulkRequest_Action) String() string { return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } -func (BatchRequest_Action) Descriptor() protoreflect.EnumDescriptor { +func (BulkRequest_Action) Descriptor() protoreflect.EnumDescriptor { return file_resource_proto_enumTypes[3].Descriptor() } -func (BatchRequest_Action) Type() protoreflect.EnumType { +func (BulkRequest_Action) Type() protoreflect.EnumType { return &file_resource_proto_enumTypes[3] } -func (x BatchRequest_Action) Number() protoreflect.EnumNumber { +func (x BulkRequest_Action) Number() protoreflect.EnumNumber { return protoreflect.EnumNumber(x) } -// Deprecated: Use BatchRequest_Action.Descriptor instead. -func (BatchRequest_Action) EnumDescriptor() ([]byte, []int) { +// Deprecated: Use BulkRequest_Action.Descriptor instead. +func (BulkRequest_Action) EnumDescriptor() ([]byte, []int) { return file_resource_proto_rawDescGZIP(), []int{19, 0} } @@ -1725,12 +1725,12 @@ func (x *WatchEvent) GetPrevious() *WatchEvent_Resource { return nil } -type BatchRequest struct { +type BulkRequest struct { state protoimpl.MessageState `protogen:"open.v1"` // NOTE everything in the same stream must share the same Namespace/Group/Resource Key *ResourceKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` // Requested action - Action BatchRequest_Action `protobuf:"varint,2,opt,name=action,proto3,enum=resource.BatchRequest_Action" json:"action,omitempty"` + Action BulkRequest_Action `protobuf:"varint,2,opt,name=action,proto3,enum=resource.BulkRequest_Action" json:"action,omitempty"` // The resource value Value []byte `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` // Hint that a new version will be written on-top of this @@ -1739,20 +1739,20 @@ type BatchRequest struct { sizeCache protoimpl.SizeCache } -func (x *BatchRequest) Reset() { - *x = BatchRequest{} +func (x *BulkRequest) Reset() { + *x = BulkRequest{} mi := &file_resource_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *BatchRequest) String() string { +func (x *BulkRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*BatchRequest) ProtoMessage() {} +func (*BulkRequest) ProtoMessage() {} -func (x *BatchRequest) ProtoReflect() protoreflect.Message { +func (x *BulkRequest) ProtoReflect() protoreflect.Message { mi := &file_resource_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1764,67 +1764,67 @@ func (x *BatchRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use BatchRequest.ProtoReflect.Descriptor instead. -func (*BatchRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use BulkRequest.ProtoReflect.Descriptor instead. +func (*BulkRequest) Descriptor() ([]byte, []int) { return file_resource_proto_rawDescGZIP(), []int{19} } -func (x *BatchRequest) GetKey() *ResourceKey { +func (x *BulkRequest) GetKey() *ResourceKey { if x != nil { return x.Key } return nil } -func (x *BatchRequest) GetAction() BatchRequest_Action { +func (x *BulkRequest) GetAction() BulkRequest_Action { if x != nil { return x.Action } - return BatchRequest_UNKNOWN + return BulkRequest_UNKNOWN } -func (x *BatchRequest) GetValue() []byte { +func (x *BulkRequest) GetValue() []byte { if x != nil { return x.Value } return nil } -func (x *BatchRequest) GetFolder() string { +func (x *BulkRequest) GetFolder() string { if x != nil { return x.Folder } return "" } -type BatchResponse struct { +type BulkResponse struct { state protoimpl.MessageState `protogen:"open.v1"` // Error details Error *ErrorResult `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` // Total events processed Processed int64 `protobuf:"varint,2,opt,name=processed,proto3" json:"processed,omitempty"` // Summary status for the processed values - Summary []*BatchResponse_Summary `protobuf:"bytes,3,rep,name=summary,proto3" json:"summary,omitempty"` + Summary []*BulkResponse_Summary `protobuf:"bytes,3,rep,name=summary,proto3" json:"summary,omitempty"` // Rejected - Rejected []*BatchResponse_Rejected `protobuf:"bytes,4,rep,name=rejected,proto3" json:"rejected,omitempty"` + Rejected []*BulkResponse_Rejected `protobuf:"bytes,4,rep,name=rejected,proto3" json:"rejected,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *BatchResponse) Reset() { - *x = BatchResponse{} +func (x *BulkResponse) Reset() { + *x = BulkResponse{} mi := &file_resource_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *BatchResponse) String() string { +func (x *BulkResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*BatchResponse) ProtoMessage() {} +func (*BulkResponse) ProtoMessage() {} -func (x *BatchResponse) ProtoReflect() protoreflect.Message { +func (x *BulkResponse) ProtoReflect() protoreflect.Message { mi := &file_resource_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1836,33 +1836,33 @@ func (x *BatchResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use BatchResponse.ProtoReflect.Descriptor instead. -func (*BatchResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use BulkResponse.ProtoReflect.Descriptor instead. +func (*BulkResponse) Descriptor() ([]byte, []int) { return file_resource_proto_rawDescGZIP(), []int{20} } -func (x *BatchResponse) GetError() *ErrorResult { +func (x *BulkResponse) GetError() *ErrorResult { if x != nil { return x.Error } return nil } -func (x *BatchResponse) GetProcessed() int64 { +func (x *BulkResponse) GetProcessed() int64 { if x != nil { return x.Processed } return 0 } -func (x *BatchResponse) GetSummary() []*BatchResponse_Summary { +func (x *BulkResponse) GetSummary() []*BulkResponse_Summary { if x != nil { return x.Summary } return nil } -func (x *BatchResponse) GetRejected() []*BatchResponse_Rejected { +func (x *BulkResponse) GetRejected() []*BulkResponse_Rejected { if x != nil { return x.Rejected } @@ -3305,7 +3305,7 @@ func (x *WatchEvent_Resource) GetValue() []byte { return nil } -type BatchResponse_Summary struct { +type BulkResponse_Summary struct { state protoimpl.MessageState `protogen:"open.v1"` Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"` Group string `protobuf:"bytes,2,opt,name=group,proto3" json:"group,omitempty"` @@ -3320,20 +3320,20 @@ type BatchResponse_Summary struct { sizeCache protoimpl.SizeCache } -func (x *BatchResponse_Summary) Reset() { - *x = BatchResponse_Summary{} +func (x *BulkResponse_Summary) Reset() { + *x = BulkResponse_Summary{} mi := &file_resource_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *BatchResponse_Summary) String() string { +func (x *BulkResponse_Summary) String() string { return protoimpl.X.MessageStringOf(x) } -func (*BatchResponse_Summary) ProtoMessage() {} +func (*BulkResponse_Summary) ProtoMessage() {} -func (x *BatchResponse_Summary) ProtoReflect() protoreflect.Message { +func (x *BulkResponse_Summary) ProtoReflect() protoreflect.Message { mi := &file_resource_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -3345,61 +3345,61 @@ func (x *BatchResponse_Summary) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use BatchResponse_Summary.ProtoReflect.Descriptor instead. -func (*BatchResponse_Summary) Descriptor() ([]byte, []int) { +// Deprecated: Use BulkResponse_Summary.ProtoReflect.Descriptor instead. +func (*BulkResponse_Summary) Descriptor() ([]byte, []int) { return file_resource_proto_rawDescGZIP(), []int{20, 0} } -func (x *BatchResponse_Summary) GetNamespace() string { +func (x *BulkResponse_Summary) GetNamespace() string { if x != nil { return x.Namespace } return "" } -func (x *BatchResponse_Summary) GetGroup() string { +func (x *BulkResponse_Summary) GetGroup() string { if x != nil { return x.Group } return "" } -func (x *BatchResponse_Summary) GetResource() string { +func (x *BulkResponse_Summary) GetResource() string { if x != nil { return x.Resource } return "" } -func (x *BatchResponse_Summary) GetCount() int64 { +func (x *BulkResponse_Summary) GetCount() int64 { if x != nil { return x.Count } return 0 } -func (x *BatchResponse_Summary) GetHistory() int64 { +func (x *BulkResponse_Summary) GetHistory() int64 { if x != nil { return x.History } return 0 } -func (x *BatchResponse_Summary) GetResourceVersion() int64 { +func (x *BulkResponse_Summary) GetResourceVersion() int64 { if x != nil { return x.ResourceVersion } return 0 } -func (x *BatchResponse_Summary) GetPreviousCount() int64 { +func (x *BulkResponse_Summary) GetPreviousCount() int64 { if x != nil { return x.PreviousCount } return 0 } -func (x *BatchResponse_Summary) GetPreviousHistory() int64 { +func (x *BulkResponse_Summary) GetPreviousHistory() int64 { if x != nil { return x.PreviousHistory } @@ -3407,29 +3407,29 @@ func (x *BatchResponse_Summary) GetPreviousHistory() int64 { } // Collect a few invalid messages -type BatchResponse_Rejected struct { +type BulkResponse_Rejected struct { state protoimpl.MessageState `protogen:"open.v1"` Key *ResourceKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` - Action BatchRequest_Action `protobuf:"varint,2,opt,name=action,proto3,enum=resource.BatchRequest_Action" json:"action,omitempty"` + Action BulkRequest_Action `protobuf:"varint,2,opt,name=action,proto3,enum=resource.BulkRequest_Action" json:"action,omitempty"` Error string `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *BatchResponse_Rejected) Reset() { - *x = BatchResponse_Rejected{} +func (x *BulkResponse_Rejected) Reset() { + *x = BulkResponse_Rejected{} mi := &file_resource_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *BatchResponse_Rejected) String() string { +func (x *BulkResponse_Rejected) String() string { return protoimpl.X.MessageStringOf(x) } -func (*BatchResponse_Rejected) ProtoMessage() {} +func (*BulkResponse_Rejected) ProtoMessage() {} -func (x *BatchResponse_Rejected) ProtoReflect() protoreflect.Message { +func (x *BulkResponse_Rejected) ProtoReflect() protoreflect.Message { mi := &file_resource_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -3441,26 +3441,26 @@ func (x *BatchResponse_Rejected) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use BatchResponse_Rejected.ProtoReflect.Descriptor instead. -func (*BatchResponse_Rejected) Descriptor() ([]byte, []int) { +// Deprecated: Use BulkResponse_Rejected.ProtoReflect.Descriptor instead. +func (*BulkResponse_Rejected) Descriptor() ([]byte, []int) { return file_resource_proto_rawDescGZIP(), []int{20, 1} } -func (x *BatchResponse_Rejected) GetKey() *ResourceKey { +func (x *BulkResponse_Rejected) GetKey() *ResourceKey { if x != nil { return x.Key } return nil } -func (x *BatchResponse_Rejected) GetAction() BatchRequest_Action { +func (x *BulkResponse_Rejected) GetAction() BulkRequest_Action { if x != nil { return x.Action } - return BatchRequest_UNKNOWN + return BulkRequest_UNKNOWN } -func (x *BatchResponse_Rejected) GetError() string { +func (x *BulkResponse_Rejected) GetError() string { if x != nil { return x.Error } @@ -4184,427 +4184,426 @@ var file_resource_proto_rawDesc = string([]byte{ 0x44, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x4d, 0x4f, 0x44, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x42, 0x4f, 0x4f, 0x4b, 0x4d, 0x41, 0x52, 0x4b, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, - 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x05, 0x22, 0xd9, 0x01, 0x0a, 0x0c, 0x42, 0x61, 0x74, 0x63, - 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, - 0x79, 0x12, 0x35, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x42, 0x61, 0x74, - 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x16, - 0x0a, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x22, 0x3b, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, - 0x05, 0x41, 0x44, 0x44, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x4d, 0x4f, 0x44, 0x49, - 0x46, 0x49, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, - 0x44, 0x10, 0x03, 0x22, 0xdf, 0x04, 0x0a, 0x0d, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, + 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x05, 0x22, 0xd7, 0x01, 0x0a, 0x0b, 0x42, 0x75, 0x6c, 0x6b, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, - 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, - 0x6f, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, - 0x12, 0x39, 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x03, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1f, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x42, 0x61, 0x74, - 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x75, 0x6d, 0x6d, 0x61, - 0x72, 0x79, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x3c, 0x0a, 0x08, 0x72, - 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x52, - 0x08, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x1a, 0x86, 0x02, 0x0a, 0x07, 0x53, 0x75, - 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x68, - 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x68, 0x69, - 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, - 0x75, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, - 0x6f, 0x75, 0x73, 0x5f, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x0f, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x48, 0x69, 0x73, 0x74, 0x6f, - 0x72, 0x79, 0x1a, 0x80, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, - 0x27, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x35, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x62, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, - 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6b, - 0x69, 0x6e, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6b, 0x69, 0x6e, 0x64, - 0x73, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x22, 0xd2, 0x01, 0x0a, 0x15, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x34, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x1c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x42, 0x75, 0x6c, 0x6b, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x16, 0x0a, 0x06, + 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, + 0x6c, 0x64, 0x65, 0x72, 0x22, 0x3b, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b, + 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x41, + 0x44, 0x44, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x4d, 0x4f, 0x44, 0x49, 0x46, 0x49, + 0x45, 0x44, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, + 0x03, 0x22, 0xda, 0x04, 0x0a, 0x0c, 0x42, 0x75, 0x6c, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, + 0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, + 0x1c, 0x0a, 0x09, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x12, 0x38, 0x0a, + 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, + 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x42, 0x75, 0x6c, 0x6b, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x07, + 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x3b, 0x0a, 0x08, 0x72, 0x65, 0x6a, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x2e, 0x42, 0x75, 0x6c, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x2e, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x52, 0x08, 0x72, 0x65, 0x6a, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x1a, 0x86, 0x02, 0x0a, 0x07, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, + 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, + 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, + 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, + 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x70, + 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0d, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x68, + 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x70, 0x72, + 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x1a, 0x7f, 0x0a, + 0x08, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x27, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x34, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x42, 0x75, + 0x6c, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x62, + 0x0a, 0x14, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6b, 0x69, 0x6e, 0x64, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x05, 0x6b, 0x69, 0x6e, 0x64, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, + 0x6c, 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c, 0x64, + 0x65, 0x72, 0x22, 0xd2, 0x01, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, + 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x05, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x3b, 0x0a, 0x05, 0x73, 0x74, 0x61, + 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, + 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x1a, 0x4f, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, + 0x14, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x8e, 0x05, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x2f, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x12, 0x33, 0x0a, 0x09, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x09, 0x66, 0x65, + 0x64, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x14, 0x0a, + 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, + 0x6d, 0x69, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x3c, 0x0a, 0x06, 0x73, + 0x6f, 0x72, 0x74, 0x42, 0x79, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x53, 0x6f, 0x72, + 0x74, 0x52, 0x06, 0x73, 0x6f, 0x72, 0x74, 0x42, 0x79, 0x12, 0x40, 0x0a, 0x05, 0x66, 0x61, 0x63, + 0x65, 0x74, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x46, 0x61, 0x63, 0x65, 0x74, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x66, 0x61, 0x63, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x66, + 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x66, 0x69, 0x65, + 0x6c, 0x64, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x12, 0x1d, 0x0a, + 0x0a, 0x69, 0x73, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x09, 0x69, 0x73, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, + 0x70, 0x61, 0x67, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, + 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0c, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x1a, 0x30, 0x0a, 0x04, 0x53, 0x6f, 0x72, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x12, + 0x0a, 0x04, 0x64, 0x65, 0x73, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x64, 0x65, + 0x73, 0x63, 0x1a, 0x33, 0x0a, 0x05, 0x46, 0x61, 0x63, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x66, + 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, + 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x1a, 0x5f, 0x0a, 0x0a, 0x46, 0x61, 0x63, 0x65, 0x74, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x3b, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x46, 0x61, 0x63, 0x65, 0x74, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xea, 0x04, 0x0a, 0x16, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, - 0x12, 0x3b, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x1a, 0x4f, 0x0a, - 0x05, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x1a, 0x0a, 0x08, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x8e, - 0x05, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, - 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x33, 0x0a, 0x09, 0x66, 0x65, 0x64, - 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x4b, 0x65, 0x79, 0x52, 0x09, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x12, 0x14, - 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, - 0x75, 0x65, 0x72, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, - 0x66, 0x73, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, - 0x65, 0x74, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x6f, 0x72, 0x74, 0x42, 0x79, 0x18, 0x06, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x2e, 0x53, 0x6f, 0x72, 0x74, 0x52, 0x06, 0x73, 0x6f, 0x72, 0x74, 0x42, 0x79, - 0x12, 0x40, 0x0a, 0x05, 0x66, 0x61, 0x63, 0x65, 0x74, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x2a, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x2e, 0x46, 0x61, 0x63, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x66, 0x61, 0x63, - 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x08, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x78, - 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x78, 0x70, - 0x6c, 0x61, 0x69, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x70, 0x65, 0x72, - 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x30, 0x0a, 0x04, 0x53, 0x6f, 0x72, 0x74, 0x12, - 0x14, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x66, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x63, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x04, 0x64, 0x65, 0x73, 0x63, 0x1a, 0x33, 0x0a, 0x05, 0x46, 0x61, 0x63, - 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x1a, 0x5f, - 0x0a, 0x0a, 0x46, 0x61, 0x63, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, - 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x3b, - 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, + 0x12, 0x27, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x46, - 0x61, 0x63, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, - 0xea, 0x04, 0x0a, 0x16, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, - 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, - 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x27, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, + 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x31, 0x0a, 0x07, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, + 0x62, 0x6c, 0x65, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, + 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x68, 0x69, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x09, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x48, 0x69, 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x71, + 0x75, 0x65, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x52, + 0x09, 0x71, 0x75, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, + 0x78, 0x5f, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x6d, + 0x61, 0x78, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x41, 0x0a, 0x05, 0x66, 0x61, 0x63, 0x65, 0x74, + 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x46, 0x61, 0x63, 0x65, 0x74, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x05, 0x66, 0x61, 0x63, 0x65, 0x74, 0x1a, 0x8f, 0x01, 0x0a, 0x05, 0x46, + 0x61, 0x63, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, + 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, + 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x07, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x12, 0x40, 0x0a, 0x05, 0x74, 0x65, + 0x72, 0x6d, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x54, 0x65, 0x72, 0x6d, + 0x46, 0x61, 0x63, 0x65, 0x74, 0x52, 0x05, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x1a, 0x35, 0x0a, 0x09, + 0x54, 0x65, 0x72, 0x6d, 0x46, 0x61, 0x63, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x72, + 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x72, 0x6d, 0x12, 0x14, 0x0a, + 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x1a, 0x60, 0x0a, 0x0a, 0x46, 0x61, 0x63, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x3c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x46, 0x61, 0x63, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x78, 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, + 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1c, 0x0a, + 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, + 0xda, 0x02, 0x0a, 0x1d, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, + 0x72, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x42, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x2c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, + 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, + 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2b, 0x0a, + 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x1a, 0x9f, 0x01, 0x0a, 0x04, 0x49, + 0x74, 0x65, 0x6d, 0x12, 0x2d, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69, + 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x14, + 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, + 0x69, 0x74, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x22, 0x51, 0x0a, 0x1d, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, + 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, + 0x94, 0x02, 0x0a, 0x1e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, + 0x6f, 0x72, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x36, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, + 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x1a, 0x77, 0x0a, + 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1e, + 0x0a, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x14, + 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x2e, 0x0a, 0x12, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0xab, 0x01, 0x0a, 0x13, 0x48, 0x65, 0x61, 0x6c, 0x74, + 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, + 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, + 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x22, 0x4f, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, + 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x45, 0x52, 0x56, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0f, + 0x0a, 0x0b, 0x4e, 0x4f, 0x54, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, + 0x13, 0x0a, 0x0f, 0x53, 0x45, 0x52, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, + 0x57, 0x4e, 0x10, 0x03, 0x22, 0x87, 0x02, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x41, 0x0a, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, + 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x12, 0x2e, 0x0a, 0x04, 0x72, 0x6f, 0x77, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, + 0x52, 0x6f, 0x77, 0x52, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, + 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x30, 0x0a, 0x14, + 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x72, 0x65, 0x6d, 0x61, + 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x49, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xf1, + 0x04, 0x0a, 0x1d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, + 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x46, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, + 0x6e, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6c, 0x75, + 0x6d, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x08, + 0x69, 0x73, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, + 0x69, 0x73, 0x41, 0x72, 0x72, 0x61, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x52, 0x0a, 0x0a, 0x70, 0x72, 0x6f, + 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x66, 0x69, + 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, + 0x73, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x1a, 0x0a, + 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x1a, 0xae, 0x01, 0x0a, 0x0a, 0x50, 0x72, + 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x6e, 0x69, 0x71, + 0x75, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0c, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x1b, 0x0a, + 0x09, 0x66, 0x72, 0x65, 0x65, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x08, 0x66, 0x72, 0x65, 0x65, 0x54, 0x65, 0x78, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, + 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, + 0x74, 0x5f, 0x6e, 0x75, 0x6c, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x6e, 0x6f, + 0x74, 0x4e, 0x75, 0x6c, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, + 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x64, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x95, 0x01, 0x0a, 0x0a, 0x43, + 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e, 0x4b, + 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x53, + 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x42, 0x4f, 0x4f, 0x4c, 0x45, + 0x41, 0x4e, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x54, 0x33, 0x32, 0x10, 0x03, 0x12, + 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x54, 0x36, 0x34, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x46, 0x4c, + 0x4f, 0x41, 0x54, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x4f, 0x55, 0x42, 0x4c, 0x45, 0x10, + 0x06, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x41, 0x54, 0x45, 0x10, 0x07, 0x12, 0x0d, 0x0a, 0x09, 0x44, + 0x41, 0x54, 0x45, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x10, 0x08, 0x12, 0x0a, 0x0a, 0x06, 0x42, 0x49, + 0x4e, 0x41, 0x52, 0x59, 0x10, 0x09, 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x42, 0x4a, 0x45, 0x43, 0x54, + 0x10, 0x0a, 0x22, 0x94, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, + 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x77, 0x12, 0x27, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, - 0x12, 0x31, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, - 0x6c, 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x68, 0x69, 0x74, - 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x48, 0x69, - 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x73, 0x74, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x52, 0x09, 0x71, 0x75, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x73, - 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x41, - 0x0a, 0x05, 0x66, 0x61, 0x63, 0x65, 0x74, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, - 0x46, 0x61, 0x63, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x66, 0x61, 0x63, 0x65, - 0x74, 0x1a, 0x8f, 0x01, 0x0a, 0x05, 0x46, 0x61, 0x63, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x66, - 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, - 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x69, 0x73, 0x73, 0x69, - 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, - 0x67, 0x12, 0x40, 0x0a, 0x05, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x2a, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x46, 0x61, 0x63, 0x65, 0x74, 0x52, 0x05, 0x74, 0x65, - 0x72, 0x6d, 0x73, 0x1a, 0x35, 0x0a, 0x09, 0x54, 0x65, 0x72, 0x6d, 0x46, 0x61, 0x63, 0x65, 0x74, - 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x74, 0x65, 0x72, 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x1a, 0x60, 0x0a, 0x0a, 0x46, 0x61, - 0x63, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x3c, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, - 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x46, 0x61, 0x63, 0x65, - 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x78, 0x0a, 0x1c, - 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4f, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0f, - 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xda, 0x02, 0x0a, 0x1d, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, - 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x26, 0x0a, 0x0f, - 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, + 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x63, + 0x65, 0x6c, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x05, 0x63, 0x65, 0x6c, 0x6c, + 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x64, 0x0a, 0x0e, 0x52, 0x65, 0x73, + 0x74, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, + 0x69, 0x0a, 0x0f, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, + 0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, + 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xd3, 0x01, 0x0a, 0x0e, 0x50, + 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, + 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x12, 0x37, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x1f, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x50, 0x75, 0x74, 0x42, + 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, + 0x64, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x22, 0x1c, 0x0a, 0x06, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x08, 0x0a, 0x04, + 0x47, 0x52, 0x50, 0x43, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x01, + 0x22, 0xc1, 0x01, 0x0a, 0x0f, 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, - 0x72, 0x1a, 0x9f, 0x01, 0x0a, 0x04, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x2d, 0x0a, 0x06, 0x6f, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, - 0x79, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, - 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, - 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, - 0x68, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, - 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c, - 0x64, 0x65, 0x72, 0x22, 0x51, 0x0a, 0x1d, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6f, - 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x94, 0x02, 0x0a, 0x1e, 0x43, 0x6f, 0x75, 0x6e, 0x74, - 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x05, 0x69, 0x74, 0x65, - 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, - 0x6f, 0x72, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, - 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, - 0x72, 0x72, 0x6f, 0x72, 0x1a, 0x77, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, - 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, - 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x2e, 0x0a, - 0x12, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0xab, 0x01, - 0x0a, 0x13, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x4f, 0x0a, 0x0d, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, - 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x45, 0x52, 0x56, - 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x4e, 0x4f, 0x54, 0x5f, 0x53, 0x45, 0x52, - 0x56, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x45, 0x52, 0x56, 0x49, 0x43, - 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x22, 0x87, 0x02, 0x0a, 0x0d, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x41, 0x0a, - 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, - 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x66, - 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, - 0x12, 0x2e, 0x0a, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, - 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x77, 0x52, 0x04, 0x72, 0x6f, 0x77, 0x73, - 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, - 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, - 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x12, 0x30, 0x0a, 0x14, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, - 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x12, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x49, 0x74, 0x65, 0x6d, - 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xf1, 0x04, 0x0a, 0x1d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x66, - 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x46, 0x0a, 0x04, 0x74, - 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, - 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, - 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x41, 0x72, 0x72, 0x61, 0x79, 0x12, 0x20, - 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x52, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, - 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x50, 0x72, - 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, - 0x74, 0x69, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, - 0x1a, 0xae, 0x01, 0x0a, 0x0a, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, - 0x23, 0x0a, 0x0d, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x72, 0x65, 0x65, 0x5f, 0x74, 0x65, 0x78, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x66, 0x72, 0x65, 0x65, 0x54, 0x65, 0x78, - 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x61, 0x62, 0x6c, - 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x74, 0x5f, 0x6e, 0x75, 0x6c, 0x6c, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x07, 0x6e, 0x6f, 0x74, 0x4e, 0x75, 0x6c, 0x6c, 0x12, 0x23, 0x0a, 0x0d, - 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x22, 0x95, 0x01, 0x0a, 0x0a, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x79, 0x70, 0x65, - 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, - 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0b, - 0x0a, 0x07, 0x42, 0x4f, 0x4f, 0x4c, 0x45, 0x41, 0x4e, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x49, - 0x4e, 0x54, 0x33, 0x32, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x54, 0x36, 0x34, 0x10, - 0x04, 0x12, 0x09, 0x0a, 0x05, 0x46, 0x4c, 0x4f, 0x41, 0x54, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, - 0x44, 0x4f, 0x55, 0x42, 0x4c, 0x45, 0x10, 0x06, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x41, 0x54, 0x45, - 0x10, 0x07, 0x12, 0x0d, 0x0a, 0x09, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x10, - 0x08, 0x12, 0x0a, 0x0a, 0x06, 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x10, 0x09, 0x12, 0x0a, 0x0a, - 0x06, 0x4f, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x10, 0x0a, 0x22, 0x94, 0x01, 0x0a, 0x10, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x77, 0x12, 0x27, - 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, - 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, - 0x0c, 0x52, 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x22, 0x64, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x27, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x10, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x69, 0x0a, 0x0f, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, - 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, - 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x22, 0xd3, 0x01, 0x0a, 0x0e, 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x08, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x37, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x2e, 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, - 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, - 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x1c, 0x0a, 0x06, 0x4d, 0x65, 0x74, - 0x68, 0x6f, 0x64, 0x12, 0x08, 0x0a, 0x04, 0x47, 0x52, 0x50, 0x43, 0x10, 0x00, 0x12, 0x08, 0x0a, - 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x01, 0x22, 0xc1, 0x01, 0x0a, 0x0f, 0x50, 0x75, 0x74, 0x42, - 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x65, - 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, - 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, - 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, - 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, - 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x68, 0x61, 0x73, 0x68, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x79, 0x70, - 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x69, 0x6d, 0x65, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x22, 0xaa, 0x01, 0x0a, 0x0e, - 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, - 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x10, - 0x6d, 0x75, 0x73, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x6d, 0x75, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x78, - 0x79, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x69, 0x64, 0x22, 0x89, 0x01, 0x0a, 0x0f, 0x47, 0x65, 0x74, - 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x05, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, - 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, - 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x33, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x10, 0x0a, 0x0c, - 0x4e, 0x6f, 0x74, 0x4f, 0x6c, 0x64, 0x65, 0x72, 0x54, 0x68, 0x61, 0x6e, 0x10, 0x00, 0x12, 0x09, - 0x0a, 0x05, 0x45, 0x78, 0x61, 0x63, 0x74, 0x10, 0x01, 0x32, 0xad, 0x03, 0x0a, 0x0d, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x52, - 0x65, 0x61, 0x64, 0x12, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, - 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x3b, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x06, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x07, 0x52, 0x65, 0x73, - 0x74, 0x6f, 0x72, 0x65, 0x12, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, - 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, - 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x4c, 0x69, 0x73, - 0x74, 0x12, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x37, 0x0a, 0x05, 0x57, 0x61, 0x74, 0x63, 0x68, 0x12, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x14, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x57, 0x61, 0x74, - 0x63, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x32, 0x4f, 0x0a, 0x0a, 0x42, 0x61, 0x74, - 0x63, 0x68, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x41, 0x0a, 0x0c, 0x42, 0x61, 0x74, 0x63, 0x68, - 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x12, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x32, 0xa9, 0x01, 0x0a, 0x0d, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x4b, 0x0a, 0x06, - 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x1f, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, - 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x08, 0x47, 0x65, 0x74, - 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x1e, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xe8, 0x01, 0x0a, 0x0f, 0x52, 0x65, 0x70, 0x6f, 0x73, - 0x69, 0x74, 0x6f, 0x72, 0x79, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x6b, 0x0a, 0x16, 0x43, 0x6f, + 0x72, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x75, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, + 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x1b, 0x0a, + 0x09, 0x6d, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x6d, 0x69, 0x6d, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x68, + 0x61, 0x72, 0x73, 0x65, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x68, 0x61, + 0x72, 0x73, 0x65, 0x74, 0x22, 0xaa, 0x01, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, + 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x10, 0x6d, 0x75, 0x73, 0x74, 0x5f, 0x70, 0x72, + 0x6f, 0x78, 0x79, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0e, 0x6d, 0x75, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, + 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x69, + 0x64, 0x22, 0x89, 0x01, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x75, 0x72, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x33, 0x0a, + 0x14, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x4d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x10, 0x0a, 0x0c, 0x4e, 0x6f, 0x74, 0x4f, 0x6c, 0x64, 0x65, + 0x72, 0x54, 0x68, 0x61, 0x6e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x78, 0x61, 0x63, 0x74, + 0x10, 0x01, 0x32, 0xad, 0x03, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, + 0x74, 0x6f, 0x72, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x52, 0x65, 0x61, 0x64, 0x12, 0x15, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, + 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, + 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x12, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, + 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x07, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x18, 0x2e, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x15, 0x2e, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x05, 0x57, 0x61, 0x74, + 0x63, 0x68, 0x12, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x57, 0x61, + 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x30, 0x01, 0x32, 0x4b, 0x0a, 0x09, 0x42, 0x75, 0x6c, 0x6b, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, + 0x3e, 0x0a, 0x0b, 0x42, 0x75, 0x6c, 0x6b, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x12, 0x15, + 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x42, 0x75, 0x6c, 0x6b, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x2e, 0x42, 0x75, 0x6c, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x32, + 0xa9, 0x01, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x64, 0x65, + 0x78, 0x12, 0x4b, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x1f, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, + 0x0a, 0x08, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x1e, 0x2e, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, + 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, + 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xe8, 0x01, 0x0a, 0x0f, + 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, + 0x6b, 0x0a, 0x16, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, + 0x72, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x27, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, + 0x74, 0x6f, 0x72, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4f, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x73, 0x12, 0x27, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, - 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4f, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, - 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x68, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, - 0x12, 0x26, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, - 0x72, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x32, 0x8b, 0x01, 0x0a, 0x09, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, - 0x3e, 0x0a, 0x07, 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x12, 0x18, 0x2e, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, - 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x3e, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x12, 0x18, 0x2e, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, - 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, - 0x57, 0x0a, 0x0b, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x12, 0x48, - 0x0a, 0x09, 0x49, 0x73, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x12, 0x1c, 0x2e, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, - 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x39, 0x5a, 0x37, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x67, - 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x2f, 0x75, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x68, 0x0a, 0x15, + 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x26, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x8b, 0x01, 0x0a, 0x09, 0x42, 0x6c, 0x6f, 0x62, 0x53, + 0x74, 0x6f, 0x72, 0x65, 0x12, 0x3e, 0x0a, 0x07, 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x12, + 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x50, 0x75, 0x74, 0x42, 0x6c, + 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x2e, 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x12, + 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, + 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x57, 0x0a, 0x0b, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, + 0x69, 0x63, 0x73, 0x12, 0x48, 0x0a, 0x09, 0x49, 0x73, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, + 0x12, 0x1c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c, + 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, + 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x39, 0x5a, + 0x37, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x66, + 0x61, 0x6e, 0x61, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x70, 0x6b, 0x67, 0x2f, + 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2f, 0x75, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2f, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, }) var ( @@ -4625,7 +4624,7 @@ var file_resource_proto_goTypes = []any{ (ResourceVersionMatch)(0), // 0: resource.ResourceVersionMatch (ListRequest_Source)(0), // 1: resource.ListRequest.Source (WatchEvent_Type)(0), // 2: resource.WatchEvent.Type - (BatchRequest_Action)(0), // 3: resource.BatchRequest.Action + (BulkRequest_Action)(0), // 3: resource.BulkRequest.Action (HealthCheckResponse_ServingStatus)(0), // 4: resource.HealthCheckResponse.ServingStatus (ResourceTableColumnDefinition_ColumnType)(0), // 5: resource.ResourceTableColumnDefinition.ColumnType (PutBlobRequest_Method)(0), // 6: resource.PutBlobRequest.Method @@ -4648,8 +4647,8 @@ var file_resource_proto_goTypes = []any{ (*ListResponse)(nil), // 23: resource.ListResponse (*WatchRequest)(nil), // 24: resource.WatchRequest (*WatchEvent)(nil), // 25: resource.WatchEvent - (*BatchRequest)(nil), // 26: resource.BatchRequest - (*BatchResponse)(nil), // 27: resource.BatchResponse + (*BulkRequest)(nil), // 26: resource.BulkRequest + (*BulkResponse)(nil), // 27: resource.BulkResponse (*ResourceStatsRequest)(nil), // 28: resource.ResourceStatsRequest (*ResourceStatsResponse)(nil), // 29: resource.ResourceStatsResponse (*ResourceSearchRequest)(nil), // 30: resource.ResourceSearchRequest @@ -4670,8 +4669,8 @@ var file_resource_proto_goTypes = []any{ (*GetBlobRequest)(nil), // 45: resource.GetBlobRequest (*GetBlobResponse)(nil), // 46: resource.GetBlobResponse (*WatchEvent_Resource)(nil), // 47: resource.WatchEvent.Resource - (*BatchResponse_Summary)(nil), // 48: resource.BatchResponse.Summary - (*BatchResponse_Rejected)(nil), // 49: resource.BatchResponse.Rejected + (*BulkResponse_Summary)(nil), // 48: resource.BulkResponse.Summary + (*BulkResponse_Rejected)(nil), // 49: resource.BulkResponse.Rejected (*ResourceStatsResponse_Stats)(nil), // 50: resource.ResourceStatsResponse.Stats (*ResourceSearchRequest_Sort)(nil), // 51: resource.ResourceSearchRequest.Sort (*ResourceSearchRequest_Facet)(nil), // 52: resource.ResourceSearchRequest.Facet @@ -4706,11 +4705,11 @@ var file_resource_proto_depIdxs = []int32{ 2, // 19: resource.WatchEvent.type:type_name -> resource.WatchEvent.Type 47, // 20: resource.WatchEvent.resource:type_name -> resource.WatchEvent.Resource 47, // 21: resource.WatchEvent.previous:type_name -> resource.WatchEvent.Resource - 7, // 22: resource.BatchRequest.key:type_name -> resource.ResourceKey - 3, // 23: resource.BatchRequest.action:type_name -> resource.BatchRequest.Action - 9, // 24: resource.BatchResponse.error:type_name -> resource.ErrorResult - 48, // 25: resource.BatchResponse.summary:type_name -> resource.BatchResponse.Summary - 49, // 26: resource.BatchResponse.rejected:type_name -> resource.BatchResponse.Rejected + 7, // 22: resource.BulkRequest.key:type_name -> resource.ResourceKey + 3, // 23: resource.BulkRequest.action:type_name -> resource.BulkRequest.Action + 9, // 24: resource.BulkResponse.error:type_name -> resource.ErrorResult + 48, // 25: resource.BulkResponse.summary:type_name -> resource.BulkResponse.Summary + 49, // 26: resource.BulkResponse.rejected:type_name -> resource.BulkResponse.Rejected 9, // 27: resource.ResourceStatsResponse.error:type_name -> resource.ErrorResult 50, // 28: resource.ResourceStatsResponse.stats:type_name -> resource.ResourceStatsResponse.Stats 21, // 29: resource.ResourceSearchRequest.options:type_name -> resource.ListOptions @@ -4738,8 +4737,8 @@ var file_resource_proto_depIdxs = []int32{ 9, // 51: resource.PutBlobResponse.error:type_name -> resource.ErrorResult 7, // 52: resource.GetBlobRequest.resource:type_name -> resource.ResourceKey 9, // 53: resource.GetBlobResponse.error:type_name -> resource.ErrorResult - 7, // 54: resource.BatchResponse.Rejected.key:type_name -> resource.ResourceKey - 3, // 55: resource.BatchResponse.Rejected.action:type_name -> resource.BatchRequest.Action + 7, // 54: resource.BulkResponse.Rejected.key:type_name -> resource.ResourceKey + 3, // 55: resource.BulkResponse.Rejected.action:type_name -> resource.BulkRequest.Action 52, // 56: resource.ResourceSearchRequest.FacetEntry.value:type_name -> resource.ResourceSearchRequest.Facet 55, // 57: resource.ResourceSearchResponse.Facet.terms:type_name -> resource.ResourceSearchResponse.TermFacet 54, // 58: resource.ResourceSearchResponse.FacetEntry.value:type_name -> resource.ResourceSearchResponse.Facet @@ -4751,7 +4750,7 @@ var file_resource_proto_depIdxs = []int32{ 41, // 64: resource.ResourceStore.Restore:input_type -> resource.RestoreRequest 22, // 65: resource.ResourceStore.List:input_type -> resource.ListRequest 24, // 66: resource.ResourceStore.Watch:input_type -> resource.WatchRequest - 26, // 67: resource.BatchStore.BatchProcess:input_type -> resource.BatchRequest + 26, // 67: resource.BulkStore.BulkProcess:input_type -> resource.BulkRequest 30, // 68: resource.ResourceIndex.Search:input_type -> resource.ResourceSearchRequest 28, // 69: resource.ResourceIndex.GetStats:input_type -> resource.ResourceStatsRequest 34, // 70: resource.RepositoryIndex.CountRepositoryObjects:input_type -> resource.CountRepositoryObjectsRequest @@ -4766,7 +4765,7 @@ var file_resource_proto_depIdxs = []int32{ 42, // 79: resource.ResourceStore.Restore:output_type -> resource.RestoreResponse 23, // 80: resource.ResourceStore.List:output_type -> resource.ListResponse 25, // 81: resource.ResourceStore.Watch:output_type -> resource.WatchEvent - 27, // 82: resource.BatchStore.BatchProcess:output_type -> resource.BatchResponse + 27, // 82: resource.BulkStore.BulkProcess:output_type -> resource.BulkResponse 31, // 83: resource.ResourceIndex.Search:output_type -> resource.ResourceSearchResponse 29, // 84: resource.ResourceIndex.GetStats:output_type -> resource.ResourceStatsResponse 35, // 85: resource.RepositoryIndex.CountRepositoryObjects:output_type -> resource.CountRepositoryObjectsResponse diff --git a/pkg/storage/unified/resource/resource.proto b/pkg/storage/unified/resource/resource.proto index 55314f836be..ea1d59cc83f 100644 --- a/pkg/storage/unified/resource/resource.proto +++ b/pkg/storage/unified/resource/resource.proto @@ -318,7 +318,7 @@ message WatchEvent { Resource previous = 4; } -message BatchRequest { +message BulkRequest { enum Action { // will be an error UNKNOWN = 0; @@ -342,7 +342,7 @@ message BatchRequest { string folder = 4; } -message BatchResponse { +message BulkResponse { message Summary { string namespace = 1; string group = 2; @@ -359,7 +359,7 @@ message BatchResponse { // Collect a few invalid messages message Rejected { ResourceKey key = 1; - BatchRequest.Action action = 2; + BulkRequest.Action action = 2; string error = 3; } @@ -818,11 +818,11 @@ service ResourceStore { rpc Watch(WatchRequest) returns (stream WatchEvent); } -service BatchStore { +service BulkStore { // Write multiple resources to the same Namespace/Group/Resource // Events will not be sent until the stream is complete // Only the *create* permissions is checked - rpc BatchProcess(stream BatchRequest) returns (BatchResponse); + rpc BulkProcess(stream BulkRequest) returns (BulkResponse); } // Unlike the ResourceStore, this service can be exposed to clients directly diff --git a/pkg/storage/unified/resource/resource_grpc.pb.go b/pkg/storage/unified/resource/resource_grpc.pb.go index c8cbb9569a0..74b085ccea0 100644 --- a/pkg/storage/unified/resource/resource_grpc.pb.go +++ b/pkg/storage/unified/resource/resource_grpc.pb.go @@ -386,128 +386,128 @@ var ResourceStore_ServiceDesc = grpc.ServiceDesc{ } const ( - BatchStore_BatchProcess_FullMethodName = "/resource.BatchStore/BatchProcess" + BulkStore_BulkProcess_FullMethodName = "/resource.BulkStore/BulkProcess" ) -// BatchStoreClient is the client API for BatchStore service. +// BulkStoreClient is the client API for BulkStore service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type BatchStoreClient interface { +type BulkStoreClient interface { // Write multiple resources to the same Namespace/Group/Resource // Events will not be sent until the stream is complete // Only the *create* permissions is checked - BatchProcess(ctx context.Context, opts ...grpc.CallOption) (BatchStore_BatchProcessClient, error) + BulkProcess(ctx context.Context, opts ...grpc.CallOption) (BulkStore_BulkProcessClient, error) } -type batchStoreClient struct { +type bulkStoreClient struct { cc grpc.ClientConnInterface } -func NewBatchStoreClient(cc grpc.ClientConnInterface) BatchStoreClient { - return &batchStoreClient{cc} +func NewBulkStoreClient(cc grpc.ClientConnInterface) BulkStoreClient { + return &bulkStoreClient{cc} } -func (c *batchStoreClient) BatchProcess(ctx context.Context, opts ...grpc.CallOption) (BatchStore_BatchProcessClient, error) { +func (c *bulkStoreClient) BulkProcess(ctx context.Context, opts ...grpc.CallOption) (BulkStore_BulkProcessClient, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - stream, err := c.cc.NewStream(ctx, &BatchStore_ServiceDesc.Streams[0], BatchStore_BatchProcess_FullMethodName, cOpts...) + stream, err := c.cc.NewStream(ctx, &BulkStore_ServiceDesc.Streams[0], BulkStore_BulkProcess_FullMethodName, cOpts...) if err != nil { return nil, err } - x := &batchStoreBatchProcessClient{ClientStream: stream} + x := &bulkStoreBulkProcessClient{ClientStream: stream} return x, nil } -type BatchStore_BatchProcessClient interface { - Send(*BatchRequest) error - CloseAndRecv() (*BatchResponse, error) +type BulkStore_BulkProcessClient interface { + Send(*BulkRequest) error + CloseAndRecv() (*BulkResponse, error) grpc.ClientStream } -type batchStoreBatchProcessClient struct { +type bulkStoreBulkProcessClient struct { grpc.ClientStream } -func (x *batchStoreBatchProcessClient) Send(m *BatchRequest) error { +func (x *bulkStoreBulkProcessClient) Send(m *BulkRequest) error { return x.ClientStream.SendMsg(m) } -func (x *batchStoreBatchProcessClient) CloseAndRecv() (*BatchResponse, error) { +func (x *bulkStoreBulkProcessClient) CloseAndRecv() (*BulkResponse, error) { if err := x.ClientStream.CloseSend(); err != nil { return nil, err } - m := new(BatchResponse) + m := new(BulkResponse) if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err } return m, nil } -// BatchStoreServer is the server API for BatchStore service. -// All implementations should embed UnimplementedBatchStoreServer +// BulkStoreServer is the server API for BulkStore service. +// All implementations should embed UnimplementedBulkStoreServer // for forward compatibility -type BatchStoreServer interface { +type BulkStoreServer interface { // Write multiple resources to the same Namespace/Group/Resource // Events will not be sent until the stream is complete // Only the *create* permissions is checked - BatchProcess(BatchStore_BatchProcessServer) error + BulkProcess(BulkStore_BulkProcessServer) error } -// UnimplementedBatchStoreServer should be embedded to have forward compatible implementations. -type UnimplementedBatchStoreServer struct { +// UnimplementedBulkStoreServer should be embedded to have forward compatible implementations. +type UnimplementedBulkStoreServer struct { } -func (UnimplementedBatchStoreServer) BatchProcess(BatchStore_BatchProcessServer) error { - return status.Errorf(codes.Unimplemented, "method BatchProcess not implemented") +func (UnimplementedBulkStoreServer) BulkProcess(BulkStore_BulkProcessServer) error { + return status.Errorf(codes.Unimplemented, "method BulkProcess not implemented") } -// UnsafeBatchStoreServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to BatchStoreServer will +// UnsafeBulkStoreServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to BulkStoreServer will // result in compilation errors. -type UnsafeBatchStoreServer interface { - mustEmbedUnimplementedBatchStoreServer() +type UnsafeBulkStoreServer interface { + mustEmbedUnimplementedBulkStoreServer() } -func RegisterBatchStoreServer(s grpc.ServiceRegistrar, srv BatchStoreServer) { - s.RegisterService(&BatchStore_ServiceDesc, srv) +func RegisterBulkStoreServer(s grpc.ServiceRegistrar, srv BulkStoreServer) { + s.RegisterService(&BulkStore_ServiceDesc, srv) } -func _BatchStore_BatchProcess_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(BatchStoreServer).BatchProcess(&batchStoreBatchProcessServer{ServerStream: stream}) +func _BulkStore_BulkProcess_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(BulkStoreServer).BulkProcess(&bulkStoreBulkProcessServer{ServerStream: stream}) } -type BatchStore_BatchProcessServer interface { - SendAndClose(*BatchResponse) error - Recv() (*BatchRequest, error) +type BulkStore_BulkProcessServer interface { + SendAndClose(*BulkResponse) error + Recv() (*BulkRequest, error) grpc.ServerStream } -type batchStoreBatchProcessServer struct { +type bulkStoreBulkProcessServer struct { grpc.ServerStream } -func (x *batchStoreBatchProcessServer) SendAndClose(m *BatchResponse) error { +func (x *bulkStoreBulkProcessServer) SendAndClose(m *BulkResponse) error { return x.ServerStream.SendMsg(m) } -func (x *batchStoreBatchProcessServer) Recv() (*BatchRequest, error) { - m := new(BatchRequest) +func (x *bulkStoreBulkProcessServer) Recv() (*BulkRequest, error) { + m := new(BulkRequest) if err := x.ServerStream.RecvMsg(m); err != nil { return nil, err } return m, nil } -// BatchStore_ServiceDesc is the grpc.ServiceDesc for BatchStore service. +// BulkStore_ServiceDesc is the grpc.ServiceDesc for BulkStore service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) -var BatchStore_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "resource.BatchStore", - HandlerType: (*BatchStoreServer)(nil), +var BulkStore_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "resource.BulkStore", + HandlerType: (*BulkStoreServer)(nil), Methods: []grpc.MethodDesc{}, Streams: []grpc.StreamDesc{ { - StreamName: "BatchProcess", - Handler: _BatchStore_BatchProcess_Handler, + StreamName: "BulkProcess", + Handler: _BulkStore_BulkProcess_Handler, ClientStreams: true, }, }, diff --git a/pkg/storage/unified/resource/server.go b/pkg/storage/unified/resource/server.go index b9ddcf14018..89b07c616a0 100644 --- a/pkg/storage/unified/resource/server.go +++ b/pkg/storage/unified/resource/server.go @@ -26,7 +26,7 @@ import ( // ResourceServer implements all gRPC services type ResourceServer interface { ResourceStoreServer - BatchStoreServer + BulkStoreServer ResourceIndexServer RepositoryIndexServer BlobStoreServer diff --git a/pkg/storage/unified/sql/backend.go b/pkg/storage/unified/sql/backend.go index c404e467eed..3c4d1ab5164 100644 --- a/pkg/storage/unified/sql/backend.go +++ b/pkg/storage/unified/sql/backend.go @@ -69,7 +69,7 @@ func NewBackend(opts BackendOptions) (Backend, error) { dbProvider: opts.DBProvider, pollingInterval: opts.PollingInterval, watchBufferSize: opts.WatchBufferSize, - batchLock: &batchLock{running: make(map[string]bool)}, + bulkLock: &bulkLock{running: make(map[string]bool)}, simulatedNetworkLatency: opts.SimulatedNetworkLatency, }, nil } @@ -92,7 +92,7 @@ type backend struct { dbProvider db.DBProvider db db.DB dialect sqltemplate.Dialect - batchLock *batchLock + bulkLock *bulkLock // watch streaming //stream chan *resource.WatchEvent diff --git a/pkg/storage/unified/sql/batch.go b/pkg/storage/unified/sql/bulk.go similarity index 75% rename from pkg/storage/unified/sql/batch.go rename to pkg/storage/unified/sql/bulk.go index 75221c98b32..dfc6703b06f 100644 --- a/pkg/storage/unified/sql/batch.go +++ b/pkg/storage/unified/sql/bulk.go @@ -23,23 +23,24 @@ import ( ) var ( - _ resource.BatchProcessingBackend = (*backend)(nil) + _ resource.BulkProcessingBackend = (*backend)(nil) ) -type batchRV struct { +type bulkRV struct { max int64 counter int64 } -func newBatchRV() *batchRV { +// When executing a bulk import we can fake the RV values +func newBulkRV() *bulkRV { t := time.Now().Truncate(time.Second * 10) - return &batchRV{ + return &bulkRV{ max: (t.UnixMicro() / 10000000) * 10000000, counter: 0, } } -func (x *batchRV) next(obj metav1.Object) int64 { +func (x *bulkRV) next(obj metav1.Object) int64 { ts := obj.GetCreationTimestamp().UnixMicro() anno := obj.GetAnnotations() if anno != nil { @@ -56,23 +57,23 @@ func (x *batchRV) next(obj metav1.Object) int64 { return (ts/10000000)*10000000 + x.counter } -type batchLock struct { +type bulkLock struct { running map[string]bool mu sync.Mutex } -func (x *batchLock) Start(keys []*resource.ResourceKey) error { +func (x *bulkLock) Start(keys []*resource.ResourceKey) error { x.mu.Lock() defer x.mu.Unlock() // First verify that it is not already running ids := make([]string, len(keys)) for i, k := range keys { - id := k.BatchID() + id := k.NSGR() if x.running[id] { return &apierrors.StatusError{ErrStatus: metav1.Status{ Code: http.StatusPreconditionFailed, - Message: "batch export is already running", + Message: "bulk export is already running", }} } ids[i] = id @@ -85,47 +86,47 @@ func (x *batchLock) Start(keys []*resource.ResourceKey) error { return nil } -func (x *batchLock) Finish(keys []*resource.ResourceKey) { +func (x *bulkLock) Finish(keys []*resource.ResourceKey) { x.mu.Lock() defer x.mu.Unlock() for _, k := range keys { - delete(x.running, k.BatchID()) + delete(x.running, k.NSGR()) } } -func (x *batchLock) Active() bool { +func (x *bulkLock) Active() bool { x.mu.Lock() defer x.mu.Unlock() return len(x.running) > 0 } -func (b *backend) ProcessBatch(ctx context.Context, setting resource.BatchSettings, iter resource.BatchRequestIterator) *resource.BatchResponse { - err := b.batchLock.Start(setting.Collection) +func (b *backend) ProcessBulk(ctx context.Context, setting resource.BulkSettings, iter resource.BulkRequestIterator) *resource.BulkResponse { + err := b.bulkLock.Start(setting.Collection) if err != nil { - return &resource.BatchResponse{ + return &resource.BulkResponse{ Error: resource.AsErrorResult(err), } } - defer b.batchLock.Finish(setting.Collection) + defer b.bulkLock.Finish(setting.Collection) // We may want to first write parquet, then read parquet if b.dialect.DialectName() == "sqlite" { - file, err := os.CreateTemp("", "grafana-batch-export-*.parquet") + file, err := os.CreateTemp("", "grafana-bulk-export-*.parquet") if err != nil { - return &resource.BatchResponse{ + return &resource.BulkResponse{ Error: resource.AsErrorResult(err), } } writer, err := parquet.NewParquetWriter(file) if err != nil { - return &resource.BatchResponse{ + return &resource.BulkResponse{ Error: resource.AsErrorResult(err), } } - // write batch to parquet - rsp := writer.ProcessBatch(ctx, setting, iter) + // write bulk to parquet + rsp := writer.ProcessBulk(ctx, setting, iter) if rsp.Error != nil { return rsp } @@ -135,18 +136,18 @@ func (b *backend) ProcessBatch(ctx context.Context, setting resource.BatchSettin // Replace the iterator with one from parquet iter, err = parquet.NewParquetReader(file.Name(), 50) if err != nil { - return &resource.BatchResponse{ + return &resource.BulkResponse{ Error: resource.AsErrorResult(err), } } } - return b.processBatch(ctx, setting, iter) + return b.processBulk(ctx, setting, iter) } -// internal batch process -func (b *backend) processBatch(ctx context.Context, setting resource.BatchSettings, iter resource.BatchRequestIterator) *resource.BatchResponse { - rsp := &resource.BatchResponse{} +// internal bulk process +func (b *backend) processBulk(ctx context.Context, setting resource.BulkSettings, iter resource.BulkRequestIterator) *resource.BulkResponse { + rsp := &resource.BulkResponse{} err := b.db.WithTx(ctx, ReadCommitted, func(ctx context.Context, tx db.Tx) error { rollbackWithError := func(err error) error { txerr := tx.Rollback() @@ -157,7 +158,7 @@ func (b *backend) processBatch(ctx context.Context, setting resource.BatchSettin } return err } - batch := &batchWroker{ + bulk := &bulkWroker{ ctx: ctx, tx: tx, dialect: b.dialect, @@ -165,18 +166,18 @@ func (b *backend) processBatch(ctx context.Context, setting resource.BatchSettin } // Calculate the RV based on incoming request timestamps - rv := newBatchRV() + rv := newBulkRV() - summaries := make(map[string]*resource.BatchResponse_Summary, len(setting.Collection)*4) + summaries := make(map[string]*resource.BulkResponse_Summary, len(setting.Collection)*4) // First clear everything in the transaction if setting.RebuildCollection { for _, key := range setting.Collection { - summary, err := batch.deleteCollection(key) + summary, err := bulk.deleteCollection(key) if err != nil { return rollbackWithError(err) } - summaries[key.BatchID()] = summary + summaries[key.NSGR()] = summary rsp.Summary = append(rsp.Summary, summary) } } @@ -194,8 +195,8 @@ func (b *backend) processBatch(ctx context.Context, setting resource.BatchSettin } rsp.Processed++ - if req.Action == resource.BatchRequest_UNKNOWN { - rsp.Rejected = append(rsp.Rejected, &resource.BatchResponse_Rejected{ + if req.Action == resource.BulkRequest_UNKNOWN { + rsp.Rejected = append(rsp.Rejected, &resource.BulkResponse_Rejected{ Key: req.Key, Action: req.Action, Error: "unknown action", @@ -205,7 +206,7 @@ func (b *backend) processBatch(ctx context.Context, setting resource.BatchSettin err := obj.UnmarshalJSON(req.Value) if err != nil { - rsp.Rejected = append(rsp.Rejected, &resource.BatchResponse_Rejected{ + rsp.Rejected = append(rsp.Rejected, &resource.BulkResponse_Rejected{ Key: req.Key, Action: req.Action, Error: "unable to unmarshal json", @@ -238,7 +239,7 @@ func (b *backend) processBatch(ctx context.Context, setting resource.BatchSettin return rollbackWithError(fmt.Errorf("missing summary key for: %s", k)) } - err := batch.syncCollection(key, summary) + err := bulk.syncCollection(key, summary) if err != nil { return err } @@ -257,7 +258,7 @@ func (b *backend) processBatch(ctx context.Context, setting resource.BatchSettin return rsp } -type batchWroker struct { +type bulkWroker struct { ctx context.Context tx db.ContextExecer dialect sqltemplate.Dialect @@ -265,8 +266,8 @@ type batchWroker struct { } // This will remove everything from the `resource` and `resource_history` table for a given namespace/group/resource -func (w *batchWroker) deleteCollection(key *resource.ResourceKey) (*resource.BatchResponse_Summary, error) { - summary := &resource.BatchResponse_Summary{ +func (w *bulkWroker) deleteCollection(key *resource.ResourceKey) (*resource.BulkResponse_Summary, error) { + summary := &resource.BulkResponse_Summary{ Namespace: key.Namespace, Group: key.Group, Resource: key.Resource, @@ -303,8 +304,8 @@ func (w *batchWroker) deleteCollection(key *resource.ResourceKey) (*resource.Bat } // Copy the latest value from history into the active resource table -func (w *batchWroker) syncCollection(key *resource.ResourceKey, summary *resource.BatchResponse_Summary) error { - w.logger.Info("synchronize collection", "key", key.BatchID()) +func (w *bulkWroker) syncCollection(key *resource.ResourceKey, summary *resource.BulkResponse_Summary) error { + w.logger.Info("synchronize collection", "key", key.NSGR()) _, err := dbutil.Exec(w.ctx, w.tx, sqlResourceInsertFromHistory, &sqlResourceInsertFromHistoryRequest{ SQLTemplate: sqltemplate.New(w.dialect), Key: key, @@ -313,7 +314,7 @@ func (w *batchWroker) syncCollection(key *resource.ResourceKey, summary *resourc return err } - w.logger.Info("get stats (still in transaction)", "key", key.BatchID()) + w.logger.Info("get stats (still in transaction)", "key", key.NSGR()) rows, err := dbutil.QueryRows(w.ctx, w.tx, sqlResourceStats, &sqlStatsRequest{ SQLTemplate: sqltemplate.New(w.dialect), Namespace: key.Namespace, diff --git a/pkg/storage/unified/sql/batch_test.go b/pkg/storage/unified/sql/bulk_test.go similarity index 95% rename from pkg/storage/unified/sql/batch_test.go rename to pkg/storage/unified/sql/bulk_test.go index 789f9922a12..e1e00fb7839 100644 --- a/pkg/storage/unified/sql/batch_test.go +++ b/pkg/storage/unified/sql/bulk_test.go @@ -13,7 +13,7 @@ func TestBatch(t *testing.T) { t.Run("rv iterator", func(t *testing.T) { t.Parallel() - rv := newBatchRV() + rv := newBulkRV() v0 := rv.next(&unstructured.Unstructured{}) v1 := rv.next(&unstructured.Unstructured{}) v2 := rv.next(&unstructured.Unstructured{}) diff --git a/pkg/storage/unified/sql/notifier.go b/pkg/storage/unified/sql/notifier.go index a57ea6b4ec7..b7ba320122c 100644 --- a/pkg/storage/unified/sql/notifier.go +++ b/pkg/storage/unified/sql/notifier.go @@ -29,7 +29,7 @@ func newNotifier(b *backend) (eventNotifier, error) { watchBufferSize: b.watchBufferSize, log: b.log, tracer: b.tracer, - batchLock: b.batchLock, + bulkLock: b.bulkLock, listLatestRVs: b.listLatestRVs, historyPoll: func(ctx context.Context, grp string, res string, since int64) ([]*historyPollResponse, error) { var records []*historyPollResponse diff --git a/pkg/storage/unified/sql/notifier_sql.go b/pkg/storage/unified/sql/notifier_sql.go index 9940f7c882f..98f2c1fe655 100644 --- a/pkg/storage/unified/sql/notifier_sql.go +++ b/pkg/storage/unified/sql/notifier_sql.go @@ -5,17 +5,18 @@ import ( "fmt" "time" + "go.opentelemetry.io/otel/trace" + "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/storage/unified/resource" "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" - "go.opentelemetry.io/otel/trace" ) var ( // Validation errors. errHistoryPollRequired = fmt.Errorf("historyPoll is required") errListLatestRVsRequired = fmt.Errorf("listLatestRVs is required") - errBatchLockRequired = fmt.Errorf("batchLock is required") + errBulkLockRequired = fmt.Errorf("bulkLock is required") errTracerRequired = fmt.Errorf("tracer is required") errLogRequired = fmt.Errorf("log is required") errInvalidWatchBufferSize = fmt.Errorf("watchBufferSize must be greater than 0") @@ -33,7 +34,7 @@ type pollingNotifier struct { log log.Logger tracer trace.Tracer - batchLock *batchLock + bulkLock *bulkLock listLatestRVs func(ctx context.Context) (groupResourceRV, error) historyPoll func(ctx context.Context, grp string, res string, since int64) ([]*historyPollResponse, error) @@ -48,7 +49,7 @@ type pollingNotifierConfig struct { log log.Logger tracer trace.Tracer - batchLock *batchLock + bulkLock *bulkLock listLatestRVs func(ctx context.Context) (groupResourceRV, error) historyPoll func(ctx context.Context, grp string, res string, since int64) ([]*historyPollResponse, error) @@ -62,8 +63,8 @@ func (cfg *pollingNotifierConfig) validate() error { if cfg.listLatestRVs == nil { return errListLatestRVsRequired } - if cfg.batchLock == nil { - return errBatchLockRequired + if cfg.bulkLock == nil { + return errBulkLockRequired } if cfg.tracer == nil { return errTracerRequired @@ -96,7 +97,7 @@ func newPollingNotifier(cfg *pollingNotifierConfig) (*pollingNotifier, error) { watchBufferSize: cfg.watchBufferSize, log: cfg.log, tracer: cfg.tracer, - batchLock: cfg.batchLock, + bulkLock: cfg.bulkLock, listLatestRVs: cfg.listLatestRVs, historyPoll: cfg.historyPoll, done: cfg.done, diff --git a/pkg/storage/unified/sql/notifier_sql_test.go b/pkg/storage/unified/sql/notifier_sql_test.go index 07fcfac3365..30bddafa0f8 100644 --- a/pkg/storage/unified/sql/notifier_sql_test.go +++ b/pkg/storage/unified/sql/notifier_sql_test.go @@ -5,11 +5,12 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" + "go.opentelemetry.io/otel/trace/noop" + "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/storage/unified/resource" "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" - "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel/trace/noop" ) func TestPollingNotifierConfig(t *testing.T) { @@ -27,7 +28,7 @@ func TestPollingNotifierConfig(t *testing.T) { return nil, nil }, listLatestRVs: func(ctx context.Context) (groupResourceRV, error) { return nil, nil }, - batchLock: &batchLock{}, + bulkLock: &bulkLock{}, tracer: noop.NewTracerProvider().Tracer("test"), log: log.NewNopLogger(), watchBufferSize: 10, @@ -41,7 +42,7 @@ func TestPollingNotifierConfig(t *testing.T) { name: "missing historyPoll", config: &pollingNotifierConfig{ listLatestRVs: func(ctx context.Context) (groupResourceRV, error) { return nil, nil }, - batchLock: &batchLock{}, + bulkLock: &bulkLock{}, tracer: noop.NewTracerProvider().Tracer("test"), log: log.NewNopLogger(), watchBufferSize: 10, @@ -57,7 +58,7 @@ func TestPollingNotifierConfig(t *testing.T) { historyPoll: func(ctx context.Context, grp string, res string, since int64) ([]*historyPollResponse, error) { return nil, nil }, - batchLock: &batchLock{}, + bulkLock: &bulkLock{}, tracer: noop.NewTracerProvider().Tracer("test"), log: log.NewNopLogger(), watchBufferSize: 10, @@ -68,7 +69,7 @@ func TestPollingNotifierConfig(t *testing.T) { expectedErr: errListLatestRVsRequired, }, { - name: "missing batchLock", + name: "missing bulkLock", config: &pollingNotifierConfig{ historyPoll: func(ctx context.Context, grp string, res string, since int64) ([]*historyPollResponse, error) { return nil, nil @@ -81,7 +82,7 @@ func TestPollingNotifierConfig(t *testing.T) { done: make(chan struct{}), dialect: sqltemplate.SQLite, }, - expectedErr: errBatchLockRequired, + expectedErr: errBulkLockRequired, }, { name: "missing tracer", @@ -90,7 +91,7 @@ func TestPollingNotifierConfig(t *testing.T) { return nil, nil }, listLatestRVs: func(ctx context.Context) (groupResourceRV, error) { return nil, nil }, - batchLock: &batchLock{}, + bulkLock: &bulkLock{}, log: log.NewNopLogger(), watchBufferSize: 10, pollingInterval: time.Second, @@ -106,7 +107,7 @@ func TestPollingNotifierConfig(t *testing.T) { return nil, nil }, listLatestRVs: func(ctx context.Context) (groupResourceRV, error) { return nil, nil }, - batchLock: &batchLock{}, + bulkLock: &bulkLock{}, tracer: noop.NewTracerProvider().Tracer("test"), watchBufferSize: 10, pollingInterval: time.Second, @@ -122,7 +123,7 @@ func TestPollingNotifierConfig(t *testing.T) { return nil, nil }, listLatestRVs: func(ctx context.Context) (groupResourceRV, error) { return nil, nil }, - batchLock: &batchLock{}, + bulkLock: &bulkLock{}, tracer: noop.NewTracerProvider().Tracer("test"), log: log.NewNopLogger(), watchBufferSize: 0, @@ -139,7 +140,7 @@ func TestPollingNotifierConfig(t *testing.T) { return nil, nil }, listLatestRVs: func(ctx context.Context) (groupResourceRV, error) { return nil, nil }, - batchLock: &batchLock{}, + bulkLock: &bulkLock{}, tracer: noop.NewTracerProvider().Tracer("test"), log: log.NewNopLogger(), watchBufferSize: 10, @@ -156,7 +157,7 @@ func TestPollingNotifierConfig(t *testing.T) { return nil, nil }, listLatestRVs: func(ctx context.Context) (groupResourceRV, error) { return nil, nil }, - batchLock: &batchLock{}, + bulkLock: &bulkLock{}, tracer: noop.NewTracerProvider().Tracer("test"), log: log.NewNopLogger(), watchBufferSize: 10, @@ -172,7 +173,7 @@ func TestPollingNotifierConfig(t *testing.T) { return nil, nil }, listLatestRVs: func(ctx context.Context) (groupResourceRV, error) { return nil, nil }, - batchLock: &batchLock{}, + bulkLock: &bulkLock{}, tracer: noop.NewTracerProvider().Tracer("test"), log: log.NewNopLogger(), watchBufferSize: 10, @@ -244,7 +245,7 @@ func TestPollingNotifier(t *testing.T) { watchBufferSize: 10, log: log.NewNopLogger(), tracer: noop.NewTracerProvider().Tracer("test"), - batchLock: &batchLock{}, + bulkLock: &bulkLock{}, listLatestRVs: listLatestRVs, historyPoll: historyPoll, done: done, @@ -298,7 +299,7 @@ func TestPollingNotifier(t *testing.T) { watchBufferSize: 10, log: log.NewNopLogger(), tracer: noop.NewTracerProvider().Tracer("test"), - batchLock: &batchLock{}, + bulkLock: &bulkLock{}, listLatestRVs: listLatestRVs, historyPoll: historyPoll, done: done, @@ -332,7 +333,7 @@ func TestPollingNotifier(t *testing.T) { watchBufferSize: 10, log: log.NewNopLogger(), tracer: noop.NewTracerProvider().Tracer("test"), - batchLock: &batchLock{}, + bulkLock: &bulkLock{}, listLatestRVs: func(ctx context.Context) (groupResourceRV, error) { return nil, nil }, historyPoll: func(ctx context.Context, grp string, res string, since int64) ([]*historyPollResponse, error) { return nil, nil @@ -369,7 +370,7 @@ func TestPollingNotifier(t *testing.T) { watchBufferSize: 10, log: log.NewNopLogger(), tracer: noop.NewTracerProvider().Tracer("test"), - batchLock: &batchLock{}, + bulkLock: &bulkLock{}, listLatestRVs: func(ctx context.Context) (groupResourceRV, error) { return nil, nil }, historyPoll: func(ctx context.Context, grp string, res string, since int64) ([]*historyPollResponse, error) { return nil, nil diff --git a/pkg/storage/unified/sql/service.go b/pkg/storage/unified/sql/service.go index c788805944b..287f39f33d8 100644 --- a/pkg/storage/unified/sql/service.go +++ b/pkg/storage/unified/sql/service.go @@ -128,7 +128,7 @@ func (s *service) start(ctx context.Context) error { srv := s.handler.GetServer() resource.RegisterResourceStoreServer(srv, server) - resource.RegisterBatchStoreServer(srv, server) + resource.RegisterBulkStoreServer(srv, server) resource.RegisterResourceIndexServer(srv, server) resource.RegisterRepositoryIndexServer(srv, server) resource.RegisterBlobStoreServer(srv, server) From ccc1477c7dbcba57f10e0063b1316274552d6e52 Mon Sep 17 00:00:00 2001 From: Marcus Andersson Date: Fri, 28 Feb 2025 07:28:01 +0100 Subject: [PATCH 26/74] PluginExtensions: Migrate edit profile page to use new plugin components API (#101346) * wip. * Refactored page a bit. * Fixed tests. * Update public/app/features/profile/UserProfileEditTabs.tsx Co-authored-by: Levente Balogh * Changed name. * rename again. --------- Co-authored-by: Levente Balogh --- packages/grafana-data/src/index.ts | 1 + .../src/types/pluginExtensions.ts | 4 + .../pluginExtensions/usePluginComponents.ts | 4 +- .../extensions/usePluginComponents.tsx | 11 +- .../profile/UserProfileEditPage.test.tsx | 75 +++++------ .../features/profile/UserProfileEditPage.tsx | 119 +++--------------- .../features/profile/UserProfileEditTabs.tsx | 111 ++++++++++++++++ 7 files changed, 176 insertions(+), 149 deletions(-) create mode 100644 public/app/features/profile/UserProfileEditTabs.tsx diff --git a/packages/grafana-data/src/index.ts b/packages/grafana-data/src/index.ts index 67c8483ed11..699ab07e244 100644 --- a/packages/grafana-data/src/index.ts +++ b/packages/grafana-data/src/index.ts @@ -550,6 +550,7 @@ export { type PluginExtensionLink, type PluginExtensionComponent, type PluginExtensionComponentMeta, + type ComponentTypeWithExtensionMeta, type PluginExtensionConfig, type PluginExtensionFunction, type PluginExtensionLinkConfig, diff --git a/packages/grafana-data/src/types/pluginExtensions.ts b/packages/grafana-data/src/types/pluginExtensions.ts index 331f6db43da..4bd286d4e3b 100644 --- a/packages/grafana-data/src/types/pluginExtensions.ts +++ b/packages/grafana-data/src/types/pluginExtensions.ts @@ -39,6 +39,10 @@ export type PluginExtensionComponent = PluginExtensionBase & { component: React.ComponentType; }; +export type ComponentTypeWithExtensionMeta = React.ComponentType & { + meta: PluginExtensionComponentMeta; +}; + export type PluginExtensionFunction void> = PluginExtensionBase & { type: PluginExtensionTypes.function; fn: Signature; diff --git a/packages/grafana-runtime/src/services/pluginExtensions/usePluginComponents.ts b/packages/grafana-runtime/src/services/pluginExtensions/usePluginComponents.ts index 649c54d0414..6417062ab90 100644 --- a/packages/grafana-runtime/src/services/pluginExtensions/usePluginComponents.ts +++ b/packages/grafana-runtime/src/services/pluginExtensions/usePluginComponents.ts @@ -1,4 +1,4 @@ -import { PluginExtensionComponentMeta } from '@grafana/data'; +import { type ComponentTypeWithExtensionMeta } from '@grafana/data'; export type UsePluginComponentsOptions = { extensionPointId: string; @@ -6,7 +6,7 @@ export type UsePluginComponentsOptions = { }; export type UsePluginComponentsResult = { - components: Array & { meta: PluginExtensionComponentMeta }>; + components: Array>; isLoading: boolean; }; diff --git a/public/app/features/plugins/extensions/usePluginComponents.tsx b/public/app/features/plugins/extensions/usePluginComponents.tsx index c3e406d5d23..e453b306d84 100644 --- a/public/app/features/plugins/extensions/usePluginComponents.tsx +++ b/public/app/features/plugins/extensions/usePluginComponents.tsx @@ -1,7 +1,12 @@ import { useMemo } from 'react'; import { useObservable } from 'react-use'; -import { PluginExtensionComponentMeta, PluginExtensionTypes, usePluginContext } from '@grafana/data'; +import { + type ComponentTypeWithExtensionMeta, + type PluginExtensionComponentMeta, + PluginExtensionTypes, + usePluginContext, +} from '@grafana/data'; import { UsePluginComponentsOptions, UsePluginComponentsResult } from '@grafana/runtime'; import { useAddedComponentsRegistry } from './ExtensionRegistriesContext'; @@ -25,7 +30,7 @@ export function usePluginComponents({ return useMemo(() => { // For backwards compatibility we don't enable restrictions in production or when the hook is used in core Grafana. const enableRestrictions = isGrafanaDevMode() && pluginContext; - const components: Array & { meta: PluginExtensionComponentMeta }> = []; + const components: Array> = []; const extensionsByPlugin: Record = {}; const pluginId = pluginContext?.meta.id ?? ''; const pointLog = log.child({ @@ -84,7 +89,7 @@ export function usePluginComponents({ export function createComponentWithMeta( registryItem: AddedComponentRegistryItem, extensionPointId: string -): React.ComponentType & { meta: PluginExtensionComponentMeta } { +): ComponentTypeWithExtensionMeta { const { component: Component, ...config } = registryItem; function ComponentWithMeta(props: Props) { return ; diff --git a/public/app/features/profile/UserProfileEditPage.test.tsx b/public/app/features/profile/UserProfileEditPage.test.tsx index 9f0adc7cee1..83152dee2e1 100644 --- a/public/app/features/profile/UserProfileEditPage.test.tsx +++ b/public/app/features/profile/UserProfileEditPage.test.tsx @@ -1,25 +1,18 @@ -import { render, screen, waitFor, within } from '@testing-library/react'; +import { screen, waitFor, within } from '@testing-library/react'; import userEvent, { PointerEventsCheckLevel } from '@testing-library/user-event'; +import { render } from 'test/test-utils'; -import { OrgRole, PluginExtensionComponent, PluginExtensionTypes } from '@grafana/data'; +import { type ComponentTypeWithExtensionMeta, OrgRole } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; -import { setPluginExtensionsHook, UsePluginExtensions } from '@grafana/runtime'; -import * as useQueryParams from 'app/core/hooks/useQueryParams'; +import { setPluginComponentsHook, usePluginComponents } from '@grafana/runtime'; -import { TestProvider } from '../../../test/helpers/TestProvider'; import { backendSrv } from '../../core/services/backend_srv'; +import { createComponentWithMeta } from '../plugins/extensions/usePluginComponents'; import { getMockTeam } from '../teams/__mocks__/teamMocks'; import { Props, UserProfileEditPage } from './UserProfileEditPage'; import { initialUserState } from './state/reducers'; -const mockUseQueryParams = useQueryParams as { useQueryParams: typeof useQueryParams.useQueryParams }; - -jest.mock('app/core/hooks/useQueryParams', () => ({ - __esModule: true, - useQueryParams: () => [{}], -})); - jest.mock('app/features/dashboard/api/dashboard_api', () => ({ getDashboardAPI: () => ({ getDashboardDTO: jest.fn().mockResolvedValue({}), @@ -136,20 +129,23 @@ const _createTabName = (tab: ExtensionPointComponentTabs) => tab; const _createTabContent = (tabId: ExtensionPointComponentId) => `this is settings for component ${tabId}`; const generalTabName = 'General'; +const generalTestId = 'user-profile-edit-page'; const tabOneName = _createTabName(ExtensionPointComponentTabs.One); const tabTwoName = _createTabName(ExtensionPointComponentTabs.Two); const _createPluginExtensionPointComponent = ( id: ExtensionPointComponentId, tab: ExtensionPointComponentTabs -): PluginExtensionComponent => ({ - id, - type: PluginExtensionTypes.component, - title: _createTabName(tab), - description: '', // description isn't used here.. - component: () =>

{_createTabContent(id)}

, - pluginId: 'grafana-plugin', -}); +): ComponentTypeWithExtensionMeta => + createComponentWithMeta<{}>( + { + title: _createTabName(tab), + description: '', // description isn't used here.. + component: () =>

{_createTabContent(id)}

, + pluginId: 'grafana-plugin', + }, + id + ); const PluginExtensionPointComponent1 = _createPluginExtensionPointComponent( ExtensionPointComponentId.One, @@ -164,8 +160,8 @@ const PluginExtensionPointComponent3 = _createPluginExtensionPointComponent( ExtensionPointComponentTabs.Two ); -async function getTestContext(overrides: Partial = {}) { - const extensions = overrides.extensions || []; +async function getTestContext(overrides: Partial = {}) { + const components = overrides.components || []; jest.clearAllMocks(); const putSpy = jest.spyOn(backendSrv, 'put'); @@ -174,18 +170,12 @@ async function getTestContext(overrides: Partial = jest - .fn() - .mockReturnValue({ extensions, isLoading: false }); + const getter: typeof usePluginComponents = jest.fn().mockReturnValue({ components, isLoading: false }); - setPluginExtensionsHook(getter); + setPluginComponentsHook(getter); const props = { ...defaultProps, ...overrides }; - const { rerender } = render( - - - - ); + const { rerender } = render(); await waitFor(() => expect(props.initUserProfilePage).toHaveBeenCalledTimes(1)); @@ -334,7 +324,7 @@ describe('UserProfileEditPage', () => { }); describe('and a plugin registers a component against the user profile settings extension point', () => { - const extensions = [ + const components = [ PluginExtensionPointComponent1, PluginExtensionPointComponent2, PluginExtensionPointComponent3, @@ -347,7 +337,7 @@ describe('UserProfileEditPage', () => { }); it('should group registered components into tabs', async () => { - await getTestContext({ extensions }); + await getTestContext({ components }); const { extensionPointTabs, extensionPointTab } = getSelectors(); const _assertTab = (tabId: string, isDefault = false) => { @@ -363,10 +353,7 @@ describe('UserProfileEditPage', () => { }); it('should change the active tab when a tab is clicked and update the "tab" query param', async () => { - const mockUpdateQueryParams = jest.fn(); - mockUseQueryParams.useQueryParams = () => [{}, mockUpdateQueryParams]; - - await getTestContext({ extensions }); + await getTestContext({ components }); const { extensionPointTab } = getSelectors(); /** @@ -378,26 +365,24 @@ describe('UserProfileEditPage', () => { const tabTwoContent = _createTabContent(ExtensionPointComponentId.Three); // "General" should be the default content + expect(screen.queryByTestId(generalTestId)).toBeInTheDocument(); expect(screen.queryByText(tabOneContent1)).toBeNull(); expect(screen.queryByText(tabOneContent2)).toBeNull(); expect(screen.queryByText(tabTwoContent)).toBeNull(); await userEvent.click(extensionPointTab(tabOneName.toLowerCase())); - expect(mockUpdateQueryParams).toHaveBeenCalledTimes(1); - expect(mockUpdateQueryParams).toHaveBeenCalledWith({ tab: tabOneName.toLowerCase() }); - expect(screen.queryByText(tabOneContent1)).not.toBeNull(); - expect(screen.queryByText(tabOneContent2)).not.toBeNull(); + expect(screen.queryByTestId(generalTestId)).toBeNull(); + expect(screen.queryByText(tabOneContent1)).toBeInTheDocument(); + expect(screen.queryByText(tabOneContent2)).toBeInTheDocument(); expect(screen.queryByText(tabTwoContent)).toBeNull(); - mockUpdateQueryParams.mockClear(); await userEvent.click(extensionPointTab(tabTwoName.toLowerCase())); - expect(mockUpdateQueryParams).toHaveBeenCalledTimes(1); - expect(mockUpdateQueryParams).toHaveBeenCalledWith({ tab: tabTwoName.toLowerCase() }); + expect(screen.queryByTestId(generalTestId)).toBeNull(); expect(screen.queryByText(tabOneContent1)).toBeNull(); expect(screen.queryByText(tabOneContent2)).toBeNull(); - expect(screen.queryByText(tabTwoContent)).not.toBeNull(); + expect(screen.queryByText(tabTwoContent)).toBeInTheDocument(); }); }); }); diff --git a/public/app/features/profile/UserProfileEditPage.tsx b/public/app/features/profile/UserProfileEditPage.tsx index 4de0ebee3d4..c5f84818cb2 100644 --- a/public/app/features/profile/UserProfileEditPage.tsx +++ b/public/app/features/profile/UserProfileEditPage.tsx @@ -1,31 +1,20 @@ -import { Fragment, useState } from 'react'; import { connect, ConnectedProps } from 'react-redux'; import { useMount } from 'react-use'; -import { PluginExtensionComponent, PluginExtensionPoints } from '@grafana/data'; -import { selectors } from '@grafana/e2e-selectors'; -import { usePluginComponentExtensions } from '@grafana/runtime'; -import { Tab, TabsBar, TabContent, Stack } from '@grafana/ui'; +import { PluginExtensionPoints } from '@grafana/data'; +import { usePluginComponents } from '@grafana/runtime'; +import { Stack } from '@grafana/ui'; import { Page } from 'app/core/components/Page/Page'; import SharedPreferences from 'app/core/components/SharedPreferences/SharedPreferences'; -import { useQueryParams } from 'app/core/hooks/useQueryParams'; -import { t } from 'app/core/internationalization'; import { StoreState } from 'app/types'; import UserOrganizations from './UserOrganizations'; import UserProfileEditForm from './UserProfileEditForm'; +import { UserProfileEditTabs } from './UserProfileEditTabs'; import UserSessions from './UserSessions'; import { UserTeams } from './UserTeams'; import { changeUserOrg, initUserProfilePage, revokeUserSession, updateUserProfile } from './state/actions'; -const TAB_QUERY_PARAM = 'tab'; -const GENERAL_SETTINGS_TAB = 'general'; - -type TabInfo = { - id: string; - title: string; -}; - export interface OwnProps {} function mapStateToProps(state: StoreState) { @@ -68,95 +57,27 @@ export function UserProfileEditPage({ changeUserOrg, updateUserProfile, }: Props) { - const [queryParams, updateQueryParams] = useQueryParams(); - const tabQueryParam = queryParams[TAB_QUERY_PARAM]; - const [activeTab, setActiveTab] = useState( - typeof tabQueryParam === 'string' ? tabQueryParam : GENERAL_SETTINGS_TAB - ); - useMount(() => initUserProfilePage()); - const { extensions } = usePluginComponentExtensions({ extensionPointId: PluginExtensionPoints.UserProfileTab }); - - const groupedExtensionComponents = extensions.reduce>((acc, extension) => { - const { title } = extension; - if (acc[title]) { - acc[title].push(extension); - } else { - acc[title] = [extension]; - } - return acc; - }, {}); - - const convertExtensionComponentTitleToTabId = (title: string) => title.toLowerCase(); - - const showTabs = extensions.length > 0; - const tabs: TabInfo[] = [ - { - id: GENERAL_SETTINGS_TAB, - title: t('user-profile.tabs.general', 'General'), - }, - ...Object.keys(groupedExtensionComponents).map((title) => ({ - id: convertExtensionComponentTitleToTabId(title), - title, - })), - ]; - - const UserProfile = () => ( - - - - - - - - - - ); - - const UserProfileWithTabs = () => ( -
- - - {tabs.map(({ id, title }) => { - return ( - { - setActiveTab(id); - updateQueryParams({ [TAB_QUERY_PARAM]: id }); - }} - data-testid={selectors.components.UserProfile.extensionPointTab(id)} - /> - ); - })} - - - {activeTab === GENERAL_SETTINGS_TAB && } - {Object.entries(groupedExtensionComponents).map(([title, pluginExtensionComponents]) => { - const tabId = convertExtensionComponentTitleToTabId(title); - - if (activeTab === tabId) { - return ( - - {pluginExtensionComponents.map(({ component: Component }, index) => ( - - ))} - - ); - } - return null; - })} - - -
- ); + const { components, isLoading } = usePluginComponents({ + extensionPointId: PluginExtensionPoints.UserProfileTab, + }); return ( - {showTabs ? : } + + + + + + + + + + + + + ); } diff --git a/public/app/features/profile/UserProfileEditTabs.tsx b/public/app/features/profile/UserProfileEditTabs.tsx new file mode 100644 index 00000000000..035e0cf01e3 --- /dev/null +++ b/public/app/features/profile/UserProfileEditTabs.tsx @@ -0,0 +1,111 @@ +import React, { type ComponentType, Fragment, type ReactElement, useCallback, useMemo } from 'react'; + +import { type ComponentTypeWithExtensionMeta, type UrlQueryValue } from '@grafana/data'; +import { selectors } from '@grafana/e2e-selectors'; +import { Stack, Tab, TabContent, TabsBar } from '@grafana/ui'; +import { useQueryParams } from 'app/core/hooks/useQueryParams'; +import { t } from 'app/core/internationalization'; + +const TAB_QUERY_PARAM = 'tab'; +const GENERAL_SETTINGS_TAB = 'general'; + +type Props = { + children?: React.ReactNode; + components: ComponentTypeWithExtensionMeta[]; +}; + +export function UserProfileEditTabs(props: Props): ReactElement { + const { children, components } = props; + const tabsById = useTabInfoById(components, children); + const [activeTab, setActiveTab] = useActiveTab(tabsById); + const showTabs = components.length > 0; + + if (showTabs === false) { + return <>{children}; + } + + return ( +
+ + + {Object.values(tabsById).map(({ tabId, title }) => { + return ( + setActiveTab(tabId)} + data-testid={selectors.components.UserProfile.extensionPointTab(tabId)} + /> + ); + })} + + + {Boolean(activeTab) && ( + + {activeTab?.components.map((Component, index) => )} + + )} + + +
+ ); +} + +type TabInfo = { + title: string; + tabId: string; + components: ComponentType[]; +}; + +function useTabInfoById(components: Props['components'], general: React.ReactNode): Record { + return useMemo(() => { + const tabs: Record = { + [GENERAL_SETTINGS_TAB]: { + title: t('user-profile.tabs.general', 'General'), + tabId: GENERAL_SETTINGS_TAB, + components: [() => <>{general}], + }, + }; + + return components.reduce((acc, component) => { + const { title } = component.meta; + const tabId = convertTitleToTabId(title); + + if (!acc[tabId]) { + acc[tabId] = { + title, + tabId, + components: [], + }; + } + + acc[tabId].components.push(component); + return acc; + }, tabs); + }, [components, general]); +} + +function useActiveTab(tabs: Record): [TabInfo | undefined, (tabId: string) => void] { + const [queryParams, updateQueryParams] = useQueryParams(); + const activeTabId = convertQueryParamToTabId(queryParams[TAB_QUERY_PARAM]); + const activeTab = tabs[activeTabId]; + + const setActiveTab = useCallback( + (tabId: string) => updateQueryParams({ [TAB_QUERY_PARAM]: tabId }), + [updateQueryParams] + ); + + return [activeTab, setActiveTab]; +} + +function convertQueryParamToTabId(queryParam: UrlQueryValue) { + if (typeof queryParam !== 'string') { + return GENERAL_SETTINGS_TAB; + } + return convertTitleToTabId(queryParam); +} + +function convertTitleToTabId(title: string) { + return title.toLowerCase(); +} From d5ace043d6bc4c42555d25cd26f7112b031bec45 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 28 Feb 2025 08:41:02 +0100 Subject: [PATCH 27/74] Update Storybook updates (#100502) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- packages/grafana-ui/package.json | 30 +- yarn.lock | 1005 ++++++++++++++++-------------- 2 files changed, 540 insertions(+), 495 deletions(-) diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index 87cc03f93b7..032b629d2bb 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -118,22 +118,22 @@ "@faker-js/faker": "^9.0.0", "@grafana/tsconfig": "^2.0.0", "@rollup/plugin-node-resolve": "16.0.0", - "@storybook/addon-a11y": "^8.4.2", - "@storybook/addon-actions": "^8.4.2", - "@storybook/addon-docs": "^8.4.2", - "@storybook/addon-essentials": "^8.4.2", - "@storybook/addon-storysource": "^8.4.2", - "@storybook/addon-webpack5-compiler-swc": "^1.0.5", - "@storybook/blocks": "^8.4.2", - "@storybook/components": "^8.4.2", - "@storybook/core-events": "^8.4.2", - "@storybook/manager-api": "^8.4.2", + "@storybook/addon-a11y": "^8.6.2", + "@storybook/addon-actions": "^8.6.2", + "@storybook/addon-docs": "^8.6.2", + "@storybook/addon-essentials": "^8.6.2", + "@storybook/addon-storysource": "^8.6.2", + "@storybook/addon-webpack5-compiler-swc": "^2.1.0", + "@storybook/blocks": "^8.6.2", + "@storybook/components": "^8.6.2", + "@storybook/core-events": "^8.6.2", + "@storybook/manager-api": "^8.6.2", "@storybook/mdx2-csf": "1.1.0", "@storybook/preset-scss": "1.0.3", - "@storybook/preview-api": "^8.4.2", - "@storybook/react": "^8.4.2", - "@storybook/react-webpack5": "^8.4.2", - "@storybook/theming": "^8.4.2", + "@storybook/preview-api": "^8.6.2", + "@storybook/react": "^8.6.2", + "@storybook/react-webpack5": "^8.6.2", + "@storybook/theming": "^8.6.2", "@testing-library/dom": "10.4.0", "@testing-library/jest-dom": "6.6.3", "@testing-library/react": "16.2.0", @@ -179,7 +179,7 @@ "rollup-plugin-node-externals": "^8.0.0", "rollup-plugin-svg-import": "3.0.0", "sass-loader": "16.0.4", - "storybook": "^8.4.2", + "storybook": "^8.6.2", "style-loader": "4.0.0", "typescript": "5.7.3", "webpack": "5.97.1" diff --git a/yarn.lock b/yarn.lock index d5a786396d4..4000b1d7385 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2067,13 +2067,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/aix-ppc64@npm:0.24.2": - version: 0.24.2 - resolution: "@esbuild/aix-ppc64@npm:0.24.2" - conditions: os=aix & cpu=ppc64 - languageName: node - linkType: hard - "@esbuild/aix-ppc64@npm:0.25.0": version: 0.25.0 resolution: "@esbuild/aix-ppc64@npm:0.25.0" @@ -2081,13 +2074,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-arm64@npm:0.24.2": - version: 0.24.2 - resolution: "@esbuild/android-arm64@npm:0.24.2" - conditions: os=android & cpu=arm64 - languageName: node - linkType: hard - "@esbuild/android-arm64@npm:0.25.0": version: 0.25.0 resolution: "@esbuild/android-arm64@npm:0.25.0" @@ -2095,13 +2081,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-arm@npm:0.24.2": - version: 0.24.2 - resolution: "@esbuild/android-arm@npm:0.24.2" - conditions: os=android & cpu=arm - languageName: node - linkType: hard - "@esbuild/android-arm@npm:0.25.0": version: 0.25.0 resolution: "@esbuild/android-arm@npm:0.25.0" @@ -2109,13 +2088,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-x64@npm:0.24.2": - version: 0.24.2 - resolution: "@esbuild/android-x64@npm:0.24.2" - conditions: os=android & cpu=x64 - languageName: node - linkType: hard - "@esbuild/android-x64@npm:0.25.0": version: 0.25.0 resolution: "@esbuild/android-x64@npm:0.25.0" @@ -2123,13 +2095,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.24.2": - version: 0.24.2 - resolution: "@esbuild/darwin-arm64@npm:0.24.2" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - "@esbuild/darwin-arm64@npm:0.25.0": version: 0.25.0 resolution: "@esbuild/darwin-arm64@npm:0.25.0" @@ -2137,13 +2102,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.24.2": - version: 0.24.2 - resolution: "@esbuild/darwin-x64@npm:0.24.2" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - "@esbuild/darwin-x64@npm:0.25.0": version: 0.25.0 resolution: "@esbuild/darwin-x64@npm:0.25.0" @@ -2151,13 +2109,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.24.2": - version: 0.24.2 - resolution: "@esbuild/freebsd-arm64@npm:0.24.2" - conditions: os=freebsd & cpu=arm64 - languageName: node - linkType: hard - "@esbuild/freebsd-arm64@npm:0.25.0": version: 0.25.0 resolution: "@esbuild/freebsd-arm64@npm:0.25.0" @@ -2165,13 +2116,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.24.2": - version: 0.24.2 - resolution: "@esbuild/freebsd-x64@npm:0.24.2" - conditions: os=freebsd & cpu=x64 - languageName: node - linkType: hard - "@esbuild/freebsd-x64@npm:0.25.0": version: 0.25.0 resolution: "@esbuild/freebsd-x64@npm:0.25.0" @@ -2179,13 +2123,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.24.2": - version: 0.24.2 - resolution: "@esbuild/linux-arm64@npm:0.24.2" - conditions: os=linux & cpu=arm64 - languageName: node - linkType: hard - "@esbuild/linux-arm64@npm:0.25.0": version: 0.25.0 resolution: "@esbuild/linux-arm64@npm:0.25.0" @@ -2193,13 +2130,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.24.2": - version: 0.24.2 - resolution: "@esbuild/linux-arm@npm:0.24.2" - conditions: os=linux & cpu=arm - languageName: node - linkType: hard - "@esbuild/linux-arm@npm:0.25.0": version: 0.25.0 resolution: "@esbuild/linux-arm@npm:0.25.0" @@ -2207,13 +2137,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.24.2": - version: 0.24.2 - resolution: "@esbuild/linux-ia32@npm:0.24.2" - conditions: os=linux & cpu=ia32 - languageName: node - linkType: hard - "@esbuild/linux-ia32@npm:0.25.0": version: 0.25.0 resolution: "@esbuild/linux-ia32@npm:0.25.0" @@ -2221,13 +2144,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.24.2": - version: 0.24.2 - resolution: "@esbuild/linux-loong64@npm:0.24.2" - conditions: os=linux & cpu=loong64 - languageName: node - linkType: hard - "@esbuild/linux-loong64@npm:0.25.0": version: 0.25.0 resolution: "@esbuild/linux-loong64@npm:0.25.0" @@ -2235,13 +2151,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.24.2": - version: 0.24.2 - resolution: "@esbuild/linux-mips64el@npm:0.24.2" - conditions: os=linux & cpu=mips64el - languageName: node - linkType: hard - "@esbuild/linux-mips64el@npm:0.25.0": version: 0.25.0 resolution: "@esbuild/linux-mips64el@npm:0.25.0" @@ -2249,13 +2158,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.24.2": - version: 0.24.2 - resolution: "@esbuild/linux-ppc64@npm:0.24.2" - conditions: os=linux & cpu=ppc64 - languageName: node - linkType: hard - "@esbuild/linux-ppc64@npm:0.25.0": version: 0.25.0 resolution: "@esbuild/linux-ppc64@npm:0.25.0" @@ -2263,13 +2165,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.24.2": - version: 0.24.2 - resolution: "@esbuild/linux-riscv64@npm:0.24.2" - conditions: os=linux & cpu=riscv64 - languageName: node - linkType: hard - "@esbuild/linux-riscv64@npm:0.25.0": version: 0.25.0 resolution: "@esbuild/linux-riscv64@npm:0.25.0" @@ -2277,13 +2172,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.24.2": - version: 0.24.2 - resolution: "@esbuild/linux-s390x@npm:0.24.2" - conditions: os=linux & cpu=s390x - languageName: node - linkType: hard - "@esbuild/linux-s390x@npm:0.25.0": version: 0.25.0 resolution: "@esbuild/linux-s390x@npm:0.25.0" @@ -2291,13 +2179,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.24.2": - version: 0.24.2 - resolution: "@esbuild/linux-x64@npm:0.24.2" - conditions: os=linux & cpu=x64 - languageName: node - linkType: hard - "@esbuild/linux-x64@npm:0.25.0": version: 0.25.0 resolution: "@esbuild/linux-x64@npm:0.25.0" @@ -2305,13 +2186,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/netbsd-arm64@npm:0.24.2": - version: 0.24.2 - resolution: "@esbuild/netbsd-arm64@npm:0.24.2" - conditions: os=netbsd & cpu=arm64 - languageName: node - linkType: hard - "@esbuild/netbsd-arm64@npm:0.25.0": version: 0.25.0 resolution: "@esbuild/netbsd-arm64@npm:0.25.0" @@ -2319,13 +2193,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.24.2": - version: 0.24.2 - resolution: "@esbuild/netbsd-x64@npm:0.24.2" - conditions: os=netbsd & cpu=x64 - languageName: node - linkType: hard - "@esbuild/netbsd-x64@npm:0.25.0": version: 0.25.0 resolution: "@esbuild/netbsd-x64@npm:0.25.0" @@ -2333,13 +2200,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/openbsd-arm64@npm:0.24.2": - version: 0.24.2 - resolution: "@esbuild/openbsd-arm64@npm:0.24.2" - conditions: os=openbsd & cpu=arm64 - languageName: node - linkType: hard - "@esbuild/openbsd-arm64@npm:0.25.0": version: 0.25.0 resolution: "@esbuild/openbsd-arm64@npm:0.25.0" @@ -2347,13 +2207,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.24.2": - version: 0.24.2 - resolution: "@esbuild/openbsd-x64@npm:0.24.2" - conditions: os=openbsd & cpu=x64 - languageName: node - linkType: hard - "@esbuild/openbsd-x64@npm:0.25.0": version: 0.25.0 resolution: "@esbuild/openbsd-x64@npm:0.25.0" @@ -2361,13 +2214,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.24.2": - version: 0.24.2 - resolution: "@esbuild/sunos-x64@npm:0.24.2" - conditions: os=sunos & cpu=x64 - languageName: node - linkType: hard - "@esbuild/sunos-x64@npm:0.25.0": version: 0.25.0 resolution: "@esbuild/sunos-x64@npm:0.25.0" @@ -2375,13 +2221,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.24.2": - version: 0.24.2 - resolution: "@esbuild/win32-arm64@npm:0.24.2" - conditions: os=win32 & cpu=arm64 - languageName: node - linkType: hard - "@esbuild/win32-arm64@npm:0.25.0": version: 0.25.0 resolution: "@esbuild/win32-arm64@npm:0.25.0" @@ -2389,13 +2228,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.24.2": - version: 0.24.2 - resolution: "@esbuild/win32-ia32@npm:0.24.2" - conditions: os=win32 & cpu=ia32 - languageName: node - linkType: hard - "@esbuild/win32-ia32@npm:0.25.0": version: 0.25.0 resolution: "@esbuild/win32-ia32@npm:0.25.0" @@ -2403,13 +2235,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.24.2": - version: 0.24.2 - resolution: "@esbuild/win32-x64@npm:0.24.2" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - "@esbuild/win32-x64@npm:0.25.0": version: 0.25.0 resolution: "@esbuild/win32-x64@npm:0.25.0" @@ -3995,22 +3820,22 @@ __metadata: "@react-aria/overlays": "npm:3.25.0" "@react-aria/utils": "npm:3.27.0" "@rollup/plugin-node-resolve": "npm:16.0.0" - "@storybook/addon-a11y": "npm:^8.4.2" - "@storybook/addon-actions": "npm:^8.4.2" - "@storybook/addon-docs": "npm:^8.4.2" - "@storybook/addon-essentials": "npm:^8.4.2" - "@storybook/addon-storysource": "npm:^8.4.2" - "@storybook/addon-webpack5-compiler-swc": "npm:^1.0.5" - "@storybook/blocks": "npm:^8.4.2" - "@storybook/components": "npm:^8.4.2" - "@storybook/core-events": "npm:^8.4.2" - "@storybook/manager-api": "npm:^8.4.2" + "@storybook/addon-a11y": "npm:^8.6.2" + "@storybook/addon-actions": "npm:^8.6.2" + "@storybook/addon-docs": "npm:^8.6.2" + "@storybook/addon-essentials": "npm:^8.6.2" + "@storybook/addon-storysource": "npm:^8.6.2" + "@storybook/addon-webpack5-compiler-swc": "npm:^2.1.0" + "@storybook/blocks": "npm:^8.6.2" + "@storybook/components": "npm:^8.6.2" + "@storybook/core-events": "npm:^8.6.2" + "@storybook/manager-api": "npm:^8.6.2" "@storybook/mdx2-csf": "npm:1.1.0" "@storybook/preset-scss": "npm:1.0.3" - "@storybook/preview-api": "npm:^8.4.2" - "@storybook/react": "npm:^8.4.2" - "@storybook/react-webpack5": "npm:^8.4.2" - "@storybook/theming": "npm:^8.4.2" + "@storybook/preview-api": "npm:^8.6.2" + "@storybook/react": "npm:^8.6.2" + "@storybook/react-webpack5": "npm:^8.6.2" + "@storybook/theming": "npm:^8.6.2" "@tanstack/react-virtual": "npm:^3.5.1" "@testing-library/dom": "npm:10.4.0" "@testing-library/jest-dom": "npm:6.6.3" @@ -4102,7 +3927,7 @@ __metadata: slate: "npm:0.47.9" slate-plain-serializer: "npm:0.7.13" slate-react: "npm:0.22.10" - storybook: "npm:^8.4.2" + storybook: "npm:^8.6.2" style-loader: "npm:4.0.0" tinycolor2: "npm:1.6.0" tslib: "npm:2.8.1" @@ -7567,21 +7392,22 @@ __metadata: languageName: node linkType: hard -"@storybook/addon-a11y@npm:^8.4.2": - version: 8.4.4 - resolution: "@storybook/addon-a11y@npm:8.4.4" +"@storybook/addon-a11y@npm:^8.6.2": + version: 8.6.2 + resolution: "@storybook/addon-a11y@npm:8.6.2" dependencies: - "@storybook/addon-highlight": "npm:8.4.4" + "@storybook/addon-highlight": "npm:8.6.2" + "@storybook/test": "npm:8.6.2" axe-core: "npm:^4.2.0" peerDependencies: - storybook: ^8.4.4 - checksum: 10/1621f3f94adac5cd860c8e80d9efa005300ce1ef52afd6f5d61e44fcd7f8967d94499cb640b86c1f731a67d9a4d1e1db77d403d431a67c4689571f826bbaf151 + storybook: ^8.6.2 + checksum: 10/c7a161734c4d587bbc2b926fcf01103203b4f50112f5ea19bdbd4dad4c1c62bb358613e3c6e608335f064ef7b7627f5a1ffeb1f524ec008bb19e86e50b1dfb27 languageName: node linkType: hard -"@storybook/addon-actions@npm:8.4.4, @storybook/addon-actions@npm:^8.4.2": - version: 8.4.4 - resolution: "@storybook/addon-actions@npm:8.4.4" +"@storybook/addon-actions@npm:8.6.2, @storybook/addon-actions@npm:^8.6.2": + version: 8.6.2 + resolution: "@storybook/addon-actions@npm:8.6.2" dependencies: "@storybook/global": "npm:^5.0.0" "@types/uuid": "npm:^9.0.1" @@ -7589,178 +7415,176 @@ __metadata: polished: "npm:^4.2.2" uuid: "npm:^9.0.0" peerDependencies: - storybook: ^8.4.4 - checksum: 10/e8af0e8af39fecff49948b7baf2957e54b53b505f1ae4dec29e9284db75405868f7fed9c692b045bbc6a606cb8c03c26563a717c6521d52ca04eebef4e6a4897 + storybook: ^8.6.2 + checksum: 10/16127ee35f08fe98df98a688a8724c803274cbe1a81d3ae46727ad6b34bdae913dd905a3a124954805e4f2650e56e18f80de2f4cf7cb0fc0480c185cf342a8e5 languageName: node linkType: hard -"@storybook/addon-backgrounds@npm:8.4.4": - version: 8.4.4 - resolution: "@storybook/addon-backgrounds@npm:8.4.4" +"@storybook/addon-backgrounds@npm:8.6.2": + version: 8.6.2 + resolution: "@storybook/addon-backgrounds@npm:8.6.2" dependencies: "@storybook/global": "npm:^5.0.0" memoizerific: "npm:^1.11.3" ts-dedent: "npm:^2.0.0" peerDependencies: - storybook: ^8.4.4 - checksum: 10/1b45008c1b7da28e331f90f825fbff497af793665e79bdb4b36767bf1943e5df55f8d1d4fa27a4c4329991aaecbb911a447c119dc2fd094962a22276889e944f + storybook: ^8.6.2 + checksum: 10/b303afb745fb34cb77565f595fdd5f1749927f3be6bc58702f3ed6b8931d89abc099b46940436a1f0509b4a6580f7c58100bf091ba6e5fe7f040704ac723118f languageName: node linkType: hard -"@storybook/addon-controls@npm:8.4.4": - version: 8.4.4 - resolution: "@storybook/addon-controls@npm:8.4.4" +"@storybook/addon-controls@npm:8.6.2": + version: 8.6.2 + resolution: "@storybook/addon-controls@npm:8.6.2" dependencies: "@storybook/global": "npm:^5.0.0" dequal: "npm:^2.0.2" ts-dedent: "npm:^2.0.0" peerDependencies: - storybook: ^8.4.4 - checksum: 10/4008300f0cb02c140685a435e4c7a8af6a981c3f21b101add66a503b848f9785ddfcc623389718f3aa14a95308b9715eac16787feb9377da2aad88711e0f365b + storybook: ^8.6.2 + checksum: 10/4d54617c514b6e88d5708e2d3b067a01f3863e83dcf327bdec0b55df36bf8e6269ab1d9e5c5cb0edb27e9554c2d212ce087356b9d68779744854207febd26808 languageName: node linkType: hard -"@storybook/addon-docs@npm:8.4.4, @storybook/addon-docs@npm:^8.4.2": - version: 8.4.4 - resolution: "@storybook/addon-docs@npm:8.4.4" +"@storybook/addon-docs@npm:8.6.2, @storybook/addon-docs@npm:^8.6.2": + version: 8.6.2 + resolution: "@storybook/addon-docs@npm:8.6.2" dependencies: "@mdx-js/react": "npm:^3.0.0" - "@storybook/blocks": "npm:8.4.4" - "@storybook/csf-plugin": "npm:8.4.4" - "@storybook/react-dom-shim": "npm:8.4.4" - react: "npm:^16.8.0 || ^17.0.0 || ^18.0.0" - react-dom: "npm:^16.8.0 || ^17.0.0 || ^18.0.0" + "@storybook/blocks": "npm:8.6.2" + "@storybook/csf-plugin": "npm:8.6.2" + "@storybook/react-dom-shim": "npm:8.6.2" + react: "npm:^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + react-dom: "npm:^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" ts-dedent: "npm:^2.0.0" peerDependencies: - storybook: ^8.4.4 - checksum: 10/991c766ea4366bae9fb0b65d7e86a8325231e3e1f5ee6924d2bb9cdbba9a66d3b20780787987d6dd9c4f9977708f0321791820004b33fd5f5255294ce9786f8c + storybook: ^8.6.2 + checksum: 10/d13752c4f31f01426724dbfdc70313948475dbbf6c43ed1cceca8d37d86424f79369c1b06c5e4daebe581e8702b02c9522ea77aff1864a7228662f4c8517fedf languageName: node linkType: hard -"@storybook/addon-essentials@npm:^8.4.2": - version: 8.4.4 - resolution: "@storybook/addon-essentials@npm:8.4.4" +"@storybook/addon-essentials@npm:^8.6.2": + version: 8.6.2 + resolution: "@storybook/addon-essentials@npm:8.6.2" dependencies: - "@storybook/addon-actions": "npm:8.4.4" - "@storybook/addon-backgrounds": "npm:8.4.4" - "@storybook/addon-controls": "npm:8.4.4" - "@storybook/addon-docs": "npm:8.4.4" - "@storybook/addon-highlight": "npm:8.4.4" - "@storybook/addon-measure": "npm:8.4.4" - "@storybook/addon-outline": "npm:8.4.4" - "@storybook/addon-toolbars": "npm:8.4.4" - "@storybook/addon-viewport": "npm:8.4.4" + "@storybook/addon-actions": "npm:8.6.2" + "@storybook/addon-backgrounds": "npm:8.6.2" + "@storybook/addon-controls": "npm:8.6.2" + "@storybook/addon-docs": "npm:8.6.2" + "@storybook/addon-highlight": "npm:8.6.2" + "@storybook/addon-measure": "npm:8.6.2" + "@storybook/addon-outline": "npm:8.6.2" + "@storybook/addon-toolbars": "npm:8.6.2" + "@storybook/addon-viewport": "npm:8.6.2" ts-dedent: "npm:^2.0.0" peerDependencies: - storybook: ^8.4.4 - checksum: 10/c8dfe7be1eac6280e4ae801a33a02f99f47e0430920d22505b80fe8684eaabaa9c977a34f90c3265185f11ded930c5b29cdc11fbaa715eec57cab95ad4343750 + storybook: ^8.6.2 + checksum: 10/2e8a9cb6fed038122230929f72dfc94116c7884d838f633b81f1b485bf169129cf8e91bc31cc9949cbfc39d31ada1d5ae4a8bc61c533b47c9b63ea7d5045c468 languageName: node linkType: hard -"@storybook/addon-highlight@npm:8.4.4": - version: 8.4.4 - resolution: "@storybook/addon-highlight@npm:8.4.4" +"@storybook/addon-highlight@npm:8.6.2": + version: 8.6.2 + resolution: "@storybook/addon-highlight@npm:8.6.2" dependencies: "@storybook/global": "npm:^5.0.0" peerDependencies: - storybook: ^8.4.4 - checksum: 10/9944ce08c8f36dc4bbdf24536b5ffde328b4032e7165e15f7bd7af5ab5adb0b9a5be49f43ab96068ea00d8acd1450f10436daa70b32ae3492364fe86a31dffb7 + storybook: ^8.6.2 + checksum: 10/0bd8298612390daa6d455876c3485e8e60751f51d6a2e67c79d2bb37b27a5059b1fab3ed4117371f6b375a6294a5e038abe6bd65db9259723578e4c55b0abcd2 languageName: node linkType: hard -"@storybook/addon-measure@npm:8.4.4": - version: 8.4.4 - resolution: "@storybook/addon-measure@npm:8.4.4" +"@storybook/addon-measure@npm:8.6.2": + version: 8.6.2 + resolution: "@storybook/addon-measure@npm:8.6.2" dependencies: "@storybook/global": "npm:^5.0.0" tiny-invariant: "npm:^1.3.1" peerDependencies: - storybook: ^8.4.4 - checksum: 10/cebd85f454026cdf46eac29a80725bb7a353b9e08c7553e2b948488413092b8d85ab1667ed1381dfcede92fd289707b1092d217df7ecc7cd5ea6d8da356b9e48 + storybook: ^8.6.2 + checksum: 10/c81946d8459aa953f633503872f30ae13336cfb9c7e539c49dccbeae6f33e57e774ff35a197d3aea46d28a33c0a45a497a14eacd403817fa87572d377d5ad4d9 languageName: node linkType: hard -"@storybook/addon-outline@npm:8.4.4": - version: 8.4.4 - resolution: "@storybook/addon-outline@npm:8.4.4" +"@storybook/addon-outline@npm:8.6.2": + version: 8.6.2 + resolution: "@storybook/addon-outline@npm:8.6.2" dependencies: "@storybook/global": "npm:^5.0.0" ts-dedent: "npm:^2.0.0" peerDependencies: - storybook: ^8.4.4 - checksum: 10/1405f812b780b2179f611be6404eeb6ce3bc7760372753c6bc176c298e396b1d90b997e1f31a9e8f828fd4f897489ce17158498c82e4a2c139c1576e250d8102 + storybook: ^8.6.2 + checksum: 10/357a72cb76cd8d1d2e7ff5ab1fc152f17b1f8c4ab087d8b94e1f157554a641aa47d96ede8087d5045eda8b99dfc2d94c29c2bdc1dce8f8d7d0c0a0b660aae966 languageName: node linkType: hard -"@storybook/addon-storysource@npm:^8.4.2": - version: 8.4.4 - resolution: "@storybook/addon-storysource@npm:8.4.4" +"@storybook/addon-storysource@npm:^8.6.2": + version: 8.6.2 + resolution: "@storybook/addon-storysource@npm:8.6.2" dependencies: - "@storybook/source-loader": "npm:8.4.4" + "@storybook/source-loader": "npm:8.6.2" estraverse: "npm:^5.2.0" tiny-invariant: "npm:^1.3.1" peerDependencies: - storybook: ^8.4.4 - checksum: 10/639177cbd8c8fdc884bec1b8ef2f9fc83778bd48dcccbaef1d4409548f27c7cbe242571e78f8d4092c988fc7a99fd54f104923842d5864aeb74d59e5a6ff6e03 + storybook: ^8.6.2 + checksum: 10/4c06dab42fd2ff88df632960bfc70144e7ab423bec373be7f1b318519a383f33515a296440e77c085345e220af5de77dd9c500a49fcc66e23db9612164d94d9f languageName: node linkType: hard -"@storybook/addon-toolbars@npm:8.4.4": - version: 8.4.4 - resolution: "@storybook/addon-toolbars@npm:8.4.4" +"@storybook/addon-toolbars@npm:8.6.2": + version: 8.6.2 + resolution: "@storybook/addon-toolbars@npm:8.6.2" peerDependencies: - storybook: ^8.4.4 - checksum: 10/efd3cbf3e63f103aacd2471a319ea46ca666f1b6be65c9fe7518322eaf149ea18aefc1146ec2abca2231edb7c2b55f430306d77e041ff10493e79b6b353b9b04 + storybook: ^8.6.2 + checksum: 10/7c7863a1e9698128557cf38bdce81aab127958c4892aeaa2f9035042d0fd36edcabb296575cf02a69d8f19abe4b1b114223a6312f25c84dff827314f004303ee languageName: node linkType: hard -"@storybook/addon-viewport@npm:8.4.4": - version: 8.4.4 - resolution: "@storybook/addon-viewport@npm:8.4.4" +"@storybook/addon-viewport@npm:8.6.2": + version: 8.6.2 + resolution: "@storybook/addon-viewport@npm:8.6.2" dependencies: memoizerific: "npm:^1.11.3" peerDependencies: - storybook: ^8.4.4 - checksum: 10/94c193f3cc4d759a696ba8f15d0211ea74af8640f79428040eb6914e153308ac54ba0b82e6dff0769ae05c02d229a74809c5999a7631aef5987e00361af4dab2 + storybook: ^8.6.2 + checksum: 10/60e67fb0b2f21c889f416bbb7d1729bf3310f56efa23d016d9984f6a9fce39cccccc02422b6ece736a558fef0053c5ac39d46df1735aa2e560e580a3fae3337f languageName: node linkType: hard -"@storybook/addon-webpack5-compiler-swc@npm:^1.0.5": - version: 1.0.5 - resolution: "@storybook/addon-webpack5-compiler-swc@npm:1.0.5" +"@storybook/addon-webpack5-compiler-swc@npm:^2.1.0": + version: 2.1.0 + resolution: "@storybook/addon-webpack5-compiler-swc@npm:2.1.0" dependencies: - "@swc/core": "npm:^1.7.3" - swc-loader: "npm:^0.2.3" - checksum: 10/9856a700a5d9a36e1c35b404ec90331ed19617f73f63256752959ee4e2904142c5b0d883b436b5b70e1ec2e04038b461d5cf1d616243fa8cfedd0b5d69b73caf + "@swc/core": "npm:^1.10.8" + swc-loader: "npm:^0.2.6" + checksum: 10/d91c17ebebdf67ee318f906d0601f3a85ca1500e212fa5a525efff815bd421030bd45167d5e98081dba9ddf224ea37c7ef79003228c3b3547219c0894f5a38de languageName: node linkType: hard -"@storybook/blocks@npm:8.4.4, @storybook/blocks@npm:^8.4.2": - version: 8.4.4 - resolution: "@storybook/blocks@npm:8.4.4" +"@storybook/blocks@npm:8.6.2, @storybook/blocks@npm:^8.6.2": + version: 8.6.2 + resolution: "@storybook/blocks@npm:8.6.2" dependencies: - "@storybook/csf": "npm:^0.1.11" "@storybook/icons": "npm:^1.2.12" ts-dedent: "npm:^2.0.0" peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.4.4 + 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 + storybook: ^8.6.2 peerDependenciesMeta: react: optional: true react-dom: optional: true - checksum: 10/1b4686d9f819b8718edadefa0a7fb911a5a7ac80c2d2abbb281c153a84546c2332eb9be062eb31e7a49fa5c9bbc76878dd4afd4629895674a821e37ec00cdb40 + checksum: 10/8137b042e99572b7bdd6df3484c75d3b1cf78b15bb7d3a7ad09738e94ec21481d295acfe2b59fa547be9ee5a0b075bb485f88a1972948e4703aef6b174b60ead languageName: node linkType: hard -"@storybook/builder-webpack5@npm:8.4.4": - version: 8.4.4 - resolution: "@storybook/builder-webpack5@npm:8.4.4" +"@storybook/builder-webpack5@npm:8.6.2": + version: 8.6.2 + resolution: "@storybook/builder-webpack5@npm:8.6.2" dependencies: - "@storybook/core-webpack": "npm:8.4.4" - "@types/node": "npm:^22.0.0" + "@storybook/core-webpack": "npm:8.6.2" "@types/semver": "npm:^7.3.4" browser-assert: "npm:^1.2.1" case-sensitive-paths-webpack-plugin: "npm:^2.4.0" @@ -7785,52 +7609,51 @@ __metadata: webpack-hot-middleware: "npm:^2.25.1" webpack-virtual-modules: "npm:^0.6.0" peerDependencies: - storybook: ^8.4.4 + storybook: ^8.6.2 peerDependenciesMeta: typescript: optional: true - checksum: 10/9894450cf1985b32947a2b27a091d4d5ac23c03f179a4653b7e98fd136b80ff6f4fce663c471eeda7db118d4c8b4bd1256dad5aea2d684bef00b7319aa11fe0c + checksum: 10/909d74c281a41a43d17ff9f313231283ac21c9c97ef47d8f8f96753f0b639dbdaeb2d12d46a7cd4fd8001bffcc2d707e83d47ab62fe3757ab30093159a1eded1 languageName: node linkType: hard -"@storybook/components@npm:8.4.4, @storybook/components@npm:^8.4.2": - version: 8.4.4 - resolution: "@storybook/components@npm:8.4.4" +"@storybook/components@npm:8.6.2, @storybook/components@npm:^8.6.2": + version: 8.6.2 + resolution: "@storybook/components@npm:8.6.2" peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - checksum: 10/ca60bd5911669112af8d59e1b424e564a681e37c3f6ac59bceea69a08adddb478b965a7207f266591ec0daca74c8f674fdf3e21fdba5c794b80f13331667913a + checksum: 10/d85bb39aedd03a05043194debf3d35965dbe84d386029f63f0aa20ac943f4cc635558f6b08cc8ec013a2cc7f2407ef3c8735a76d4805e41569aaabe8efe59fd4 languageName: node linkType: hard -"@storybook/core-events@npm:^8.4.2": - version: 8.4.4 - resolution: "@storybook/core-events@npm:8.4.4" +"@storybook/core-events@npm:^8.6.2": + version: 8.6.2 + resolution: "@storybook/core-events@npm:8.6.2" peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - checksum: 10/4aca6f98968350a78cfb7b5e709705026e65dfb792d00542ce8c236fef9d7225680dc4f3259b3203bcf8abf3674754fe908e9dfef975d3b4d49baa5a4a5664cf + checksum: 10/d2f574be4bc4fd5be82be376954b795dca291dd834b62ef4545eb912bf0c879bd6b4e544613cc399bbe5161c05788d32ad9119811d05921f690417fd3f1448f4 languageName: node linkType: hard -"@storybook/core-webpack@npm:8.4.4": - version: 8.4.4 - resolution: "@storybook/core-webpack@npm:8.4.4" +"@storybook/core-webpack@npm:8.6.2": + version: 8.6.2 + resolution: "@storybook/core-webpack@npm:8.6.2" dependencies: - "@types/node": "npm:^22.0.0" ts-dedent: "npm:^2.0.0" peerDependencies: - storybook: ^8.4.4 - checksum: 10/e9f7677e45eaa7eee5d97b745fc9e64a83f13895e42fdc7eb71285a2e2295140b075e74b8b37d4eda2eb488327b4ec9b83201562b27204f93dc8d246929c04a5 + storybook: ^8.6.2 + checksum: 10/666edcb895b034b74fa86bb6d6dc16d26078ffc3524d20917ca27c40b4f722706622f83c4f97a323f8fc441d655a5ab124c9fbea12a2fa2e25000cf1231a5e78 languageName: node linkType: hard -"@storybook/core@npm:8.4.4": - version: 8.4.4 - resolution: "@storybook/core@npm:8.4.4" +"@storybook/core@npm:8.6.2": + version: 8.6.2 + resolution: "@storybook/core@npm:8.6.2" dependencies: - "@storybook/csf": "npm:^0.1.11" + "@storybook/theming": "npm:8.6.2" better-opn: "npm:^3.0.2" browser-assert: "npm:^1.2.1" - esbuild: "npm:^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0" + esbuild: "npm:^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0" esbuild-register: "npm:^3.5.0" jsdoc-type-pratt-parser: "npm:^4.0.0" process: "npm:^0.11.10" @@ -7843,27 +7666,18 @@ __metadata: peerDependenciesMeta: prettier: optional: true - checksum: 10/94458d2768e0fe28e75359a13fa15c80080b62f102a1283a6b4eb8a793ecd8d32d3544fc5c3eddfedfb69830bb88f264f72d034daea2a85e1fd7a102f3d57327 + checksum: 10/57d8af6d822c4cbeab201aec813830d632165c2411bf8708481ad0daa2fa942ce6a912e0ef764e6acb9bd2053baf0614b7726e5827b071f3f845d459ac1f3d3a languageName: node linkType: hard -"@storybook/csf-plugin@npm:8.4.4": - version: 8.4.4 - resolution: "@storybook/csf-plugin@npm:8.4.4" +"@storybook/csf-plugin@npm:8.6.2": + version: 8.6.2 + resolution: "@storybook/csf-plugin@npm:8.6.2" dependencies: unplugin: "npm:^1.3.1" peerDependencies: - storybook: ^8.4.4 - checksum: 10/109c54af8aabaa64c2eeb8b0b6f1379b3588b8c1c3d4da828e0a0c8f6479960d64adc4635e911484915ac651061aa15e218cde1dd7be27562ce8e6ba79be7cae - languageName: node - linkType: hard - -"@storybook/csf@npm:^0.1.11": - version: 0.1.11 - resolution: "@storybook/csf@npm:0.1.11" - dependencies: - type-fest: "npm:^2.19.0" - checksum: 10/f6eeefe3b92ab206676587da9e22a775da026c055999681580d2ca23c98185736f965adc79039a0ae97ea625f0fbc7915cd4559e5db24229a4805784d0b78584 + storybook: ^8.6.2 + checksum: 10/6d71101640975cbe08d5dc9bae30938337b0e999f5724c4802713cf3d8c34671b646158ffde659e9cbcd005153844223cd4f9a4af2aa0d6f5a15b3db8d31f85d languageName: node linkType: hard @@ -7884,12 +7698,24 @@ __metadata: languageName: node linkType: hard -"@storybook/manager-api@npm:8.4.4, @storybook/manager-api@npm:^8.4.2": - version: 8.4.4 - resolution: "@storybook/manager-api@npm:8.4.4" +"@storybook/instrumenter@npm:8.6.2": + version: 8.6.2 + resolution: "@storybook/instrumenter@npm:8.6.2" + dependencies: + "@storybook/global": "npm:^5.0.0" + "@vitest/utils": "npm:^2.1.1" + peerDependencies: + storybook: ^8.6.2 + checksum: 10/40d028d6f8b5ab51eb112bb5b903f64438eaf818c501a78ef77a5e946676e13f15ad8f5188a85e40bf91f987c6ab15c6a33b4e8bef8b8f8e05011013dcda092a + languageName: node + linkType: hard + +"@storybook/manager-api@npm:8.6.2, @storybook/manager-api@npm:^8.6.2": + version: 8.6.2 + resolution: "@storybook/manager-api@npm:8.6.2" peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - checksum: 10/9eac4488f55e1860940e0e850a48f4278a7b6e6325c7381007447626715a8f8e52d6f876f6caaa2597787fb19c40a33f96d34b56558190f7be4772cac7805ebc + checksum: 10/d344c88c6cad0bcc54767a8ef1d269a9df868c76ae22927c31936e46aaeb47075783d84f8815b4d0c7812ed50b2d4616417429479e3a9ea36043c557eb141590 languageName: node linkType: hard @@ -7900,14 +7726,13 @@ __metadata: languageName: node linkType: hard -"@storybook/preset-react-webpack@npm:8.4.4": - version: 8.4.4 - resolution: "@storybook/preset-react-webpack@npm:8.4.4" +"@storybook/preset-react-webpack@npm:8.6.2": + version: 8.6.2 + resolution: "@storybook/preset-react-webpack@npm:8.6.2" dependencies: - "@storybook/core-webpack": "npm:8.4.4" - "@storybook/react": "npm:8.4.4" + "@storybook/core-webpack": "npm:8.6.2" + "@storybook/react": "npm:8.6.2" "@storybook/react-docgen-typescript-plugin": "npm:1.0.6--canary.9.0c3f3b7.0" - "@types/node": "npm:^22.0.0" "@types/semver": "npm:^7.3.4" find-up: "npm:^5.0.0" magic-string: "npm:^0.30.5" @@ -7919,11 +7744,11 @@ __metadata: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.4.4 + storybook: ^8.6.2 peerDependenciesMeta: typescript: optional: true - checksum: 10/acff2bec1907610cca8e17d4e782d1ebe1747861a77426ed2d20f403a6f022c006ac56d9eb085c1ae6110f7630ccc8a8a2c154d9a9f90fb54e082f45f0002d98 + checksum: 10/d903a14e6e65bdfb56568962f456a103ec3f64d339d4ed3d091befe66dddcff2e31d7a2acee1bbf52cf9a33d09564af2dc36483961f73c812eacb34d71f7a951 languageName: node linkType: hard @@ -7938,12 +7763,12 @@ __metadata: languageName: node linkType: hard -"@storybook/preview-api@npm:8.4.4, @storybook/preview-api@npm:^8.4.2": - version: 8.4.4 - resolution: "@storybook/preview-api@npm:8.4.4" +"@storybook/preview-api@npm:8.6.2, @storybook/preview-api@npm:^8.6.2": + version: 8.6.2 + resolution: "@storybook/preview-api@npm:8.6.2" peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - checksum: 10/ad95ce132d598e8b13da70a319ffdfaf41e5f8629cfb4552a577f3624a92d4a168e1de5220fe7c735babbd5945dd2182448a910b246a458cddde2afe7378461e + checksum: 10/5d286ed8c266a8aa63361bbb0245163e6fe3fd85a5e60555a79a579535faf36c30a9ad07bff30b0d9d536d35ec8f5ee78484629b174ecc965cbe0726e749d6de languageName: node linkType: hard @@ -7965,82 +7790,97 @@ __metadata: languageName: node linkType: hard -"@storybook/react-dom-shim@npm:8.4.4": - version: 8.4.4 - resolution: "@storybook/react-dom-shim@npm:8.4.4" +"@storybook/react-dom-shim@npm:8.6.2": + version: 8.6.2 + resolution: "@storybook/react-dom-shim@npm:8.6.2" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.4.4 - checksum: 10/151b4669746da46d7c24531d0f33dc1e99301d45c4653de4dcf02c557adc2d8eea305963a681ff0eb47c8e175065928509924c69f3007e5a5cafe3a048a9c344 + storybook: ^8.6.2 + checksum: 10/f32718a49ccbd7c01233c83d738479eb60c41a3f8855066b85593fb7a07129b1b18a0c93fe64b01dce9c9105293b40c1e131410169d5aaaa2f8b7a7c00f836ee languageName: node linkType: hard -"@storybook/react-webpack5@npm:^8.4.2": - version: 8.4.4 - resolution: "@storybook/react-webpack5@npm:8.4.4" +"@storybook/react-webpack5@npm:^8.6.2": + version: 8.6.2 + resolution: "@storybook/react-webpack5@npm:8.6.2" dependencies: - "@storybook/builder-webpack5": "npm:8.4.4" - "@storybook/preset-react-webpack": "npm:8.4.4" - "@storybook/react": "npm:8.4.4" - "@types/node": "npm:^22.0.0" + "@storybook/builder-webpack5": "npm:8.6.2" + "@storybook/preset-react-webpack": "npm:8.6.2" + "@storybook/react": "npm:8.6.2" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.4.4 + storybook: ^8.6.2 typescript: ">= 4.2.x" peerDependenciesMeta: typescript: optional: true - checksum: 10/baa0c17c87d5c21c55cd485a7aea96c3314241c44064b1812be0b5d6bba7ae39521f3d030a0a0f1a155f4de4b5f444a3d61d47dcffa801e19410bac00cd9dfb3 + checksum: 10/1d8c745d21da7853328a1870797808982864be68783c2a56248ab642a81eaad667f5522cc9f0eba74a9b96658d6fcd9b6a5b9296e235ff8e1566edbc48e5d146 languageName: node linkType: hard -"@storybook/react@npm:8.4.4, @storybook/react@npm:^8.4.2": - version: 8.4.4 - resolution: "@storybook/react@npm:8.4.4" +"@storybook/react@npm:8.6.2, @storybook/react@npm:^8.6.2": + version: 8.6.2 + resolution: "@storybook/react@npm:8.6.2" dependencies: - "@storybook/components": "npm:8.4.4" + "@storybook/components": "npm:8.6.2" "@storybook/global": "npm:^5.0.0" - "@storybook/manager-api": "npm:8.4.4" - "@storybook/preview-api": "npm:8.4.4" - "@storybook/react-dom-shim": "npm:8.4.4" - "@storybook/theming": "npm:8.4.4" + "@storybook/manager-api": "npm:8.6.2" + "@storybook/preview-api": "npm:8.6.2" + "@storybook/react-dom-shim": "npm:8.6.2" + "@storybook/theming": "npm:8.6.2" peerDependencies: - "@storybook/test": 8.4.4 + "@storybook/test": 8.6.2 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.4.4 + storybook: ^8.6.2 typescript: ">= 4.2.x" peerDependenciesMeta: "@storybook/test": optional: true typescript: optional: true - checksum: 10/06be762e00ebf06398ed233dc6347ab058f4a26c99f373a3d5f8f089fa2b68b4d328e5304e30d3e2aee049d0d947c1627637f0ceb38edc715d4a58bb9256b758 + checksum: 10/b8a91e6a8aeb9e32e05e12db4df1dafd59b54d82954e481ea9224316bd1e432093259b474f773911e90aeebe441cbb17e8dc0a6940b79b5899eff1f2b4aae334 languageName: node linkType: hard -"@storybook/source-loader@npm:8.4.4": - version: 8.4.4 - resolution: "@storybook/source-loader@npm:8.4.4" +"@storybook/source-loader@npm:8.6.2": + version: 8.6.2 + resolution: "@storybook/source-loader@npm:8.6.2" dependencies: - "@storybook/csf": "npm:^0.1.11" es-toolkit: "npm:^1.22.0" estraverse: "npm:^5.2.0" prettier: "npm:^3.1.1" peerDependencies: - storybook: ^8.4.4 - checksum: 10/25cf2dcc5bd628ca240ab8527ade65b206036f5f1b6da9481b19c1854832b221f0285e4483925b9b00c9fcb0939bb7d1b866230b2ae1ad8726b97a3387022011 + storybook: ^8.6.2 + checksum: 10/8cf43eb6ce2df997272c71f3d9f8e85f3fecb6ca1d176c87fd349ea17e1d821dadb43496af5d10a2c6163fd6d920940a253a075a7774fc9bb5f724c132cfcaf0 languageName: node linkType: hard -"@storybook/theming@npm:8.4.4, @storybook/theming@npm:^8.4.2": - version: 8.4.4 - resolution: "@storybook/theming@npm:8.4.4" +"@storybook/test@npm:8.6.2": + version: 8.6.2 + resolution: "@storybook/test@npm:8.6.2" + dependencies: + "@storybook/global": "npm:^5.0.0" + "@storybook/instrumenter": "npm:8.6.2" + "@testing-library/dom": "npm:10.4.0" + "@testing-library/jest-dom": "npm:6.5.0" + "@testing-library/user-event": "npm:14.5.2" + "@vitest/expect": "npm:2.0.5" + "@vitest/spy": "npm:2.0.5" + peerDependencies: + storybook: ^8.6.2 + checksum: 10/4cb89e254143374716fcd72c3a9a4c603a9f664162c5755ead7257ce130bc33d3c48c9cbaa35274023f4b961d66c4e84733e35ca663019d770fcfa6ef5b21b84 + languageName: node + linkType: hard + +"@storybook/theming@npm:8.6.2, @storybook/theming@npm:^8.6.2": + version: 8.6.2 + resolution: "@storybook/theming@npm:8.6.2" peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - checksum: 10/8a39c0c0c519a98491de3c8f29d3c9ab2d2bb5ee616933dd07aaed276cd46635e1b3019902b40dc073e7ee0679b5760234c920e455817a13e8d1d753811553ee + checksum: 10/81ff1f740edaa000d6abaab5a47b038b46cfc54ddad308335b8d26d7a6f1ee100f617f52d51cd6596f424a534dbda0d9801e3928b4b6f758d9a3e8da6f9d40f5 languageName: node linkType: hard @@ -8790,6 +8630,13 @@ __metadata: languageName: node linkType: hard +"@swc/core-darwin-arm64@npm:1.11.4": + version: 1.11.4 + resolution: "@swc/core-darwin-arm64@npm:1.11.4" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@swc/core-darwin-x64@npm:1.10.12": version: 1.10.12 resolution: "@swc/core-darwin-x64@npm:1.10.12" @@ -8797,6 +8644,13 @@ __metadata: languageName: node linkType: hard +"@swc/core-darwin-x64@npm:1.11.4": + version: 1.11.4 + resolution: "@swc/core-darwin-x64@npm:1.11.4" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@swc/core-linux-arm-gnueabihf@npm:1.10.12": version: 1.10.12 resolution: "@swc/core-linux-arm-gnueabihf@npm:1.10.12" @@ -8804,6 +8658,13 @@ __metadata: languageName: node linkType: hard +"@swc/core-linux-arm-gnueabihf@npm:1.11.4": + version: 1.11.4 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.11.4" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + "@swc/core-linux-arm64-gnu@npm:1.10.12": version: 1.10.12 resolution: "@swc/core-linux-arm64-gnu@npm:1.10.12" @@ -8811,6 +8672,13 @@ __metadata: languageName: node linkType: hard +"@swc/core-linux-arm64-gnu@npm:1.11.4": + version: 1.11.4 + resolution: "@swc/core-linux-arm64-gnu@npm:1.11.4" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + "@swc/core-linux-arm64-musl@npm:1.10.12": version: 1.10.12 resolution: "@swc/core-linux-arm64-musl@npm:1.10.12" @@ -8818,6 +8686,13 @@ __metadata: languageName: node linkType: hard +"@swc/core-linux-arm64-musl@npm:1.11.4": + version: 1.11.4 + resolution: "@swc/core-linux-arm64-musl@npm:1.11.4" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + "@swc/core-linux-x64-gnu@npm:1.10.12": version: 1.10.12 resolution: "@swc/core-linux-x64-gnu@npm:1.10.12" @@ -8825,6 +8700,13 @@ __metadata: languageName: node linkType: hard +"@swc/core-linux-x64-gnu@npm:1.11.4": + version: 1.11.4 + resolution: "@swc/core-linux-x64-gnu@npm:1.11.4" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + "@swc/core-linux-x64-musl@npm:1.10.12": version: 1.10.12 resolution: "@swc/core-linux-x64-musl@npm:1.10.12" @@ -8832,6 +8714,13 @@ __metadata: languageName: node linkType: hard +"@swc/core-linux-x64-musl@npm:1.11.4": + version: 1.11.4 + resolution: "@swc/core-linux-x64-musl@npm:1.11.4" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + "@swc/core-win32-arm64-msvc@npm:1.10.12": version: 1.10.12 resolution: "@swc/core-win32-arm64-msvc@npm:1.10.12" @@ -8839,6 +8728,13 @@ __metadata: languageName: node linkType: hard +"@swc/core-win32-arm64-msvc@npm:1.11.4": + version: 1.11.4 + resolution: "@swc/core-win32-arm64-msvc@npm:1.11.4" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + "@swc/core-win32-ia32-msvc@npm:1.10.12": version: 1.10.12 resolution: "@swc/core-win32-ia32-msvc@npm:1.10.12" @@ -8846,6 +8742,13 @@ __metadata: languageName: node linkType: hard +"@swc/core-win32-ia32-msvc@npm:1.11.4": + version: 1.11.4 + resolution: "@swc/core-win32-ia32-msvc@npm:1.11.4" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + "@swc/core-win32-x64-msvc@npm:1.10.12": version: 1.10.12 resolution: "@swc/core-win32-x64-msvc@npm:1.10.12" @@ -8853,7 +8756,14 @@ __metadata: languageName: node linkType: hard -"@swc/core@npm:1.10.12, @swc/core@npm:^1.7.3": +"@swc/core-win32-x64-msvc@npm:1.11.4": + version: 1.11.4 + resolution: "@swc/core-win32-x64-msvc@npm:1.11.4" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@swc/core@npm:1.10.12": version: 1.10.12 resolution: "@swc/core@npm:1.10.12" dependencies: @@ -8899,6 +8809,52 @@ __metadata: languageName: node linkType: hard +"@swc/core@npm:^1.10.8": + version: 1.11.4 + resolution: "@swc/core@npm:1.11.4" + dependencies: + "@swc/core-darwin-arm64": "npm:1.11.4" + "@swc/core-darwin-x64": "npm:1.11.4" + "@swc/core-linux-arm-gnueabihf": "npm:1.11.4" + "@swc/core-linux-arm64-gnu": "npm:1.11.4" + "@swc/core-linux-arm64-musl": "npm:1.11.4" + "@swc/core-linux-x64-gnu": "npm:1.11.4" + "@swc/core-linux-x64-musl": "npm:1.11.4" + "@swc/core-win32-arm64-msvc": "npm:1.11.4" + "@swc/core-win32-ia32-msvc": "npm:1.11.4" + "@swc/core-win32-x64-msvc": "npm:1.11.4" + "@swc/counter": "npm:^0.1.3" + "@swc/types": "npm:^0.1.19" + peerDependencies: + "@swc/helpers": "*" + dependenciesMeta: + "@swc/core-darwin-arm64": + optional: true + "@swc/core-darwin-x64": + optional: true + "@swc/core-linux-arm-gnueabihf": + optional: true + "@swc/core-linux-arm64-gnu": + optional: true + "@swc/core-linux-arm64-musl": + optional: true + "@swc/core-linux-x64-gnu": + optional: true + "@swc/core-linux-x64-musl": + optional: true + "@swc/core-win32-arm64-msvc": + optional: true + "@swc/core-win32-ia32-msvc": + optional: true + "@swc/core-win32-x64-msvc": + optional: true + peerDependenciesMeta: + "@swc/helpers": + optional: true + checksum: 10/9dce8808f8c17be58c0e42f14d1c257db0418f7f426774e2f05794eb4b9011445c7ac13805e7ae0dad53b858720eabaffe0bcc5366696007e166bc4ab50fbe4d + languageName: node + linkType: hard + "@swc/counter@npm:^0.1.3": version: 0.1.3 resolution: "@swc/counter@npm:0.1.3" @@ -8915,12 +8871,12 @@ __metadata: languageName: node linkType: hard -"@swc/types@npm:^0.1.17": - version: 0.1.17 - resolution: "@swc/types@npm:0.1.17" +"@swc/types@npm:^0.1.17, @swc/types@npm:^0.1.19": + version: 0.1.19 + resolution: "@swc/types@npm:0.1.19" dependencies: "@swc/counter": "npm:^0.1.3" - checksum: 10/ddef1ad5bfead3acdfc41f14e79ba43a99200eb325afbad5716058dbe36358b0513400e9f22aff32432be84a98ae93df95a20b94192f69b8687144270e4eaa18 + checksum: 10/693147cc9b23147164ddff9cb89477c369fbeb103319584779352a9ff1c72e0a70b97a89dfd97629040db8956d668d7b7a8fed328ffea46a3e8c18577e396994 languageName: node linkType: hard @@ -9023,6 +8979,21 @@ __metadata: languageName: node linkType: hard +"@testing-library/jest-dom@npm:6.5.0": + version: 6.5.0 + resolution: "@testing-library/jest-dom@npm:6.5.0" + dependencies: + "@adobe/css-tools": "npm:^4.4.0" + aria-query: "npm:^5.0.0" + chalk: "npm:^3.0.0" + css.escape: "npm:^1.5.1" + dom-accessibility-api: "npm:^0.6.3" + lodash: "npm:^4.17.21" + redent: "npm:^3.0.0" + checksum: 10/3d2080888af5fd7306f57448beb5a23f55d965e265b5e53394fffc112dfb0678d616a5274ff0200c46c7618f293520f86fc8562eecd8bdbc0dbb3294d63ec431 + languageName: node + linkType: hard + "@testing-library/jest-dom@npm:6.6.3, @testing-library/jest-dom@npm:^6.1.2": version: 6.6.3 resolution: "@testing-library/jest-dom@npm:6.6.3" @@ -9058,6 +9029,15 @@ __metadata: languageName: node linkType: hard +"@testing-library/user-event@npm:14.5.2": + version: 14.5.2 + resolution: "@testing-library/user-event@npm:14.5.2" + peerDependencies: + "@testing-library/dom": ">=7.21.4" + checksum: 10/49821459d81c6bc435d97128d6386ca24f1e4b3ba8e46cb5a96fe3643efa6e002d88c1b02b7f2ec58da593e805c59b78d7fdf0db565c1f02ba782f63ee984040 + languageName: node + linkType: hard + "@testing-library/user-event@npm:14.6.1": version: 14.6.1 resolution: "@testing-library/user-event@npm:14.6.1" @@ -10064,7 +10044,7 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:22.12.0, @types/node@npm:>=10.0.0, @types/node@npm:>=13.7.0, @types/node@npm:>=13.7.4, @types/node@npm:^22.0.0": +"@types/node@npm:*, @types/node@npm:22.12.0, @types/node@npm:>=10.0.0, @types/node@npm:>=13.7.0, @types/node@npm:>=13.7.4": version: 22.12.0 resolution: "@types/node@npm:22.12.0" dependencies: @@ -10954,6 +10934,68 @@ __metadata: languageName: node linkType: hard +"@vitest/expect@npm:2.0.5": + version: 2.0.5 + resolution: "@vitest/expect@npm:2.0.5" + dependencies: + "@vitest/spy": "npm:2.0.5" + "@vitest/utils": "npm:2.0.5" + chai: "npm:^5.1.1" + tinyrainbow: "npm:^1.2.0" + checksum: 10/ca9a218f50254b2259fd16166b2d8c9ccc8ee2cc068905e6b3d6281da10967b1590cc7d34b5fa9d429297f97e740450233745583b4cc12272ff11705faf70a37 + languageName: node + linkType: hard + +"@vitest/pretty-format@npm:2.0.5": + version: 2.0.5 + resolution: "@vitest/pretty-format@npm:2.0.5" + dependencies: + tinyrainbow: "npm:^1.2.0" + checksum: 10/70bf452dd0b8525e658795125b3f11110bd6baadfaa38c5bb91ca763bded35ec6dc80e27964ad4e91b91be6544d35e18ea7748c1997693988f975a7283c3e9a0 + languageName: node + linkType: hard + +"@vitest/pretty-format@npm:2.1.9": + version: 2.1.9 + resolution: "@vitest/pretty-format@npm:2.1.9" + dependencies: + tinyrainbow: "npm:^1.2.0" + checksum: 10/557dc637c5825abd62ccb15080e59e04d22121e746d8020a0815d7c0c45132fed81b1ff36b26f5991e57a9f1d36e52aa19712abbfe1d0cbcd14252b449a919dc + languageName: node + linkType: hard + +"@vitest/spy@npm:2.0.5": + version: 2.0.5 + resolution: "@vitest/spy@npm:2.0.5" + dependencies: + tinyspy: "npm:^3.0.0" + checksum: 10/ed19f4c3bb4d3853241e8070979615138e24403ce4c137fa48c903b3af2c8b3ada2cc26aca9c1aa323bb314a457a8130a29acbb18dafd4e42737deefb2abf1ca + languageName: node + linkType: hard + +"@vitest/utils@npm:2.0.5": + version: 2.0.5 + resolution: "@vitest/utils@npm:2.0.5" + dependencies: + "@vitest/pretty-format": "npm:2.0.5" + estree-walker: "npm:^3.0.3" + loupe: "npm:^3.1.1" + tinyrainbow: "npm:^1.2.0" + checksum: 10/d631d56d29c33bc8de631166b2b6691c470187a345469dfef7048befe6027e1c6ff9552f2ee11c8a247522c325c4a64bfcc73f8f0f0c525da39cb9f190f119f8 + languageName: node + linkType: hard + +"@vitest/utils@npm:^2.1.1": + version: 2.1.9 + resolution: "@vitest/utils@npm:2.1.9" + dependencies: + "@vitest/pretty-format": "npm:2.1.9" + loupe: "npm:^3.1.2" + tinyrainbow: "npm:^1.2.0" + checksum: 10/83d62d5703a3210a2f137c25dc4e797a7a1d74d5d2e14ecc33b274c7710304fa8b5099101c98bc8d66cc2bf18a14f88ebf21f0996a99d0ee1439ae23b49f3961 + languageName: node + linkType: hard + "@webassemblyjs/ast@npm:1.14.1, @webassemblyjs/ast@npm:^1.12.1, @webassemblyjs/ast@npm:^1.14.1": version: 1.14.1 resolution: "@webassemblyjs/ast@npm:1.14.1" @@ -11860,6 +11902,13 @@ __metadata: languageName: node linkType: hard +"assertion-error@npm:^2.0.1": + version: 2.0.1 + resolution: "assertion-error@npm:2.0.1" + checksum: 10/a0789dd882211b87116e81e2648ccb7f60340b34f19877dd020b39ebb4714e475eb943e14ba3e22201c221ef6645b7bfe10297e76b6ac95b48a9898c1211ce66 + languageName: node + linkType: hard + "ast-types-flow@npm:^0.0.8": version: 0.0.8 resolution: "ast-types-flow@npm:0.0.8" @@ -12823,6 +12872,19 @@ __metadata: languageName: node linkType: hard +"chai@npm:^5.1.1": + version: 5.2.0 + resolution: "chai@npm:5.2.0" + dependencies: + assertion-error: "npm:^2.0.1" + check-error: "npm:^2.1.1" + deep-eql: "npm:^5.0.1" + loupe: "npm:^3.1.0" + pathval: "npm:^2.0.0" + checksum: 10/2ce03671c159c6a567bf1912756daabdbb7c075f3c0078f1b59d61da8d276936367ee696dfe093b49e1479d9ba93a6074c8e55d49791dddd8061728cdcad249e + languageName: node + linkType: hard + "chalk@npm:4.1.0": version: 4.1.0 resolution: "chalk@npm:4.1.0" @@ -12920,6 +12982,13 @@ __metadata: languageName: node linkType: hard +"check-error@npm:^2.1.1": + version: 2.1.1 + resolution: "check-error@npm:2.1.1" + checksum: 10/d785ed17b1d4a4796b6e75c765a9a290098cf52ff9728ce0756e8ffd4293d2e419dd30c67200aee34202463b474306913f2fcfaf1890641026d9fc6966fea27a + languageName: node + linkType: hard + "check-more-types@npm:^2.24.0": version: 2.24.0 resolution: "check-more-types@npm:2.24.0" @@ -14964,6 +15033,13 @@ __metadata: languageName: node linkType: hard +"deep-eql@npm:^5.0.1": + version: 5.0.2 + resolution: "deep-eql@npm:5.0.2" + checksum: 10/a529b81e2ef8821621d20a36959a0328873a3e49d393ad11f8efe8559f31239494c2eb889b80342808674c475802ba95b9d6c4c27641b9a029405104c1b59fcf + languageName: node + linkType: hard + "deep-extend@npm:0.6.0": version: 0.6.0 resolution: "deep-extend@npm:0.6.0" @@ -15967,7 +16043,7 @@ __metadata: languageName: node linkType: hard -"esbuild@npm:0.25.0, esbuild@npm:^0.25.0": +"esbuild@npm:0.25.0, esbuild@npm:^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0, esbuild@npm:^0.25.0": version: 0.25.0 resolution: "esbuild@npm:0.25.0" dependencies: @@ -16053,92 +16129,6 @@ __metadata: languageName: node linkType: hard -"esbuild@npm:^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0": - version: 0.24.2 - resolution: "esbuild@npm:0.24.2" - dependencies: - "@esbuild/aix-ppc64": "npm:0.24.2" - "@esbuild/android-arm": "npm:0.24.2" - "@esbuild/android-arm64": "npm:0.24.2" - "@esbuild/android-x64": "npm:0.24.2" - "@esbuild/darwin-arm64": "npm:0.24.2" - "@esbuild/darwin-x64": "npm:0.24.2" - "@esbuild/freebsd-arm64": "npm:0.24.2" - "@esbuild/freebsd-x64": "npm:0.24.2" - "@esbuild/linux-arm": "npm:0.24.2" - "@esbuild/linux-arm64": "npm:0.24.2" - "@esbuild/linux-ia32": "npm:0.24.2" - "@esbuild/linux-loong64": "npm:0.24.2" - "@esbuild/linux-mips64el": "npm:0.24.2" - "@esbuild/linux-ppc64": "npm:0.24.2" - "@esbuild/linux-riscv64": "npm:0.24.2" - "@esbuild/linux-s390x": "npm:0.24.2" - "@esbuild/linux-x64": "npm:0.24.2" - "@esbuild/netbsd-arm64": "npm:0.24.2" - "@esbuild/netbsd-x64": "npm:0.24.2" - "@esbuild/openbsd-arm64": "npm:0.24.2" - "@esbuild/openbsd-x64": "npm:0.24.2" - "@esbuild/sunos-x64": "npm:0.24.2" - "@esbuild/win32-arm64": "npm:0.24.2" - "@esbuild/win32-ia32": "npm:0.24.2" - "@esbuild/win32-x64": "npm:0.24.2" - dependenciesMeta: - "@esbuild/aix-ppc64": - optional: true - "@esbuild/android-arm": - optional: true - "@esbuild/android-arm64": - optional: true - "@esbuild/android-x64": - optional: true - "@esbuild/darwin-arm64": - optional: true - "@esbuild/darwin-x64": - optional: true - "@esbuild/freebsd-arm64": - optional: true - "@esbuild/freebsd-x64": - optional: true - "@esbuild/linux-arm": - optional: true - "@esbuild/linux-arm64": - optional: true - "@esbuild/linux-ia32": - optional: true - "@esbuild/linux-loong64": - optional: true - "@esbuild/linux-mips64el": - optional: true - "@esbuild/linux-ppc64": - optional: true - "@esbuild/linux-riscv64": - optional: true - "@esbuild/linux-s390x": - optional: true - "@esbuild/linux-x64": - optional: true - "@esbuild/netbsd-arm64": - optional: true - "@esbuild/netbsd-x64": - optional: true - "@esbuild/openbsd-arm64": - optional: true - "@esbuild/openbsd-x64": - optional: true - "@esbuild/sunos-x64": - optional: true - "@esbuild/win32-arm64": - optional: true - "@esbuild/win32-ia32": - optional: true - "@esbuild/win32-x64": - optional: true - bin: - esbuild: bin/esbuild - checksum: 10/95425071c9f24ff88bf61e0710b636ec0eb24ddf8bd1f7e1edef3044e1221104bbfa7bbb31c18018c8c36fa7902c5c0b843f829b981ebc89160cf5eebdaa58f4 - languageName: node - linkType: hard - "escalade@npm:^3.1.1, escalade@npm:^3.2.0": version: 3.2.0 resolution: "escalade@npm:3.2.0" @@ -16605,6 +16595,15 @@ __metadata: languageName: node linkType: hard +"estree-walker@npm:^3.0.3": + version: 3.0.3 + resolution: "estree-walker@npm:3.0.3" + dependencies: + "@types/estree": "npm:^1.0.0" + checksum: 10/a65728d5727b71de172c5df323385755a16c0fdab8234dc756c3854cfee343261ddfbb72a809a5660fac8c75d960bb3e21aa898c2d7e9b19bb298482ca58a3af + languageName: node + linkType: hard + "esutils@npm:^2.0.2": version: 2.0.3 resolution: "esutils@npm:2.0.3" @@ -21956,6 +21955,13 @@ __metadata: languageName: node linkType: hard +"loupe@npm:^3.1.0, loupe@npm:^3.1.1, loupe@npm:^3.1.2": + version: 3.1.3 + resolution: "loupe@npm:3.1.3" + checksum: 10/9e98c34daf0eba48ccc603595e51f2ae002110982d84879cf78c51de2c632f0c571dfe82ce4210af60c32203d06b443465c269bda925076fe6d9b612cc65c321 + languageName: node + linkType: hard + "lower-case@npm:^2.0.2": version: 2.0.2 resolution: "lower-case@npm:2.0.2" @@ -24505,6 +24511,13 @@ __metadata: languageName: node linkType: hard +"pathval@npm:^2.0.0": + version: 2.0.0 + resolution: "pathval@npm:2.0.0" + checksum: 10/b91575bf9cdf01757afd7b5e521eb8a0b874a49bc972d08e0047cfea0cd3c019f5614521d4bc83d2855e3fcc331db6817dfd533dd8f3d90b16bc76fad2450fc1 + languageName: node + linkType: hard + "pbf@npm:3.2.1": version: 3.2.1 resolution: "pbf@npm:3.2.1" @@ -26280,7 +26293,7 @@ __metadata: languageName: node linkType: hard -"react-dom@npm:18.3.1, react-dom@npm:^16.8.0 || ^17.0.0 || ^18.0.0, react-dom@npm:^18.3.1": +"react-dom@npm:18.3.1, react-dom@npm:^18.3.1": version: 18.3.1 resolution: "react-dom@npm:18.3.1" dependencies: @@ -26292,6 +26305,17 @@ __metadata: languageName: node linkType: hard +"react-dom@npm:^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0": + version: 19.0.0 + resolution: "react-dom@npm:19.0.0" + dependencies: + scheduler: "npm:^0.25.0" + peerDependencies: + react: ^19.0.0 + checksum: 10/aa64a2f1991042f516260e8b0eca0ae777b6c8f1aa2b5ae096e80bbb6ac9b005aef2bca697969841d34f7e1819556263476bdfea36c35092e8d9aefde3de2d9a + languageName: node + linkType: hard + "react-draggable@npm:4.4.6, react-draggable@npm:^4.0.3, react-draggable@npm:^4.4.5": version: 4.4.6 resolution: "react-draggable@npm:4.4.6" @@ -27140,7 +27164,7 @@ __metadata: languageName: node linkType: hard -"react@npm:18.3.1, react@npm:^16.8.0 || ^17.0.0 || ^18.0.0, react@npm:^18": +"react@npm:18.3.1, react@npm:^18": version: 18.3.1 resolution: "react@npm:18.3.1" dependencies: @@ -27149,6 +27173,13 @@ __metadata: languageName: node linkType: hard +"react@npm:^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0": + version: 19.0.0 + resolution: "react@npm:19.0.0" + checksum: 10/2490969c503f644703c88990d20e4011fa6119ddeca451e9de48f6d7ab058d670d2852a5fcd3aa3cd90a923ab2815d532637bd4a814add402ae5c0d4f129ee71 + languageName: node + linkType: hard + "read-cmd-shim@npm:4.0.0, read-cmd-shim@npm:^4.0.0": version: 4.0.0 resolution: "read-cmd-shim@npm:4.0.0" @@ -28208,6 +28239,13 @@ __metadata: languageName: node linkType: hard +"scheduler@npm:^0.25.0": + version: 0.25.0 + resolution: "scheduler@npm:0.25.0" + checksum: 10/e661e38503ab29a153429a99203fefa764f28b35c079719eb5efdd2c1c1086522f6653d8ffce388209682c23891a6d1d32fa6badf53c35fb5b9cd0c55ace42de + languageName: node + linkType: hard + "schema-utils@npm:>1.0.0, schema-utils@npm:^4.0.0, schema-utils@npm:^4.2.0, schema-utils@npm:^4.3.0": version: 4.3.0 resolution: "schema-utils@npm:4.3.0" @@ -29369,11 +29407,11 @@ __metadata: languageName: node linkType: hard -"storybook@npm:^8.4.2": - version: 8.4.4 - resolution: "storybook@npm:8.4.4" +"storybook@npm:^8.6.2": + version: 8.6.2 + resolution: "storybook@npm:8.6.2" dependencies: - "@storybook/core": "npm:8.4.4" + "@storybook/core": "npm:8.6.2" peerDependencies: prettier: ^2 || ^3 peerDependenciesMeta: @@ -29383,7 +29421,7 @@ __metadata: getstorybook: ./bin/index.cjs sb: ./bin/index.cjs storybook: ./bin/index.cjs - checksum: 10/e2d27c97a82da9161f5c8f3d2cadbd77701032b5053c714a768930f41fe5aae479c07f8fb5afa98434e45d89ee501fa9866bdea4fdcb16a4723b8238c56d974f + checksum: 10/81884ce80d36bfe3170c46ce08168f24a2a27b2698a9ec66ebb1a9727502ab9db3e6e221121a10606ef06db466966b47a12b48b99e519755c508bc183a2de815 languageName: node linkType: hard @@ -29995,7 +30033,7 @@ __metadata: languageName: node linkType: hard -"swc-loader@npm:0.2.6, swc-loader@npm:^0.2.3": +"swc-loader@npm:0.2.6, swc-loader@npm:^0.2.6": version: 0.2.6 resolution: "swc-loader@npm:0.2.6" dependencies: @@ -30304,6 +30342,20 @@ __metadata: languageName: node linkType: hard +"tinyrainbow@npm:^1.2.0": + version: 1.2.0 + resolution: "tinyrainbow@npm:1.2.0" + checksum: 10/2924444db6804355e5ba2b6e586c7f77329d93abdd7257a069a0f4530dff9f16de484e80479094e3f39273462541b003a65ee3a6afc2d12555aa745132deba5d + languageName: node + linkType: hard + +"tinyspy@npm:^3.0.0": + version: 3.0.2 + resolution: "tinyspy@npm:3.0.2" + checksum: 10/5db671b2ff5cd309de650c8c4761ca945459d7204afb1776db9a04fb4efa28a75f08517a8620c01ee32a577748802231ad92f7d5b194dc003ee7f987a2a06337 + languageName: node + linkType: hard + "tlds@npm:1.252.0": version: 1.252.0 resolution: "tlds@npm:1.252.0" @@ -30786,13 +30838,6 @@ __metadata: languageName: node linkType: hard -"type-fest@npm:^2.19.0": - version: 2.19.0 - resolution: "type-fest@npm:2.19.0" - checksum: 10/7bf9e8fdf34f92c8bb364c0af14ca875fac7e0183f2985498b77be129dc1b3b1ad0a6b3281580f19e48c6105c037fb966ad9934520c69c6434d17fd0af4eed78 - languageName: node - linkType: hard - "type-fest@npm:^3.0.0": version: 3.13.1 resolution: "type-fest@npm:3.13.1" From 5652e0b835e74c63dd3bb1572653a4b91504c6f2 Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Fri, 28 Feb 2025 11:34:09 +0300 Subject: [PATCH 28/74] K8s/Dashboard/SQL: Support ascending order query (#101363) --- pkg/registry/apis/dashboard/legacy/migrate.go | 2 ++ pkg/registry/apis/dashboard/legacy/queries.go | 6 +++++ .../apis/dashboard/legacy/queries_test.go | 8 +++++++ .../dashboard/legacy/query_dashboards.sql | 4 ++-- ...--query_dashboards-export_with_history.sql | 22 +++++++++++++++++++ .../mysql-query_dashboards-dashboard.sql | 18 --------------- ...l-query_dashboards-dashboard_next_page.sql | 20 ----------------- .../mysql-query_dashboards-history_uid.sql | 19 ---------------- ...uery_dashboards-history_uid_at_version.sql | 20 ----------------- ...ery_dashboards-history_uid_second_page.sql | 20 ----------------- ...--query_dashboards-export_with_history.sql | 22 +++++++++++++++++++ .../postgres-query_dashboards-dashboard.sql | 18 --------------- ...s-query_dashboards-dashboard_next_page.sql | 20 ----------------- .../postgres-query_dashboards-history_uid.sql | 19 ---------------- ...uery_dashboards-history_uid_at_version.sql | 20 ----------------- ...ery_dashboards-history_uid_second_page.sql | 20 ----------------- ...--query_dashboards-export_with_history.sql | 22 +++++++++++++++++++ .../sqlite-query_dashboards-dashboard.sql | 18 --------------- ...e-query_dashboards-dashboard_next_page.sql | 20 ----------------- .../sqlite-query_dashboards-history_uid.sql | 19 ---------------- ...uery_dashboards-history_uid_at_version.sql | 20 ----------------- ...ery_dashboards-history_uid_second_page.sql | 20 ----------------- pkg/registry/apis/dashboard/legacy/types.go | 3 +++ 23 files changed, 87 insertions(+), 293 deletions(-) create mode 100755 pkg/registry/apis/dashboard/legacy/testdata/mysql--query_dashboards-export_with_history.sql delete mode 100755 pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-dashboard.sql delete mode 100755 pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-dashboard_next_page.sql delete mode 100755 pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-history_uid.sql delete mode 100755 pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-history_uid_at_version.sql delete mode 100755 pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-history_uid_second_page.sql create mode 100755 pkg/registry/apis/dashboard/legacy/testdata/postgres--query_dashboards-export_with_history.sql delete mode 100755 pkg/registry/apis/dashboard/legacy/testdata/postgres-query_dashboards-dashboard.sql delete mode 100755 pkg/registry/apis/dashboard/legacy/testdata/postgres-query_dashboards-dashboard_next_page.sql delete mode 100755 pkg/registry/apis/dashboard/legacy/testdata/postgres-query_dashboards-history_uid.sql delete mode 100755 pkg/registry/apis/dashboard/legacy/testdata/postgres-query_dashboards-history_uid_at_version.sql delete mode 100755 pkg/registry/apis/dashboard/legacy/testdata/postgres-query_dashboards-history_uid_second_page.sql create mode 100755 pkg/registry/apis/dashboard/legacy/testdata/sqlite--query_dashboards-export_with_history.sql delete mode 100755 pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-dashboard.sql delete mode 100755 pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-dashboard_next_page.sql delete mode 100755 pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-history_uid.sql delete mode 100755 pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-history_uid_at_version.sql delete mode 100755 pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-history_uid_second_page.sql diff --git a/pkg/registry/apis/dashboard/legacy/migrate.go b/pkg/registry/apis/dashboard/legacy/migrate.go index 27959d31785..a39463a4b8e 100644 --- a/pkg/registry/apis/dashboard/legacy/migrate.go +++ b/pkg/registry/apis/dashboard/legacy/migrate.go @@ -195,6 +195,7 @@ func (a *dashboardSqlAccess) migrateDashboards(ctx context.Context, orgId int64, OrgID: orgId, Limit: 100000000, GetHistory: opts.WithHistory, // include history + Order: "ASC", // oldest first } blobs := &BlobStoreInfo{} @@ -301,6 +302,7 @@ func (a *dashboardSqlAccess) migrateFolders(ctx context.Context, orgId int64, op OrgID: orgId, Limit: 100000000, GetFolders: true, + Order: "ASC", } sql, err := a.sql(ctx) diff --git a/pkg/registry/apis/dashboard/legacy/queries.go b/pkg/registry/apis/dashboard/legacy/queries.go index 9c4688202ba..56807b9cc5a 100644 --- a/pkg/registry/apis/dashboard/legacy/queries.go +++ b/pkg/registry/apis/dashboard/legacy/queries.go @@ -41,10 +41,16 @@ type sqlQuery struct { } func (r sqlQuery) Validate() error { + if r.Query.Order == "ASC" && r.Query.LastID > 0 { + return fmt.Errorf("ascending order does not support paging by last id") + } return nil // TODO } func newQueryReq(sql *legacysql.LegacyDatabaseHelper, query *DashboardQuery) sqlQuery { + if query.Order == "" { + query.Order = "DESC" // use version as RV + } return sqlQuery{ SQLTemplate: sqltemplate.New(sql.DialectForDriver()), Query: query, diff --git a/pkg/registry/apis/dashboard/legacy/queries_test.go b/pkg/registry/apis/dashboard/legacy/queries_test.go index 315c9593450..35fffa9a597 100644 --- a/pkg/registry/apis/dashboard/legacy/queries_test.go +++ b/pkg/registry/apis/dashboard/legacy/queries_test.go @@ -76,6 +76,14 @@ func TestDashboardQueries(t *testing.T) { GetFolders: true, }), }, + { + Name: "export_with_history", + Data: getQuery(&DashboardQuery{ + OrgID: 1, + GetHistory: true, + Order: "ASC", + }), + }, }, sqlQueryPanels: { { diff --git a/pkg/registry/apis/dashboard/legacy/query_dashboards.sql b/pkg/registry/apis/dashboard/legacy/query_dashboards.sql index 80c0b815310..6da03389dab 100644 --- a/pkg/registry/apis/dashboard/legacy/query_dashboards.sql +++ b/pkg/registry/apis/dashboard/legacy/query_dashboards.sql @@ -33,8 +33,8 @@ WHERE dashboard.is_folder = {{ .Arg .Query.GetFolders }} AND dashboard_version.version < {{ .Arg .Query.LastID }} {{ end }} ORDER BY - dashboard_version.created DESC, - dashboard_version.version DESC, + dashboard_version.created {{ .Query.Order }}, + dashboard_version.version {{ .Query.Order }}, dashboard.uid ASC {{ else }} {{ if .Query.UID }} diff --git a/pkg/registry/apis/dashboard/legacy/testdata/mysql--query_dashboards-export_with_history.sql b/pkg/registry/apis/dashboard/legacy/testdata/mysql--query_dashboards-export_with_history.sql new file mode 100755 index 00000000000..a19e0df94d1 --- /dev/null +++ b/pkg/registry/apis/dashboard/legacy/testdata/mysql--query_dashboards-export_with_history.sql @@ -0,0 +1,22 @@ +SELECT + dashboard.org_id, dashboard.id, + dashboard.uid, dashboard.folder_uid, + dashboard.deleted, plugin_id, + provisioning.name as repo_name, + provisioning.external_id as repo_path, + provisioning.check_sum as repo_hash, + provisioning.updated as repo_ts, + dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id, + dashboard_version.created, updated_user.uid as updated_by,updated_user.id as created_by_id, + dashboard_version.version, dashboard_version.message, dashboard_version.data +FROM `grafana`.`dashboard` as dashboard +LEFT OUTER JOIN `grafana`.`dashboard_version` as dashboard_version ON dashboard.id = dashboard_version.dashboard_id +LEFT OUTER JOIN `grafana`.`dashboard_provisioning` as provisioning ON dashboard.id = provisioning.dashboard_id +LEFT OUTER JOIN `grafana`.`user` as created_user ON dashboard.created_by = created_user.id +LEFT OUTER JOIN `grafana`.`user` as updated_user ON dashboard.updated_by = updated_user.id +WHERE dashboard.is_folder = FALSE + AND dashboard.org_id = 1 + ORDER BY + dashboard_version.created ASC, + dashboard_version.version ASC, + dashboard.uid ASC diff --git a/pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-dashboard.sql b/pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-dashboard.sql deleted file mode 100755 index c5da8ec1fea..00000000000 --- a/pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-dashboard.sql +++ /dev/null @@ -1,18 +0,0 @@ -SELECT - dashboard.org_id, dashboard.id, - dashboard.uid, dashboard.folder_uid, - dashboard.deleted, plugin_id, - dashboard_provisioning.name as origin_name, - dashboard_provisioning.external_id as origin_path, - dashboard_provisioning.check_sum as origin_key, - dashboard_provisioning.updated as origin_ts, - dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id, - dashboard.updated, updated_user.uid as updated_by, dashboard.updated_by as updated_by_id, - dashboard.version, '' as message, dashboard.data - FROM dashboard - LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id - LEFT OUTER JOIN `user` AS created_user ON dashboard.created_by = created_user.id - LEFT OUTER JOIN `user` AS updated_user ON dashboard.updated_by = updated_user.id - WHERE dashboard.is_folder = false - AND dashboard.org_id = 2 - ORDER BY dashboard.id DESC diff --git a/pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-dashboard_next_page.sql b/pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-dashboard_next_page.sql deleted file mode 100755 index 0fc8146965f..00000000000 --- a/pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-dashboard_next_page.sql +++ /dev/null @@ -1,20 +0,0 @@ -SELECT - dashboard.org_id, dashboard.id, - dashboard.uid, dashboard.folder_uid, - dashboard.deleted, plugin_id, - dashboard_provisioning.name as origin_name, - dashboard_provisioning.external_id as origin_path, - dashboard_provisioning.check_sum as origin_key, - dashboard_provisioning.updated as origin_ts, - dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id, - dashboard.updated, updated_user.uid as updated_by, dashboard.updated_by as updated_by_id, - dashboard.version, '' as message, dashboard.data - FROM dashboard - LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id - LEFT OUTER JOIN `user` AS created_user ON dashboard.created_by = created_user.id - LEFT OUTER JOIN `user` AS updated_user ON dashboard.updated_by = updated_user.id - WHERE dashboard.is_folder = false - AND dashboard.org_id = 2 - AND dashboard.id > 22 - AND dashboard.deleted IS NULL - ORDER BY dashboard.id DESC diff --git a/pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-history_uid.sql b/pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-history_uid.sql deleted file mode 100755 index c2385d49c1d..00000000000 --- a/pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-history_uid.sql +++ /dev/null @@ -1,19 +0,0 @@ -SELECT - dashboard.org_id, dashboard.id, - dashboard.uid, dashboard.folder_uid, - dashboard.deleted, plugin_id, - dashboard_provisioning.name as origin_name, - dashboard_provisioning.external_id as origin_path, - dashboard_provisioning.check_sum as origin_key, - dashboard_provisioning.updated as origin_ts, - dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id, - dashboard.updated, updated_user.uid as updated_by, dashboard.updated_by as updated_by_id, - dashboard.version, '' as message, dashboard.data - FROM dashboard - LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id - LEFT OUTER JOIN `user` AS created_user ON dashboard.created_by = created_user.id - LEFT OUTER JOIN `user` AS updated_user ON dashboard.updated_by = updated_user.id - WHERE dashboard.is_folder = false - AND dashboard.org_id = 2 - AND dashboard.uid = 'UUU' - ORDER BY dashboard.id DESC diff --git a/pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-history_uid_at_version.sql b/pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-history_uid_at_version.sql deleted file mode 100755 index 93be3353bc8..00000000000 --- a/pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-history_uid_at_version.sql +++ /dev/null @@ -1,20 +0,0 @@ -SELECT - dashboard.org_id, dashboard.id, - dashboard.uid, dashboard.folder_uid, - dashboard.deleted, plugin_id, - dashboard_provisioning.name as origin_name, - dashboard_provisioning.external_id as origin_path, - dashboard_provisioning.check_sum as origin_key, - dashboard_provisioning.updated as origin_ts, - dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id, - dashboard_version.created, updated_user.uid as updated_by,updated_user.id as created_by_id, - dashboard_version.version, dashboard_version.message, dashboard_version.data - FROM dashboard - LEFT OUTER JOIN dashboard_version ON dashboard.id = dashboard_version.dashboard_id - LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id - LEFT OUTER JOIN `user` AS created_user ON dashboard.created_by = created_user.id - LEFT OUTER JOIN `user` AS updated_user ON dashboard.updated_by = updated_user.id - WHERE dashboard.is_folder = false - AND dashboard.org_id = 2 - AND dashboard_version.version = 3 - ORDER BY dashboard_version.version DESC diff --git a/pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-history_uid_second_page.sql b/pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-history_uid_second_page.sql deleted file mode 100755 index dcdfa47e3f7..00000000000 --- a/pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-history_uid_second_page.sql +++ /dev/null @@ -1,20 +0,0 @@ -SELECT - dashboard.org_id, dashboard.id, - dashboard.uid, dashboard.folder_uid, - dashboard.deleted, plugin_id, - dashboard_provisioning.name as origin_name, - dashboard_provisioning.external_id as origin_path, - dashboard_provisioning.check_sum as origin_key, - dashboard_provisioning.updated as origin_ts, - dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id, - dashboard.updated, updated_user.uid as updated_by, dashboard.updated_by as updated_by_id, - dashboard.version, '' as message, dashboard.data - FROM dashboard - LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id - LEFT OUTER JOIN `user` AS created_user ON dashboard.created_by = created_user.id - LEFT OUTER JOIN `user` AS updated_user ON dashboard.updated_by = updated_user.id - WHERE dashboard.is_folder = false - AND dashboard.org_id = 2 - AND dashboard.uid = 'UUU' - AND dashboard.deleted IS NULL - ORDER BY dashboard.id DESC diff --git a/pkg/registry/apis/dashboard/legacy/testdata/postgres--query_dashboards-export_with_history.sql b/pkg/registry/apis/dashboard/legacy/testdata/postgres--query_dashboards-export_with_history.sql new file mode 100755 index 00000000000..8ad23c2206f --- /dev/null +++ b/pkg/registry/apis/dashboard/legacy/testdata/postgres--query_dashboards-export_with_history.sql @@ -0,0 +1,22 @@ +SELECT + dashboard.org_id, dashboard.id, + dashboard.uid, dashboard.folder_uid, + dashboard.deleted, plugin_id, + provisioning.name as repo_name, + provisioning.external_id as repo_path, + provisioning.check_sum as repo_hash, + provisioning.updated as repo_ts, + dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id, + dashboard_version.created, updated_user.uid as updated_by,updated_user.id as created_by_id, + dashboard_version.version, dashboard_version.message, dashboard_version.data +FROM "grafana"."dashboard" as dashboard +LEFT OUTER JOIN "grafana"."dashboard_version" as dashboard_version ON dashboard.id = dashboard_version.dashboard_id +LEFT OUTER JOIN "grafana"."dashboard_provisioning" as provisioning ON dashboard.id = provisioning.dashboard_id +LEFT OUTER JOIN "grafana"."user" as created_user ON dashboard.created_by = created_user.id +LEFT OUTER JOIN "grafana"."user" as updated_user ON dashboard.updated_by = updated_user.id +WHERE dashboard.is_folder = FALSE + AND dashboard.org_id = 1 + ORDER BY + dashboard_version.created ASC, + dashboard_version.version ASC, + dashboard.uid ASC diff --git a/pkg/registry/apis/dashboard/legacy/testdata/postgres-query_dashboards-dashboard.sql b/pkg/registry/apis/dashboard/legacy/testdata/postgres-query_dashboards-dashboard.sql deleted file mode 100755 index 64a659963b8..00000000000 --- a/pkg/registry/apis/dashboard/legacy/testdata/postgres-query_dashboards-dashboard.sql +++ /dev/null @@ -1,18 +0,0 @@ -SELECT - dashboard.org_id, dashboard.id, - dashboard.uid, dashboard.folder_uid, - dashboard.deleted, plugin_id, - dashboard_provisioning.name as origin_name, - dashboard_provisioning.external_id as origin_path, - dashboard_provisioning.check_sum as origin_key, - dashboard_provisioning.updated as origin_ts, - dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id, - dashboard.updated, updated_user.uid as updated_by, dashboard.updated_by as updated_by_id, - dashboard.version, '' as message, dashboard.data - FROM dashboard - LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id - LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id - LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id - WHERE dashboard.is_folder = false - AND dashboard.org_id = 2 - ORDER BY dashboard.id DESC diff --git a/pkg/registry/apis/dashboard/legacy/testdata/postgres-query_dashboards-dashboard_next_page.sql b/pkg/registry/apis/dashboard/legacy/testdata/postgres-query_dashboards-dashboard_next_page.sql deleted file mode 100755 index cda07bd2fd5..00000000000 --- a/pkg/registry/apis/dashboard/legacy/testdata/postgres-query_dashboards-dashboard_next_page.sql +++ /dev/null @@ -1,20 +0,0 @@ -SELECT - dashboard.org_id, dashboard.id, - dashboard.uid, dashboard.folder_uid, - dashboard.deleted, plugin_id, - dashboard_provisioning.name as origin_name, - dashboard_provisioning.external_id as origin_path, - dashboard_provisioning.check_sum as origin_key, - dashboard_provisioning.updated as origin_ts, - dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id, - dashboard.updated, updated_user.uid as updated_by, dashboard.updated_by as updated_by_id, - dashboard.version, '' as message, dashboard.data - FROM dashboard - LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id - LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id - LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id - WHERE dashboard.is_folder = false - AND dashboard.org_id = 2 - AND dashboard.id > 22 - AND dashboard.deleted IS NULL - ORDER BY dashboard.id DESC diff --git a/pkg/registry/apis/dashboard/legacy/testdata/postgres-query_dashboards-history_uid.sql b/pkg/registry/apis/dashboard/legacy/testdata/postgres-query_dashboards-history_uid.sql deleted file mode 100755 index 71f0756bb3f..00000000000 --- a/pkg/registry/apis/dashboard/legacy/testdata/postgres-query_dashboards-history_uid.sql +++ /dev/null @@ -1,19 +0,0 @@ -SELECT - dashboard.org_id, dashboard.id, - dashboard.uid, dashboard.folder_uid, - dashboard.deleted, plugin_id, - dashboard_provisioning.name as origin_name, - dashboard_provisioning.external_id as origin_path, - dashboard_provisioning.check_sum as origin_key, - dashboard_provisioning.updated as origin_ts, - dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id, - dashboard.updated, updated_user.uid as updated_by, dashboard.updated_by as updated_by_id, - dashboard.version, '' as message, dashboard.data - FROM dashboard - LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id - LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id - LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id - WHERE dashboard.is_folder = false - AND dashboard.org_id = 2 - AND dashboard.uid = 'UUU' - ORDER BY dashboard.id DESC diff --git a/pkg/registry/apis/dashboard/legacy/testdata/postgres-query_dashboards-history_uid_at_version.sql b/pkg/registry/apis/dashboard/legacy/testdata/postgres-query_dashboards-history_uid_at_version.sql deleted file mode 100755 index 002d1e9fdae..00000000000 --- a/pkg/registry/apis/dashboard/legacy/testdata/postgres-query_dashboards-history_uid_at_version.sql +++ /dev/null @@ -1,20 +0,0 @@ -SELECT - dashboard.org_id, dashboard.id, - dashboard.uid, dashboard.folder_uid, - dashboard.deleted, plugin_id, - dashboard_provisioning.name as origin_name, - dashboard_provisioning.external_id as origin_path, - dashboard_provisioning.check_sum as origin_key, - dashboard_provisioning.updated as origin_ts, - dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id, - dashboard_version.created, updated_user.uid as updated_by,updated_user.id as created_by_id, - dashboard_version.version, dashboard_version.message, dashboard_version.data - FROM dashboard - LEFT OUTER JOIN dashboard_version ON dashboard.id = dashboard_version.dashboard_id - LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id - LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id - LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id - WHERE dashboard.is_folder = false - AND dashboard.org_id = 2 - AND dashboard_version.version = 3 - ORDER BY dashboard_version.version DESC diff --git a/pkg/registry/apis/dashboard/legacy/testdata/postgres-query_dashboards-history_uid_second_page.sql b/pkg/registry/apis/dashboard/legacy/testdata/postgres-query_dashboards-history_uid_second_page.sql deleted file mode 100755 index f28d6fac178..00000000000 --- a/pkg/registry/apis/dashboard/legacy/testdata/postgres-query_dashboards-history_uid_second_page.sql +++ /dev/null @@ -1,20 +0,0 @@ -SELECT - dashboard.org_id, dashboard.id, - dashboard.uid, dashboard.folder_uid, - dashboard.deleted, plugin_id, - dashboard_provisioning.name as origin_name, - dashboard_provisioning.external_id as origin_path, - dashboard_provisioning.check_sum as origin_key, - dashboard_provisioning.updated as origin_ts, - dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id, - dashboard.updated, updated_user.uid as updated_by, dashboard.updated_by as updated_by_id, - dashboard.version, '' as message, dashboard.data - FROM dashboard - LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id - LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id - LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id - WHERE dashboard.is_folder = false - AND dashboard.org_id = 2 - AND dashboard.uid = 'UUU' - AND dashboard.deleted IS NULL - ORDER BY dashboard.id DESC diff --git a/pkg/registry/apis/dashboard/legacy/testdata/sqlite--query_dashboards-export_with_history.sql b/pkg/registry/apis/dashboard/legacy/testdata/sqlite--query_dashboards-export_with_history.sql new file mode 100755 index 00000000000..8ad23c2206f --- /dev/null +++ b/pkg/registry/apis/dashboard/legacy/testdata/sqlite--query_dashboards-export_with_history.sql @@ -0,0 +1,22 @@ +SELECT + dashboard.org_id, dashboard.id, + dashboard.uid, dashboard.folder_uid, + dashboard.deleted, plugin_id, + provisioning.name as repo_name, + provisioning.external_id as repo_path, + provisioning.check_sum as repo_hash, + provisioning.updated as repo_ts, + dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id, + dashboard_version.created, updated_user.uid as updated_by,updated_user.id as created_by_id, + dashboard_version.version, dashboard_version.message, dashboard_version.data +FROM "grafana"."dashboard" as dashboard +LEFT OUTER JOIN "grafana"."dashboard_version" as dashboard_version ON dashboard.id = dashboard_version.dashboard_id +LEFT OUTER JOIN "grafana"."dashboard_provisioning" as provisioning ON dashboard.id = provisioning.dashboard_id +LEFT OUTER JOIN "grafana"."user" as created_user ON dashboard.created_by = created_user.id +LEFT OUTER JOIN "grafana"."user" as updated_user ON dashboard.updated_by = updated_user.id +WHERE dashboard.is_folder = FALSE + AND dashboard.org_id = 1 + ORDER BY + dashboard_version.created ASC, + dashboard_version.version ASC, + dashboard.uid ASC diff --git a/pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-dashboard.sql b/pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-dashboard.sql deleted file mode 100755 index 64a659963b8..00000000000 --- a/pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-dashboard.sql +++ /dev/null @@ -1,18 +0,0 @@ -SELECT - dashboard.org_id, dashboard.id, - dashboard.uid, dashboard.folder_uid, - dashboard.deleted, plugin_id, - dashboard_provisioning.name as origin_name, - dashboard_provisioning.external_id as origin_path, - dashboard_provisioning.check_sum as origin_key, - dashboard_provisioning.updated as origin_ts, - dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id, - dashboard.updated, updated_user.uid as updated_by, dashboard.updated_by as updated_by_id, - dashboard.version, '' as message, dashboard.data - FROM dashboard - LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id - LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id - LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id - WHERE dashboard.is_folder = false - AND dashboard.org_id = 2 - ORDER BY dashboard.id DESC diff --git a/pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-dashboard_next_page.sql b/pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-dashboard_next_page.sql deleted file mode 100755 index cda07bd2fd5..00000000000 --- a/pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-dashboard_next_page.sql +++ /dev/null @@ -1,20 +0,0 @@ -SELECT - dashboard.org_id, dashboard.id, - dashboard.uid, dashboard.folder_uid, - dashboard.deleted, plugin_id, - dashboard_provisioning.name as origin_name, - dashboard_provisioning.external_id as origin_path, - dashboard_provisioning.check_sum as origin_key, - dashboard_provisioning.updated as origin_ts, - dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id, - dashboard.updated, updated_user.uid as updated_by, dashboard.updated_by as updated_by_id, - dashboard.version, '' as message, dashboard.data - FROM dashboard - LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id - LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id - LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id - WHERE dashboard.is_folder = false - AND dashboard.org_id = 2 - AND dashboard.id > 22 - AND dashboard.deleted IS NULL - ORDER BY dashboard.id DESC diff --git a/pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-history_uid.sql b/pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-history_uid.sql deleted file mode 100755 index 71f0756bb3f..00000000000 --- a/pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-history_uid.sql +++ /dev/null @@ -1,19 +0,0 @@ -SELECT - dashboard.org_id, dashboard.id, - dashboard.uid, dashboard.folder_uid, - dashboard.deleted, plugin_id, - dashboard_provisioning.name as origin_name, - dashboard_provisioning.external_id as origin_path, - dashboard_provisioning.check_sum as origin_key, - dashboard_provisioning.updated as origin_ts, - dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id, - dashboard.updated, updated_user.uid as updated_by, dashboard.updated_by as updated_by_id, - dashboard.version, '' as message, dashboard.data - FROM dashboard - LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id - LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id - LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id - WHERE dashboard.is_folder = false - AND dashboard.org_id = 2 - AND dashboard.uid = 'UUU' - ORDER BY dashboard.id DESC diff --git a/pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-history_uid_at_version.sql b/pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-history_uid_at_version.sql deleted file mode 100755 index 002d1e9fdae..00000000000 --- a/pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-history_uid_at_version.sql +++ /dev/null @@ -1,20 +0,0 @@ -SELECT - dashboard.org_id, dashboard.id, - dashboard.uid, dashboard.folder_uid, - dashboard.deleted, plugin_id, - dashboard_provisioning.name as origin_name, - dashboard_provisioning.external_id as origin_path, - dashboard_provisioning.check_sum as origin_key, - dashboard_provisioning.updated as origin_ts, - dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id, - dashboard_version.created, updated_user.uid as updated_by,updated_user.id as created_by_id, - dashboard_version.version, dashboard_version.message, dashboard_version.data - FROM dashboard - LEFT OUTER JOIN dashboard_version ON dashboard.id = dashboard_version.dashboard_id - LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id - LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id - LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id - WHERE dashboard.is_folder = false - AND dashboard.org_id = 2 - AND dashboard_version.version = 3 - ORDER BY dashboard_version.version DESC diff --git a/pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-history_uid_second_page.sql b/pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-history_uid_second_page.sql deleted file mode 100755 index f28d6fac178..00000000000 --- a/pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-history_uid_second_page.sql +++ /dev/null @@ -1,20 +0,0 @@ -SELECT - dashboard.org_id, dashboard.id, - dashboard.uid, dashboard.folder_uid, - dashboard.deleted, plugin_id, - dashboard_provisioning.name as origin_name, - dashboard_provisioning.external_id as origin_path, - dashboard_provisioning.check_sum as origin_key, - dashboard_provisioning.updated as origin_ts, - dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id, - dashboard.updated, updated_user.uid as updated_by, dashboard.updated_by as updated_by_id, - dashboard.version, '' as message, dashboard.data - FROM dashboard - LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id - LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id - LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id - WHERE dashboard.is_folder = false - AND dashboard.org_id = 2 - AND dashboard.uid = 'UUU' - AND dashboard.deleted IS NULL - ORDER BY dashboard.id DESC diff --git a/pkg/registry/apis/dashboard/legacy/types.go b/pkg/registry/apis/dashboard/legacy/types.go index 8a62ca0c8df..d89655faf52 100644 --- a/pkg/registry/apis/dashboard/legacy/types.go +++ b/pkg/registry/apis/dashboard/legacy/types.go @@ -30,6 +30,9 @@ type DashboardQuery struct { // The label requirements Labels []*resource.Requirement + + // DESC|ASC, how to order the IDs + Order string // asc required to use lastID, desc required for export with history } func (r *DashboardQuery) UseHistoryTable() bool { From d6b6a9da7bf292407df55612d5ecc90c5adac72d Mon Sep 17 00:00:00 2001 From: Karl Persson <23356117+kalleep@users.noreply.github.com> Date: Fri, 28 Feb 2025 10:10:32 +0100 Subject: [PATCH 29/74] FolderAPI: Use different authorizer for multi-tenant api (#101372) Use different authorizers depening on if we are running multi-tenant or single-tenant --- pkg/registry/apis/folders/authorizer.go | 106 +++++++ pkg/registry/apis/folders/authorizer_test.go | 277 +++++++++++++++++++ pkg/registry/apis/folders/register.go | 70 +---- pkg/registry/apis/folders/register_test.go | 257 ++--------------- 4 files changed, 423 insertions(+), 287 deletions(-) create mode 100644 pkg/registry/apis/folders/authorizer.go create mode 100644 pkg/registry/apis/folders/authorizer_test.go diff --git a/pkg/registry/apis/folders/authorizer.go b/pkg/registry/apis/folders/authorizer.go new file mode 100644 index 00000000000..b4d5c3fdc1c --- /dev/null +++ b/pkg/registry/apis/folders/authorizer.go @@ -0,0 +1,106 @@ +package folders + +import ( + "context" + "errors" + "slices" + + "k8s.io/apiserver/pkg/authorization/authorizer" + + "github.com/grafana/authlib/types" + "github.com/grafana/grafana/pkg/apimachinery/identity" + "github.com/grafana/grafana/pkg/apimachinery/utils" + "github.com/grafana/grafana/pkg/services/accesscontrol" + "github.com/grafana/grafana/pkg/services/dashboards" +) + +// newLegacyAuthorizer creates an authorizer using legacy access control, this is only usable for single tenant api. +func newLegacyAuthorizer(ac accesscontrol.AccessControl) authorizer.Authorizer { + return authorizer.AuthorizerFunc(func(ctx context.Context, attr authorizer.Attributes) (authorizer.Decision, string, error) { + in, err := authorizerFunc(ctx, attr) + if err != nil { + if errors.Is(err, errNoUser) { + return authorizer.DecisionDeny, "", nil + } + return authorizer.DecisionNoOpinion, "", nil + } + + ok, err := ac.Evaluate(ctx, in.user, in.evaluator) + if ok { + return authorizer.DecisionAllow, "", nil + } + return authorizer.DecisionDeny, "folder", err + }) +} + +func authorizerFunc(ctx context.Context, attr authorizer.Attributes) (*authorizerParams, error) { + allowedVerbs := []string{utils.VerbCreate, utils.VerbDelete, utils.VerbList} + verb := attr.GetVerb() + name := attr.GetName() + if (!attr.IsResourceRequest()) || (name == "" && verb != utils.VerbCreate && slices.Contains(allowedVerbs, verb)) { + return nil, errNoResource + } + + // require a user + user, err := identity.GetRequester(ctx) + if err != nil { + return nil, errNoUser + } + + scope := dashboards.ScopeFoldersProvider.GetResourceScopeUID(name) + var eval accesscontrol.Evaluator + + // "get" is used for sub-resources with GET http (parents, access, count) + switch verb { + case utils.VerbCreate: + eval = accesscontrol.EvalPermission(dashboards.ActionFoldersCreate) + case utils.VerbPatch: + fallthrough + case utils.VerbUpdate: + eval = accesscontrol.EvalPermission(dashboards.ActionFoldersWrite, scope) + case utils.VerbDeleteCollection: + fallthrough + case utils.VerbDelete: + eval = accesscontrol.EvalPermission(dashboards.ActionFoldersDelete, scope) + case utils.VerbList: + eval = accesscontrol.EvalPermission(dashboards.ActionFoldersRead) + default: + eval = accesscontrol.EvalPermission(dashboards.ActionFoldersRead, scope) + } + return &authorizerParams{evaluator: eval, user: user}, nil +} + +// newMultiTenantAuthorizer creates an authorizer sutiable to multi-tenant setup. +// For now it only allow authorization of access tokens. +func newMultiTenantAuthorizer(ac types.AccessClient) authorizer.Authorizer { + return authorizer.AuthorizerFunc(func(ctx context.Context, a authorizer.Attributes) (authorizer.Decision, string, error) { + info, ok := types.AuthInfoFrom(ctx) + if !ok { + return authorizer.DecisionDeny, "missing auth info", nil + } + + // For now we only allow access policy to authorize with multi-tenant setup + if !types.IsIdentityType(info.GetIdentityType(), types.TypeAccessPolicy) { + return authorizer.DecisionDeny, "permission denied", nil + } + + res, err := ac.Check(ctx, info, types.CheckRequest{ + Verb: a.GetVerb(), + Group: a.GetAPIGroup(), + Resource: a.GetResource(), + Namespace: a.GetNamespace(), + Name: a.GetNamespace(), + Subresource: a.GetSubresource(), + }) + + if err != nil { + return authorizer.DecisionDeny, "faild to perform authorization", err + } + + if !res.Allowed { + return authorizer.DecisionDeny, "permission denied", nil + } + + return authorizer.DecisionAllow, "", nil + }) +} diff --git a/pkg/registry/apis/folders/authorizer_test.go b/pkg/registry/apis/folders/authorizer_test.go new file mode 100644 index 00000000000..eced4071112 --- /dev/null +++ b/pkg/registry/apis/folders/authorizer_test.go @@ -0,0 +1,277 @@ +package folders + +import ( + "context" + "testing" + + "github.com/go-jose/go-jose/v3/jwt" + "github.com/grafana/authlib/authn" + "github.com/grafana/authlib/authz" + "github.com/grafana/authlib/types" + "github.com/stretchr/testify/require" + "k8s.io/apiserver/pkg/authorization/authorizer" + + "github.com/grafana/grafana/pkg/apimachinery/identity" + "github.com/grafana/grafana/pkg/apimachinery/utils" + folderv0aplha1 "github.com/grafana/grafana/pkg/apis/folder/v0alpha1" + "github.com/grafana/grafana/pkg/services/accesscontrol/acimpl" + "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/featuremgmt" + "github.com/grafana/grafana/pkg/services/user" +) + +func TestLegacyAuthorizer(t *testing.T) { + type input struct { + user identity.Requester + verb string + } + type expect struct { + authorized authorizer.Decision + err error + } + var orgID int64 = 1 + + tests := []struct { + name string + input input + expect expect + }{ + { + name: "user with create permissions should be able to create a folder", + input: input{ + user: &user.SignedInUser{ + UserID: 1, + OrgID: orgID, + Name: "123", + Permissions: map[int64]map[string][]string{ + orgID: {dashboards.ActionFoldersCreate: {}, dashboards.ActionFoldersWrite: {dashboards.ScopeFoldersAll}}, + }, + }, + verb: string(utils.VerbCreate), + }, + expect: expect{ + authorized: authorizer.DecisionAllow, + }, + }, + { + name: "not possible to create a folder without a user", + input: input{ + user: nil, + verb: string(utils.VerbCreate), + }, + expect: expect{authorized: authorizer.DecisionDeny}, + }, + { + name: "user without permissions should not be able to create a folder", + input: input{ + user: &user.SignedInUser{}, + verb: string(utils.VerbCreate), + }, + expect: expect{authorized: authorizer.DecisionDeny}, + }, + { + name: "user in another orgId should not be able to create a folder ", + input: input{ + user: &user.SignedInUser{ + UserID: 1, + OrgID: 2, + Name: "123", + Permissions: map[int64]map[string][]string{ + orgID: {dashboards.ActionFoldersCreate: {}, dashboards.ActionFoldersWrite: {dashboards.ScopeFoldersAll}}, + }, + }, + verb: string(utils.VerbCreate), + }, + expect: expect{authorized: authorizer.DecisionDeny}, + }, + { + name: "user with read permissions should be able to list folders", + input: input{ + user: &user.SignedInUser{ + UserID: 1, + OrgID: orgID, + Name: "123", + Permissions: map[int64]map[string][]string{ + orgID: {}, + }, + }, + verb: string(utils.VerbList), + }, + expect: expect{authorized: authorizer.DecisionDeny}, + }, + { + name: "user with delete permissions should be able to delete a folder", + input: input{ + user: &user.SignedInUser{ + UserID: 1, + OrgID: orgID, + Name: "123", + Permissions: map[int64]map[string][]string{ + orgID: {dashboards.ActionFoldersDelete: {dashboards.ScopeFoldersAll}, dashboards.ActionFoldersWrite: {dashboards.ScopeFoldersAll}}, + }, + }, + verb: string(utils.VerbDelete), + }, + expect: expect{authorized: authorizer.DecisionAllow}, + }, + { + name: "user without delete permissions should NOT be able to delete a folder", + input: input{ + user: &user.SignedInUser{ + UserID: 1, + OrgID: orgID, + Name: "123", + Permissions: map[int64]map[string][]string{ + orgID: {}, + }, + }, + verb: string(utils.VerbDelete), + }, + expect: expect{authorized: authorizer.DecisionDeny}, + }, + { + name: "user with write permissions should be able to update a folder", + input: input{ + user: &user.SignedInUser{ + UserID: 1, + OrgID: orgID, + Name: "123", + Permissions: map[int64]map[string][]string{ + orgID: {dashboards.ActionFoldersWrite: {dashboards.ScopeFoldersAll}}, + }, + }, + verb: string(utils.VerbUpdate), + }, + expect: expect{authorized: authorizer.DecisionAllow}, + }, + { + name: "user without write permissions should NOT be able to update a folder", + input: input{ + user: &user.SignedInUser{ + UserID: 1, + OrgID: orgID, + Name: "123", + Permissions: map[int64]map[string][]string{ + orgID: {}, + }, + }, + verb: string(utils.VerbUpdate), + }, + expect: expect{authorized: authorizer.DecisionDeny}, + }, + } + + authz := newLegacyAuthorizer(acimpl.ProvideAccessControl(featuremgmt.WithFeatures("nestedFolders"))) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + authorized, _, err := authz.Authorize( + identity.WithRequester(context.Background(), tt.input.user), + authorizer.AttributesRecord{User: tt.input.user, Verb: tt.input.verb, Resource: "folders", ResourceRequest: true, Name: "123"}, + ) + if tt.expect.err != nil { + require.Error(t, err) + require.Equal(t, authorizer.DecisionDeny, authorized) + return + } + + require.NoError(t, err) + require.Equal(t, tt.expect.authorized, authorized) + }) + } +} + +func TestMultiTenantAuthorizer(t *testing.T) { + type input struct { + verb string + info types.AuthInfo + client types.AccessClient + } + + type expected struct { + authorized authorizer.Decision + err bool + } + + tests := []struct { + name string + input input + expeted expected + }{ + { + name: "non access policy idenity should not be able to authorize", + input: input{ + verb: utils.VerbGet, + info: &identity.StaticRequester{ + Type: types.TypeUser, + UserID: 1, + UserUID: "1", + }, + }, + expeted: expected{ + authorized: authorizer.DecisionDeny, + }, + }, + { + name: "access policy identity with correct permissions should be able to authorize", + input: input{ + verb: utils.VerbGet, + info: authn.NewAccessTokenAuthInfo(authn.Claims[authn.AccessTokenClaims]{ + Claims: jwt.Claims{ + Subject: "access-policy:123", + }, + Rest: authn.AccessTokenClaims{ + Namespace: "stacks-1", + Permissions: []string{ + "folder.grafana.app/folders:get", + }, + }, + }), + client: authz.NewClient(nil), + }, + expeted: expected{ + authorized: authorizer.DecisionAllow, + }, + }, + { + name: "access policy identity without correct permissions should not be able to authorize", + input: input{ + verb: utils.VerbGet, + info: authn.NewAccessTokenAuthInfo(authn.Claims[authn.AccessTokenClaims]{ + Claims: jwt.Claims{ + Subject: "access-policy:123", + }, + Rest: authn.AccessTokenClaims{ + Namespace: "stacks-1", + Permissions: []string{ + "folder.grafana.app/folders:create", + }, + }, + }), + client: authz.NewClient(nil), + }, + expeted: expected{ + authorized: authorizer.DecisionDeny, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + authz := newMultiTenantAuthorizer(tt.input.client) + authorized, _, err := authz.Authorize( + types.WithAuthInfo(context.Background(), tt.input.info), + authorizer.AttributesRecord{User: tt.input.info, Verb: tt.input.verb, APIGroup: folderv0aplha1.GROUP, Resource: "folders", ResourceRequest: true, Name: "123", Namespace: "stacks-1"}, + ) + + if tt.expeted.err { + require.Error(t, err) + require.Equal(t, authorizer.DecisionDeny, authorized) + return + } + + require.NoError(t, err) + require.Equal(t, tt.expeted.authorized, authorized) + }) + } +} diff --git a/pkg/registry/apis/folders/register.go b/pkg/registry/apis/folders/register.go index 1ca84a49a4f..4e5e144d50e 100644 --- a/pkg/registry/apis/folders/register.go +++ b/pkg/registry/apis/folders/register.go @@ -4,9 +4,9 @@ import ( "context" "errors" "fmt" - "slices" "strings" + authtypes "github.com/grafana/authlib/types" "github.com/prometheus/client_golang/prometheus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -50,10 +50,12 @@ type FolderAPIBuilder struct { folderSvc folder.Service folderPermissionsSvc accesscontrol.FolderPermissionsService storage grafanarest.Storage - accessControl accesscontrol.AccessControl - searcher resource.ResourceIndexClient - cfg *setting.Cfg - ignoreLegacy bool // skip legacy storage and only use unified storage + + authorizer authorizer.Authorizer + + searcher resource.ResourceIndexClient + cfg *setting.Cfg + ignoreLegacy bool // skip legacy storage and only use unified storage } func RegisterAPIService(cfg *setting.Cfg, @@ -79,17 +81,18 @@ func RegisterAPIService(cfg *setting.Cfg, folderSvc: folderSvc, folderPermissionsSvc: folderPermissionsSvc, cfg: cfg, - accessControl: accessControl, + authorizer: newLegacyAuthorizer(accessControl), searcher: unified, } apiregistration.RegisterAPI(builder) return builder } -func NewAPIService() *FolderAPIBuilder { +func NewAPIService(ac authtypes.AccessClient) *FolderAPIBuilder { return &FolderAPIBuilder{ gv: resourceInfo.GroupVersion(), namespacer: request.GetNamespaceMapper(nil), + authorizer: newMultiTenantAuthorizer(ac), ignoreLegacy: true, } } @@ -201,58 +204,7 @@ type authorizerParams struct { } func (b *FolderAPIBuilder) GetAuthorizer() authorizer.Authorizer { - return authorizer.AuthorizerFunc(func(ctx context.Context, attr authorizer.Attributes) (authorizer.Decision, string, error) { - in, err := authorizerFunc(ctx, attr) - if err != nil { - if errors.Is(err, errNoUser) { - return authorizer.DecisionDeny, "", nil - } - return authorizer.DecisionNoOpinion, "", nil - } - - ok, err := b.accessControl.Evaluate(ctx, in.user, in.evaluator) - if ok { - return authorizer.DecisionAllow, "", nil - } - return authorizer.DecisionDeny, "folder", err - }) -} - -func authorizerFunc(ctx context.Context, attr authorizer.Attributes) (*authorizerParams, error) { - allowedVerbs := []string{utils.VerbCreate, utils.VerbDelete, utils.VerbList} - verb := attr.GetVerb() - name := attr.GetName() - if (!attr.IsResourceRequest()) || (name == "" && verb != utils.VerbCreate && slices.Contains(allowedVerbs, verb)) { - return nil, errNoResource - } - - // require a user - user, err := identity.GetRequester(ctx) - if err != nil { - return nil, errNoUser - } - - scope := dashboards.ScopeFoldersProvider.GetResourceScopeUID(name) - var eval accesscontrol.Evaluator - - // "get" is used for sub-resources with GET http (parents, access, count) - switch verb { - case utils.VerbCreate: - eval = accesscontrol.EvalPermission(dashboards.ActionFoldersCreate) - case utils.VerbPatch: - fallthrough - case utils.VerbUpdate: - eval = accesscontrol.EvalPermission(dashboards.ActionFoldersWrite, scope) - case utils.VerbDeleteCollection: - fallthrough - case utils.VerbDelete: - eval = accesscontrol.EvalPermission(dashboards.ActionFoldersDelete, scope) - case utils.VerbList: - eval = accesscontrol.EvalPermission(dashboards.ActionFoldersRead) - default: - eval = accesscontrol.EvalPermission(dashboards.ActionFoldersRead, scope) - } - return &authorizerParams{evaluator: eval, user: user}, nil + return b.authorizer } var folderValidationRules = struct { diff --git a/pkg/registry/apis/folders/register_test.go b/pkg/registry/apis/folders/register_test.go index 4f1aae986f7..5d80a2c2369 100644 --- a/pkg/registry/apis/folders/register_test.go +++ b/pkg/registry/apis/folders/register_test.go @@ -8,211 +8,17 @@ import ( "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apiserver/pkg/admission" - "k8s.io/apiserver/pkg/authorization/authorizer" - "github.com/grafana/grafana/pkg/apimachinery/identity" - "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/apis/folder/v0alpha1" grafanarest "github.com/grafana/grafana/pkg/apiserver/rest" "github.com/grafana/grafana/pkg/services/accesscontrol" - "github.com/grafana/grafana/pkg/services/accesscontrol/acimpl" "github.com/grafana/grafana/pkg/services/dashboards" - "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/folder/foldertest" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/storage/unified/resource" ) -func TestFolderAPIBuilder_getAuthorizerFunc(t *testing.T) { - type input struct { - user identity.Requester - verb string - } - type expect struct { - eval string - allow bool - err error - } - var orgID int64 = 1 - - tests := []struct { - name string - input input - expect expect - }{ - { - name: "user with create permissions should be able to create a folder", - input: input{ - user: &user.SignedInUser{ - UserID: 1, - OrgID: orgID, - Name: "123", - Permissions: map[int64]map[string][]string{ - orgID: {dashboards.ActionFoldersCreate: {}, dashboards.ActionFoldersWrite: {dashboards.ScopeFoldersAll}}, - }, - }, - verb: string(utils.VerbCreate), - }, - expect: expect{ - eval: "folders:create", - allow: true, - }, - }, - { - name: "not possible to create a folder without a user", - input: input{ - user: nil, - verb: string(utils.VerbCreate), - }, - expect: expect{ - eval: "folders:create", - err: errNoUser, - }, - }, - { - name: "user without permissions should not be able to create a folder", - input: input{ - user: &user.SignedInUser{}, - verb: string(utils.VerbCreate), - }, - expect: expect{ - eval: "folders:create", - }, - }, - { - name: "user in another orgId should not be able to create a folder ", - input: input{ - user: &user.SignedInUser{ - UserID: 1, - OrgID: 2, - Name: "123", - Permissions: map[int64]map[string][]string{ - orgID: {dashboards.ActionFoldersCreate: {}, dashboards.ActionFoldersWrite: {dashboards.ScopeFoldersAll}}, - }, - }, - verb: string(utils.VerbCreate), - }, - expect: expect{ - eval: "folders:create", - }, - }, - { - name: "user with read permissions should be able to list folders", - input: input{ - user: &user.SignedInUser{ - UserID: 1, - OrgID: orgID, - Name: "123", - Permissions: map[int64]map[string][]string{ - orgID: {}, - }, - }, - verb: string(utils.VerbList), - }, - expect: expect{ - eval: "folders:read", - allow: false, - }, - }, - { - name: "user with delete permissions should be able to delete a folder", - input: input{ - user: &user.SignedInUser{ - UserID: 1, - OrgID: orgID, - Name: "123", - Permissions: map[int64]map[string][]string{ - orgID: {dashboards.ActionFoldersDelete: {dashboards.ScopeFoldersAll}, dashboards.ActionFoldersWrite: {dashboards.ScopeFoldersAll}}, - }, - }, - verb: string(utils.VerbDelete), - }, - expect: expect{ - eval: "folders:delete", - allow: true, - }, - }, - { - name: "user without delete permissions should NOT be able to delete a folder", - input: input{ - user: &user.SignedInUser{ - UserID: 1, - OrgID: orgID, - Name: "123", - Permissions: map[int64]map[string][]string{ - orgID: {}, - }, - }, - verb: string(utils.VerbDelete), - }, - expect: expect{ - eval: "folders:delete", - allow: false, - }, - }, - { - name: "user with write permissions should be able to update a folder", - input: input{ - user: &user.SignedInUser{ - UserID: 1, - OrgID: orgID, - Name: "123", - Permissions: map[int64]map[string][]string{ - orgID: {dashboards.ActionFoldersWrite: {dashboards.ScopeFoldersAll}}, - }, - }, - verb: string(utils.VerbUpdate), - }, - expect: expect{ - eval: "folders:write", - allow: true, - }, - }, - { - name: "user without write permissions should NOT be able to update a folder", - input: input{ - user: &user.SignedInUser{ - UserID: 1, - OrgID: orgID, - Name: "123", - Permissions: map[int64]map[string][]string{ - orgID: {}, - }, - }, - verb: string(utils.VerbUpdate), - }, - expect: expect{ - eval: "folders:write", - allow: false, - }, - }, - } - - b := &FolderAPIBuilder{ - gv: resourceInfo.GroupVersion(), - features: nil, - namespacer: func(_ int64) string { return "123" }, - folderSvc: foldertest.NewFakeService(), - accessControl: acimpl.ProvideAccessControl(featuremgmt.WithFeatures("nestedFolders")), - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ctx := context.Background() - out, err := authorizerFunc(identity.WithRequester(ctx, tt.input.user), authorizer.AttributesRecord{User: tt.input.user, Verb: tt.input.verb, Resource: "folders", ResourceRequest: true, Name: "123"}) - if tt.expect.err != nil { - require.Error(t, err) - return - } - allow, _ := b.accessControl.Evaluate(ctx, out.user, out.evaluator) - require.NoError(t, err) - require.Equal(t, tt.expect.eval, out.evaluator.String()) - require.Equal(t, tt.expect.allow, allow) - }) - } -} - func TestFolderAPIBuilder_Validate_Create(t *testing.T) { type input struct { obj *v0alpha1.Folder @@ -294,12 +100,11 @@ func TestFolderAPIBuilder_Validate_Create(t *testing.T) { us := storageMock{m, s} b := &FolderAPIBuilder{ - gv: resourceInfo.GroupVersion(), - features: nil, - namespacer: func(_ int64) string { return "123" }, - folderSvc: foldertest.NewFakeService(), - storage: us, - accessControl: acimpl.ProvideAccessControl(featuremgmt.WithFeatures("nestedFolders")), + gv: resourceInfo.GroupVersion(), + features: nil, + namespacer: func(_ int64) string { return "123" }, + folderSvc: foldertest.NewFakeService(), + storage: us, } for _, tt := range tests { @@ -379,13 +184,12 @@ func TestFolderAPIBuilder_Validate_Delete(t *testing.T) { setupFn(m, tt.statsResponse) b := &FolderAPIBuilder{ - gv: resourceInfo.GroupVersion(), - features: nil, - namespacer: func(_ int64) string { return "123" }, - folderSvc: foldertest.NewFakeService(), - storage: us, - accessControl: acimpl.ProvideAccessControl(featuremgmt.WithFeatures("nestedFolders")), - searcher: sm, + gv: resourceInfo.GroupVersion(), + features: nil, + namespacer: func(_ int64) string { return "123" }, + folderSvc: foldertest.NewFakeService(), + storage: us, + searcher: sm, } err := b.Validate(context.Background(), admission.NewAttributesRecord( @@ -545,13 +349,12 @@ func TestFolderAPIBuilder_Validate_Update(t *testing.T) { } t.Run(tt.name, func(t *testing.T) { b := &FolderAPIBuilder{ - gv: resourceInfo.GroupVersion(), - features: nil, - namespacer: func(_ int64) string { return "123" }, - folderSvc: foldertest.NewFakeService(), - storage: us, - accessControl: acimpl.ProvideAccessControl(featuremgmt.WithFeatures("nestedFolders")), - searcher: sm, + gv: resourceInfo.GroupVersion(), + features: nil, + namespacer: func(_ int64) string { return "123" }, + folderSvc: foldertest.NewFakeService(), + storage: us, + searcher: sm, } err := b.Validate(context.Background(), admission.NewAttributesRecord( @@ -641,13 +444,12 @@ func TestFolderAPIBuilder_Mutate_Create(t *testing.T) { us := storageMock{m, s} sm := searcherMock{Mock: m} b := &FolderAPIBuilder{ - gv: resourceInfo.GroupVersion(), - features: nil, - namespacer: func(_ int64) string { return "123" }, - folderSvc: foldertest.NewFakeService(), - storage: us, - accessControl: acimpl.ProvideAccessControl(featuremgmt.WithFeatures("nestedFolders")), - searcher: sm, + gv: resourceInfo.GroupVersion(), + features: nil, + namespacer: func(_ int64) string { return "123" }, + folderSvc: foldertest.NewFakeService(), + storage: us, + searcher: sm, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -748,13 +550,12 @@ func TestFolderAPIBuilder_Mutate_Update(t *testing.T) { us := storageMock{m, s} sm := searcherMock{Mock: m} b := &FolderAPIBuilder{ - gv: resourceInfo.GroupVersion(), - features: nil, - namespacer: func(_ int64) string { return "123" }, - folderSvc: foldertest.NewFakeService(), - storage: us, - accessControl: acimpl.ProvideAccessControl(featuremgmt.WithFeatures("nestedFolders")), - searcher: sm, + gv: resourceInfo.GroupVersion(), + features: nil, + namespacer: func(_ int64) string { return "123" }, + folderSvc: foldertest.NewFakeService(), + storage: us, + searcher: sm, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From 520f46cb6d2e4b42c337f5d0a9039da37525bcdf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 28 Feb 2025 09:52:42 +0000 Subject: [PATCH 30/74] Update babel monorepo to v7.26.9 (#101447) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 6 +- packages/grafana-flamegraph/package.json | 4 +- packages/grafana-icons/package.json | 2 +- packages/grafana-ui/package.json | 2 +- yarn.lock | 220 +++++++++++------------ 5 files changed, 117 insertions(+), 117 deletions(-) diff --git a/package.json b/package.json index a07f4835a14..07870be6c31 100644 --- a/package.json +++ b/package.json @@ -71,9 +71,9 @@ "releaseNotesUrl": "https://grafana.com/docs/grafana/next/release-notes/" }, "devDependencies": { - "@babel/core": "7.26.7", - "@babel/preset-env": "7.26.7", - "@babel/runtime": "7.26.7", + "@babel/core": "7.26.9", + "@babel/preset-env": "7.26.9", + "@babel/runtime": "7.26.9", "@betterer/betterer": "5.4.0", "@betterer/cli": "5.4.0", "@cypress/webpack-preprocessor": "6.0.2", diff --git a/packages/grafana-flamegraph/package.json b/packages/grafana-flamegraph/package.json index 3eb48f5eaef..f47339c0aa0 100644 --- a/packages/grafana-flamegraph/package.json +++ b/packages/grafana-flamegraph/package.json @@ -56,8 +56,8 @@ "tslib": "2.8.1" }, "devDependencies": { - "@babel/core": "7.26.7", - "@babel/preset-env": "7.26.7", + "@babel/core": "7.26.9", + "@babel/preset-env": "7.26.9", "@babel/preset-react": "7.26.3", "@grafana/tsconfig": "^2.0.0", "@rollup/plugin-node-resolve": "16.0.0", diff --git a/packages/grafana-icons/package.json b/packages/grafana-icons/package.json index c08c70e14ed..cb60d576dd5 100644 --- a/packages/grafana-icons/package.json +++ b/packages/grafana-icons/package.json @@ -35,7 +35,7 @@ "build": "yarn generate && rollup -c rollup.config.ts --configPlugin esbuild" }, "devDependencies": { - "@babel/core": "7.26.7", + "@babel/core": "7.26.9", "@grafana/tsconfig": "^2.0.0", "@rollup/plugin-node-resolve": "^16.0.0", "@rollup/plugin-typescript": "^12.1.0", diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index 032b629d2bb..cce6ef25960 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -114,7 +114,7 @@ "uuid": "11.0.5" }, "devDependencies": { - "@babel/core": "7.26.7", + "@babel/core": "7.26.9", "@faker-js/faker": "^9.0.0", "@grafana/tsconfig": "^2.0.0", "@rollup/plugin-node-resolve": "16.0.0", diff --git a/yarn.lock b/yarn.lock index 4000b1d7385..67d212cde43 100644 --- a/yarn.lock +++ b/yarn.lock @@ -81,7 +81,7 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.3, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.16.7, @babel/code-frame@npm:^7.24.2, @babel/code-frame@npm:^7.25.9, @babel/code-frame@npm:^7.26.2": +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.3, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.16.7, @babel/code-frame@npm:^7.24.2, @babel/code-frame@npm:^7.26.2": version: 7.26.2 resolution: "@babel/code-frame@npm:7.26.2" dependencies: @@ -92,46 +92,46 @@ __metadata: languageName: node linkType: hard -"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.26.5": - version: 7.26.5 - resolution: "@babel/compat-data@npm:7.26.5" - checksum: 10/afe35751f27bda80390fa221d5e37be55b7fc42cec80de9896086e20394f2306936c4296fcb4d62b683e3b49ba2934661ea7e06196ca2dacdc2e779fbea4a1a9 +"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.26.5, @babel/compat-data@npm:^7.26.8": + version: 7.26.8 + resolution: "@babel/compat-data@npm:7.26.8" + checksum: 10/bdddf577f670e0e12996ef37e134856c8061032edb71a13418c3d4dae8135da28910b7cd6dec6e668ab3a41e42089ef7ee9c54ef52fe0860b54cb420b0d14948 languageName: node linkType: hard -"@babel/core@npm:7.26.7, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.18.9, @babel/core@npm:^7.21.3, @babel/core@npm:^7.22.9": - version: 7.26.7 - resolution: "@babel/core@npm:7.26.7" +"@babel/core@npm:7.26.9, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.18.9, @babel/core@npm:^7.21.3, @babel/core@npm:^7.22.9": + version: 7.26.9 + resolution: "@babel/core@npm:7.26.9" dependencies: "@ampproject/remapping": "npm:^2.2.0" "@babel/code-frame": "npm:^7.26.2" - "@babel/generator": "npm:^7.26.5" + "@babel/generator": "npm:^7.26.9" "@babel/helper-compilation-targets": "npm:^7.26.5" "@babel/helper-module-transforms": "npm:^7.26.0" - "@babel/helpers": "npm:^7.26.7" - "@babel/parser": "npm:^7.26.7" - "@babel/template": "npm:^7.25.9" - "@babel/traverse": "npm:^7.26.7" - "@babel/types": "npm:^7.26.7" + "@babel/helpers": "npm:^7.26.9" + "@babel/parser": "npm:^7.26.9" + "@babel/template": "npm:^7.26.9" + "@babel/traverse": "npm:^7.26.9" + "@babel/types": "npm:^7.26.9" convert-source-map: "npm:^2.0.0" debug: "npm:^4.1.0" gensync: "npm:^1.0.0-beta.2" json5: "npm:^2.2.3" semver: "npm:^6.3.1" - checksum: 10/1ca1c9b1366a1ee77ade9c72302f288b2b148e4190e0f36bc032d09c686b2c7973d3309e4eec2c57243508c16cf907c17dec4e34ba95e7a18badd57c61bbcb7c + checksum: 10/ceed199dbe25f286a0a59a2ea7879aed37c1f3bb289375d061eda4752cab2ba365e7f9e969c7fd3b9b95c930493db6eeb5a6d6f017dd135fb5a4503449aad753 languageName: node linkType: hard -"@babel/generator@npm:^7.22.9, @babel/generator@npm:^7.26.5, @babel/generator@npm:^7.7.2": - version: 7.26.5 - resolution: "@babel/generator@npm:7.26.5" +"@babel/generator@npm:^7.22.9, @babel/generator@npm:^7.26.9, @babel/generator@npm:^7.7.2": + version: 7.26.9 + resolution: "@babel/generator@npm:7.26.9" dependencies: - "@babel/parser": "npm:^7.26.5" - "@babel/types": "npm:^7.26.5" + "@babel/parser": "npm:^7.26.9" + "@babel/types": "npm:^7.26.9" "@jridgewell/gen-mapping": "npm:^0.3.5" "@jridgewell/trace-mapping": "npm:^0.3.25" jsesc: "npm:^3.0.2" - checksum: 10/aa5f176155431d1fb541ca11a7deddec0fc021f20992ced17dc2f688a0a9584e4ff4280f92e8a39302627345cd325762f70f032764806c579c6fd69432542bcb + checksum: 10/95075dd6158a49efcc71d7f2c5d20194fcf245348de7723ca35e37cd5800587f1d4de2be6c4ba87b5f5fbb967c052543c109eaab14b43f6a73eb05ccd9a5bb44 languageName: node linkType: hard @@ -187,9 +187,9 @@ __metadata: languageName: node linkType: hard -"@babel/helper-define-polyfill-provider@npm:^0.6.1, @babel/helper-define-polyfill-provider@npm:^0.6.2": - version: 0.6.2 - resolution: "@babel/helper-define-polyfill-provider@npm:0.6.2" +"@babel/helper-define-polyfill-provider@npm:^0.6.1, @babel/helper-define-polyfill-provider@npm:^0.6.3": + version: 0.6.3 + resolution: "@babel/helper-define-polyfill-provider@npm:0.6.3" dependencies: "@babel/helper-compilation-targets": "npm:^7.22.6" "@babel/helper-plugin-utils": "npm:^7.22.5" @@ -198,7 +198,7 @@ __metadata: resolve: "npm:^1.14.2" peerDependencies: "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 - checksum: 10/bb32ec12024d3f16e70641bc125d2534a97edbfdabbc9f69001ec9c4ce46f877c7a224c566aa6c8c510c3b0def2e43dc4433bf6a40896ba5ce0cef4ea5ccbcff + checksum: 10/b79a77ac8fbf1aaf6c7f99191871760508e87d75a374ff3c39c6599a17d9bb82284797cd451769305764e504546caf22ae63367b22d6e45e32d0a8f4a34aab53 languageName: node linkType: hard @@ -329,13 +329,13 @@ __metadata: languageName: node linkType: hard -"@babel/helpers@npm:^7.26.7": - version: 7.26.7 - resolution: "@babel/helpers@npm:7.26.7" +"@babel/helpers@npm:^7.26.9": + version: 7.26.9 + resolution: "@babel/helpers@npm:7.26.9" dependencies: - "@babel/template": "npm:^7.25.9" - "@babel/types": "npm:^7.26.7" - checksum: 10/97593a0c9b3c5e2e7cf824e549b5f6fa6dc739593ad93d5bb36d06883d8124beac63ee2154c9a514dbee68a169d5683ab463e0ac6713ad92fb4854cea35ed4d4 + "@babel/template": "npm:^7.26.9" + "@babel/types": "npm:^7.26.9" + checksum: 10/267dfa7d04dff7720610497f466aa7b60652b7ec8dde5914527879350c9d655271e892117c5b2f0f083d92d2a8e5e2cf9832d4f98cd7fb72d78f796002af19a1 languageName: node linkType: hard @@ -351,14 +351,14 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.25.9, @babel/parser@npm:^7.26.5, @babel/parser@npm:^7.26.7": - version: 7.26.7 - resolution: "@babel/parser@npm:7.26.7" +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.26.9": + version: 7.26.9 + resolution: "@babel/parser@npm:7.26.9" dependencies: - "@babel/types": "npm:^7.26.7" + "@babel/types": "npm:^7.26.9" bin: parser: ./bin/babel-parser.js - checksum: 10/3ccc384366ca9a9b49c54f5b24c9d8cff9a505f2fbdd1cfc04941c8e1897084cc32f100e77900c12bc14a176cf88daa3c155faad680d9a23491b997fd2a59ffc + checksum: 10/cb84fe3ba556d6a4360f3373cf7eb0901c46608c8d77330cc1ca021d60f5d6ebb4056a8e7f9dd0ef231923ef1fe69c87b11ce9e160d2252e089a20232a2b942b languageName: node linkType: hard @@ -663,16 +663,16 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-async-generator-functions@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-async-generator-functions@npm:7.25.9" +"@babel/plugin-transform-async-generator-functions@npm:^7.26.8": + version: 7.26.8 + resolution: "@babel/plugin-transform-async-generator-functions@npm:7.26.8" dependencies: - "@babel/helper-plugin-utils": "npm:^7.25.9" + "@babel/helper-plugin-utils": "npm:^7.26.5" "@babel/helper-remap-async-to-generator": "npm:^7.25.9" - "@babel/traverse": "npm:^7.25.9" + "@babel/traverse": "npm:^7.26.8" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10/99306c44a4a791abd51a56d89fa61c4cfe805a58e070c7fb1cbf950886778a6c8c4f25a92d231f91da1746d14a338436073fd83038e607f03a2a98ac5340406b + checksum: 10/8fb43823f56281b041dbd358de4f59fccb3e20aac133a439caaeb5aaa30671b3482da9a8515b169fef108148e937c1248b7d6383979c3b30f9348e3fabd29b8e languageName: node linkType: hard @@ -842,15 +842,15 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-for-of@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-for-of@npm:7.25.9" +"@babel/plugin-transform-for-of@npm:^7.26.9": + version: 7.26.9 + resolution: "@babel/plugin-transform-for-of@npm:7.26.9" dependencies: - "@babel/helper-plugin-utils": "npm:^7.25.9" + "@babel/helper-plugin-utils": "npm:^7.26.5" "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.25.9" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10/63a2db7fe06c2e3f5fc1926f478dac66a5f7b3eaeb4a0ffae577e6f3cb3d822cb1ed2ed3798f70f5cb1aa06bc2ad8bcd1f557342f5c425fd83c37a8fc1cfd2ba + checksum: 10/25df1ea3bcecc1bcef99f273fbd8f4a73a509ab7ef3db93629817cb02f9d24868ca3760347f864c8fa4ab79ffa86fb09b2f2de1f2ba1f73f27dbe0c3973c6868 languageName: node linkType: hard @@ -1219,14 +1219,14 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-template-literals@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-template-literals@npm:7.25.9" +"@babel/plugin-transform-template-literals@npm:^7.26.8": + version: 7.26.8 + resolution: "@babel/plugin-transform-template-literals@npm:7.26.8" dependencies: - "@babel/helper-plugin-utils": "npm:^7.25.9" + "@babel/helper-plugin-utils": "npm:^7.26.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10/92eb1d6e2d95bd24abbb74fa7640d02b66ff6214e0bb616d7fda298a7821ce15132a4265d576a3502a347a3c9e94b6c69ed265bb0784664592fa076785a3d16a + checksum: 10/65874c8844ce906507cd5b9c78950d6173f8339b6416a2a9e763021db5a7045315a6f0e58976ec4af5e960c003ef322576c105130a644addb8f94d1a0821a972 languageName: node linkType: hard @@ -1298,11 +1298,11 @@ __metadata: languageName: node linkType: hard -"@babel/preset-env@npm:7.26.7": - version: 7.26.7 - resolution: "@babel/preset-env@npm:7.26.7" +"@babel/preset-env@npm:7.26.9": + version: 7.26.9 + resolution: "@babel/preset-env@npm:7.26.9" dependencies: - "@babel/compat-data": "npm:^7.26.5" + "@babel/compat-data": "npm:^7.26.8" "@babel/helper-compilation-targets": "npm:^7.26.5" "@babel/helper-plugin-utils": "npm:^7.26.5" "@babel/helper-validator-option": "npm:^7.25.9" @@ -1316,7 +1316,7 @@ __metadata: "@babel/plugin-syntax-import-attributes": "npm:^7.26.0" "@babel/plugin-syntax-unicode-sets-regex": "npm:^7.18.6" "@babel/plugin-transform-arrow-functions": "npm:^7.25.9" - "@babel/plugin-transform-async-generator-functions": "npm:^7.25.9" + "@babel/plugin-transform-async-generator-functions": "npm:^7.26.8" "@babel/plugin-transform-async-to-generator": "npm:^7.25.9" "@babel/plugin-transform-block-scoped-functions": "npm:^7.26.5" "@babel/plugin-transform-block-scoping": "npm:^7.25.9" @@ -1331,7 +1331,7 @@ __metadata: "@babel/plugin-transform-dynamic-import": "npm:^7.25.9" "@babel/plugin-transform-exponentiation-operator": "npm:^7.26.3" "@babel/plugin-transform-export-namespace-from": "npm:^7.25.9" - "@babel/plugin-transform-for-of": "npm:^7.25.9" + "@babel/plugin-transform-for-of": "npm:^7.26.9" "@babel/plugin-transform-function-name": "npm:^7.25.9" "@babel/plugin-transform-json-strings": "npm:^7.25.9" "@babel/plugin-transform-literals": "npm:^7.25.9" @@ -1359,7 +1359,7 @@ __metadata: "@babel/plugin-transform-shorthand-properties": "npm:^7.25.9" "@babel/plugin-transform-spread": "npm:^7.25.9" "@babel/plugin-transform-sticky-regex": "npm:^7.25.9" - "@babel/plugin-transform-template-literals": "npm:^7.25.9" + "@babel/plugin-transform-template-literals": "npm:^7.26.8" "@babel/plugin-transform-typeof-symbol": "npm:^7.26.7" "@babel/plugin-transform-unicode-escapes": "npm:^7.25.9" "@babel/plugin-transform-unicode-property-regex": "npm:^7.25.9" @@ -1367,13 +1367,13 @@ __metadata: "@babel/plugin-transform-unicode-sets-regex": "npm:^7.25.9" "@babel/preset-modules": "npm:0.1.6-no-external-plugins" babel-plugin-polyfill-corejs2: "npm:^0.4.10" - babel-plugin-polyfill-corejs3: "npm:^0.10.6" + babel-plugin-polyfill-corejs3: "npm:^0.11.0" babel-plugin-polyfill-regenerator: "npm:^0.6.1" - core-js-compat: "npm:^3.38.1" + core-js-compat: "npm:^3.40.0" semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10/d5833ac61580ca8ca672466d06edcf523b49f400caa8f4b8f21358a30875a8ca1628a250b89369e8a0be3439f6ae0002af6f64335794b06acaf603906055f43a + checksum: 10/ac6fad331760c0bc25ed428b7696b297bad7046a75f30e544b392acfb33709f12316b9a5b0c8606f933d5756e1b9d527b46fda09693db52e851325443dd6a574 languageName: node linkType: hard @@ -1416,48 +1416,48 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:7.26.7, @babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.11.1, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.14.0, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.0, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.0, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.9, @babel/runtime@npm:^7.24.1, @babel/runtime@npm:^7.24.5, @babel/runtime@npm:^7.24.7, @babel/runtime@npm:^7.25.0, @babel/runtime@npm:^7.25.6, @babel/runtime@npm:^7.25.7, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7": - version: 7.26.7 - resolution: "@babel/runtime@npm:7.26.7" +"@babel/runtime@npm:7.26.9, @babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.11.1, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.14.0, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.0, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.0, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.9, @babel/runtime@npm:^7.24.1, @babel/runtime@npm:^7.24.5, @babel/runtime@npm:^7.24.7, @babel/runtime@npm:^7.25.0, @babel/runtime@npm:^7.25.6, @babel/runtime@npm:^7.25.7, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7": + version: 7.26.9 + resolution: "@babel/runtime@npm:7.26.9" dependencies: regenerator-runtime: "npm:^0.14.0" - checksum: 10/c7a661a6836b332d9d2e047cba77ba1862c1e4f78cec7146db45808182ef7636d8a7170be9797e5d8fd513180bffb9fa16f6ca1c69341891efec56113cf22bfc + checksum: 10/08edd07d774eafbf157fdc8450ed6ddd22416fdd8e2a53e4a00349daba1b502c03ab7f7ad3ad3a7c46b9a24d99b5697591d0f852ee2f84642082ef7dda90b83d languageName: node linkType: hard -"@babel/template@npm:^7.22.5, @babel/template@npm:^7.24.7, @babel/template@npm:^7.25.9, @babel/template@npm:^7.3.3": - version: 7.25.9 - resolution: "@babel/template@npm:7.25.9" - dependencies: - "@babel/code-frame": "npm:^7.25.9" - "@babel/parser": "npm:^7.25.9" - "@babel/types": "npm:^7.25.9" - checksum: 10/e861180881507210150c1335ad94aff80fd9e9be6202e1efa752059c93224e2d5310186ddcdd4c0f0b0fc658ce48cb47823f15142b5c00c8456dde54f5de80b2 - languageName: node - linkType: hard - -"@babel/traverse@npm:^7.18.9, @babel/traverse@npm:^7.22.8, @babel/traverse@npm:^7.25.9, @babel/traverse@npm:^7.26.7": - version: 7.26.7 - resolution: "@babel/traverse@npm:7.26.7" +"@babel/template@npm:^7.22.5, @babel/template@npm:^7.24.7, @babel/template@npm:^7.25.9, @babel/template@npm:^7.26.9, @babel/template@npm:^7.3.3": + version: 7.26.9 + resolution: "@babel/template@npm:7.26.9" dependencies: "@babel/code-frame": "npm:^7.26.2" - "@babel/generator": "npm:^7.26.5" - "@babel/parser": "npm:^7.26.7" - "@babel/template": "npm:^7.25.9" - "@babel/types": "npm:^7.26.7" - debug: "npm:^4.3.1" - globals: "npm:^11.1.0" - checksum: 10/c821c9682fe0b9edf7f7cbe9cc3e0787ffee3f73b52c13b21b463f8979950a6433f5e7e482a74348d22c0b7a05180e6f72b23eb6732328b49c59fc6388ebf6e5 + "@babel/parser": "npm:^7.26.9" + "@babel/types": "npm:^7.26.9" + checksum: 10/240288cebac95b1cc1cb045ad143365643da0470e905e11731e63280e43480785bd259924f4aea83898ef68e9fa7c176f5f2d1e8b0a059b27966e8ca0b41a1b6 languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.18.9, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.3, @babel/types@npm:^7.22.5, @babel/types@npm:^7.24.7, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.5, @babel/types@npm:^7.26.7, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4": - version: 7.26.7 - resolution: "@babel/types@npm:7.26.7" +"@babel/traverse@npm:^7.18.9, @babel/traverse@npm:^7.22.8, @babel/traverse@npm:^7.25.9, @babel/traverse@npm:^7.26.8, @babel/traverse@npm:^7.26.9": + version: 7.26.9 + resolution: "@babel/traverse@npm:7.26.9" + dependencies: + "@babel/code-frame": "npm:^7.26.2" + "@babel/generator": "npm:^7.26.9" + "@babel/parser": "npm:^7.26.9" + "@babel/template": "npm:^7.26.9" + "@babel/types": "npm:^7.26.9" + debug: "npm:^4.3.1" + globals: "npm:^11.1.0" + checksum: 10/c16a79522eafa0a7e40eb556bf1e8a3d50dbb0ff943a80f2c06cee2ec7ff87baa0c5d040a5cff574d9bcb3bed05e7d8c6f13b238a931c97267674b02c6cf45b4 + languageName: node + linkType: hard + +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.18.9, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.3, @babel/types@npm:^7.22.5, @babel/types@npm:^7.24.7, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.9, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4": + version: 7.26.9 + resolution: "@babel/types@npm:7.26.9" dependencies: "@babel/helper-string-parser": "npm:^7.25.9" "@babel/helper-validator-identifier": "npm:^7.25.9" - checksum: 10/2264efd02cc261ca5d1c5bc94497c8995238f28afd2b7483b24ea64dd694cf46b00d51815bf0c87f0d0061ea221569c77893aeecb0d4b4bb254e9c2f938d7669 + checksum: 10/11b62ea7ed64ef7e39cc9b33852c1084064c3b970ae0eaa5db659241cfb776577d1e68cbff4de438bada885d3a827b52cc0f3746112d8e1bc672bb99a8eb5b56 languageName: node linkType: hard @@ -3195,8 +3195,8 @@ __metadata: version: 0.0.0-use.local resolution: "@grafana/flamegraph@workspace:packages/grafana-flamegraph" dependencies: - "@babel/core": "npm:7.26.7" - "@babel/preset-env": "npm:7.26.7" + "@babel/core": "npm:7.26.9" + "@babel/preset-env": "npm:7.26.9" "@babel/preset-react": "npm:7.26.3" "@emotion/css": "npm:11.13.5" "@grafana/data": "npm:11.6.0-pre" @@ -3566,7 +3566,7 @@ __metadata: version: 0.0.0-use.local resolution: "@grafana/saga-icons@workspace:packages/grafana-icons" dependencies: - "@babel/core": "npm:7.26.7" + "@babel/core": "npm:7.26.9" "@grafana/tsconfig": "npm:^2.0.0" "@rollup/plugin-node-resolve": "npm:^16.0.0" "@rollup/plugin-typescript": "npm:^12.1.0" @@ -3800,7 +3800,7 @@ __metadata: version: 0.0.0-use.local resolution: "@grafana/ui@workspace:packages/grafana-ui" dependencies: - "@babel/core": "npm:7.26.7" + "@babel/core": "npm:7.26.9" "@emotion/css": "npm:11.13.5" "@emotion/react": "npm:11.14.0" "@emotion/serialize": "npm:1.3.3" @@ -12151,15 +12151,15 @@ __metadata: languageName: node linkType: hard -"babel-plugin-polyfill-corejs3@npm:^0.10.6": - version: 0.10.6 - resolution: "babel-plugin-polyfill-corejs3@npm:0.10.6" +"babel-plugin-polyfill-corejs3@npm:^0.11.0": + version: 0.11.1 + resolution: "babel-plugin-polyfill-corejs3@npm:0.11.1" dependencies: - "@babel/helper-define-polyfill-provider": "npm:^0.6.2" - core-js-compat: "npm:^3.38.0" + "@babel/helper-define-polyfill-provider": "npm:^0.6.3" + core-js-compat: "npm:^3.40.0" peerDependencies: "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 - checksum: 10/360ac9054a57a18c540059dc627ad5d84d15f79790cb3d84d19a02eec7188c67d08a07db789c3822d6f5df22d918e296d1f27c4055fec2e287d328f09ea8a78a + checksum: 10/19a2978ee3462cc3b98e7d36e6537bf9fb1fb61f42fd96cb41e9313f2ac6f2c62380d94064366431eff537f342184720fe9bce73eb65fd57c5311d15e8648f62 languageName: node linkType: hard @@ -12529,7 +12529,7 @@ __metadata: languageName: node linkType: hard -"browserslist@npm:^4.0.0, browserslist@npm:^4.21.10, browserslist@npm:^4.21.4, browserslist@npm:^4.23.3, browserslist@npm:^4.24.0": +"browserslist@npm:^4.0.0, browserslist@npm:^4.21.10, browserslist@npm:^4.21.4, browserslist@npm:^4.23.3, browserslist@npm:^4.24.0, browserslist@npm:^4.24.3": version: 4.24.4 resolution: "browserslist@npm:4.24.4" dependencies: @@ -13819,12 +13819,12 @@ __metadata: languageName: node linkType: hard -"core-js-compat@npm:^3.38.0, core-js-compat@npm:^3.38.1": - version: 3.38.1 - resolution: "core-js-compat@npm:3.38.1" +"core-js-compat@npm:^3.38.1, core-js-compat@npm:^3.40.0": + version: 3.40.0 + resolution: "core-js-compat@npm:3.40.0" dependencies: - browserslist: "npm:^4.23.3" - checksum: 10/4e2f219354fd268895f79486461a12df96f24ed307321482fe2a43529c5a64e7c16bcba654980ba217d603444f5141d43a79058aeac77511085f065c5da72207 + browserslist: "npm:^4.24.3" + checksum: 10/3dd3d717b3d4ae0d9c2930d39c0f2a21ca6f195fcdd5711bda833557996c4d9f90277eab576423478e95689257e2de8d1a2623d6618084416bd224d10d5df9a4 languageName: node linkType: hard @@ -18091,9 +18091,9 @@ __metadata: version: 0.0.0-use.local resolution: "grafana@workspace:." dependencies: - "@babel/core": "npm:7.26.7" - "@babel/preset-env": "npm:7.26.7" - "@babel/runtime": "npm:7.26.7" + "@babel/core": "npm:7.26.9" + "@babel/preset-env": "npm:7.26.9" + "@babel/runtime": "npm:7.26.9" "@betterer/betterer": "npm:5.4.0" "@betterer/cli": "npm:5.4.0" "@bsull/augurs": "npm:^0.9.0" From c6c5f44eeb76a38e599ac6807c5f27bcd00733ff Mon Sep 17 00:00:00 2001 From: Victor Marin <36818606+mdvictor@users.noreply.github.com> Date: Fri, 28 Feb 2025 12:15:25 +0200 Subject: [PATCH 31/74] Remove menuShouldBlockScroll react-select flag (#101450) revert 100950 --- packages/grafana-ui/src/components/Select/SelectBase.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grafana-ui/src/components/Select/SelectBase.tsx b/packages/grafana-ui/src/components/Select/SelectBase.tsx index 75c2b10681a..6a173554360 100644 --- a/packages/grafana-ui/src/components/Select/SelectBase.tsx +++ b/packages/grafana-ui/src/components/Select/SelectBase.tsx @@ -255,6 +255,7 @@ export function SelectBase({ menuIsOpen: isOpen, menuPlacement: menuPlacement === 'auto' && closeToBottom ? 'top' : menuPlacement, menuPosition, + menuShouldBlockScroll: true, menuPortalTarget: menuShouldPortal && typeof document !== 'undefined' ? document.body : undefined, menuShouldScrollIntoView: false, onBlur, From ae2074ef55d20954f32b1662fe1778d833c6d332 Mon Sep 17 00:00:00 2001 From: Alexander Akhmetov Date: Fri, 28 Feb 2025 12:11:49 +0100 Subject: [PATCH 32/74] Alerting: Fix updating Prometheus definition in the metadata (#101440) Initially, Metadata had only the EditorSettings, and HasMetadata was used to understand if the incoming update request had metadata in the body because it could be omitted if it was empty. For example, when the rule is updated via the provisioning API or has only false values. If it was in the request, we used that; if not, we used the metadata from the existing rule from the database. If the rule was updated via the AlertRuleService, we didn't change Metadata at all if the rule already existed. But now, Metadata also has the Prometheus rule definition, and we always need to update it with the new version of the AlertRuleService when the rule exists in the DB and has the same UID. HasMetadata is renamed to HasEditorSettings to keep the old behaviour only for EditorSettings. Now, the provisioning API and the conversion API will overwrite everything except EditorSettings with the new data. --- .../ngalert/api/api_ruler_validation.go | 6 +- pkg/services/ngalert/models/alert_rule.go | 19 ++- .../ngalert/models/alert_rule_test.go | 2 +- .../ngalert/provisioning/alert_rules_test.go | 125 ++++++++++++++++++ pkg/services/ngalert/store/deltas_test.go | 4 +- .../alerting/api_convert_prometheus_test.go | 88 ++++++++++++ 6 files changed, 227 insertions(+), 17 deletions(-) diff --git a/pkg/services/ngalert/api/api_ruler_validation.go b/pkg/services/ngalert/api/api_ruler_validation.go index 1ed855378fd..672873fa040 100644 --- a/pkg/services/ngalert/api/api_ruler_validation.go +++ b/pkg/services/ngalert/api/api_ruler_validation.go @@ -314,7 +314,7 @@ func ValidateRuleGroup( uids[rule.UID] = idx } - var hasPause, isPaused, hasMetadata bool + var hasPause, isPaused, hasEditorSettings bool original := ruleGroupConfig.Rules[idx] if alert := original.GrafanaManagedAlert; alert != nil { if alert.IsPaused != nil { @@ -322,7 +322,7 @@ func ValidateRuleGroup( hasPause = true } if alert.Metadata != nil { - hasMetadata = true + hasEditorSettings = true } } @@ -331,7 +331,7 @@ func ValidateRuleGroup( rule.RuleGroupIndex = idx + 1 ruleWithOptionals.AlertRule = *rule ruleWithOptionals.HasPause = hasPause - ruleWithOptionals.HasMetadata = hasMetadata + ruleWithOptionals.HasEditorSettings = hasEditorSettings result = append(result, &ruleWithOptionals) } diff --git a/pkg/services/ngalert/models/alert_rule.go b/pkg/services/ngalert/models/alert_rule.go index bef50b1b4e7..cdbc2a35b20 100644 --- a/pkg/services/ngalert/models/alert_rule.go +++ b/pkg/services/ngalert/models/alert_rule.go @@ -327,8 +327,8 @@ type AlertRuleWithOptionals struct { AlertRule // This parameter is to know if an optional API field was sent and, therefore, patch it with the current field from // DB in case it was not sent. - HasPause bool - HasMetadata bool + HasPause bool + HasEditorSettings bool } // AlertsRulesBy is a function that defines the ordering of alert rules. @@ -902,9 +902,10 @@ func (c Condition) IsValid() bool { // PatchPartialAlertRule patches `ruleToPatch` by `existingRule` following the rule that if a field of `ruleToPatch` is empty or has the default value, it is populated by the value of the corresponding field from `existingRule`. // There are several exceptions: -// 1. Following fields are not patched and therefore will be ignored: AlertRule.ID, AlertRule.OrgID, AlertRule.Updated, AlertRule.Version, AlertRule.UID, AlertRule.DashboardUID, AlertRule.PanelID, AlertRule.Annotations and AlertRule.Labels -// 2. There are fields that are patched together: -// - AlertRule.Condition and AlertRule.Data +// 1. Following fields are not patched and therefore will be ignored: AlertRule.ID, AlertRule.OrgID, AlertRule.Updated, AlertRule.Version, +// AlertRule.UID, AlertRule.DashboardUID, AlertRule.PanelID, AlertRule.Annotations, AlertRule.Labels, AlertRule.Metadata (except for EditorSettings) +// 2. There are fields that are patched together: +// - AlertRule.Condition and AlertRule.Data // // If either of the pair is specified, neither is patched. func PatchPartialAlertRule(existingRule *AlertRule, ruleToPatch *AlertRuleWithOptionals) { @@ -936,12 +937,8 @@ func PatchPartialAlertRule(existingRule *AlertRule, ruleToPatch *AlertRuleWithOp if !ruleToPatch.HasPause { ruleToPatch.IsPaused = existingRule.IsPaused } - - // Currently metadata contains only editor settings, so we can just copy it. - // If we add more fields to metadata, we might need to handle them separately, - // and/or merge or update their values. - if !ruleToPatch.HasMetadata { - ruleToPatch.Metadata = existingRule.Metadata + if !ruleToPatch.HasEditorSettings { + ruleToPatch.Metadata.EditorSettings = existingRule.Metadata.EditorSettings } } diff --git a/pkg/services/ngalert/models/alert_rule_test.go b/pkg/services/ngalert/models/alert_rule_test.go index 9f6c8b52b96..84cbed48175 100644 --- a/pkg/services/ngalert/models/alert_rule_test.go +++ b/pkg/services/ngalert/models/alert_rule_test.go @@ -263,7 +263,7 @@ func TestPatchPartialAlertRule(t *testing.T) { name: "No metadata", mutator: func(r *AlertRuleWithOptionals) { r.Metadata = AlertRuleMetadata{} - r.HasMetadata = false + r.HasEditorSettings = false }, }, } diff --git a/pkg/services/ngalert/provisioning/alert_rules_test.go b/pkg/services/ngalert/provisioning/alert_rules_test.go index c269a92c664..491d084c096 100644 --- a/pkg/services/ngalert/provisioning/alert_rules_test.go +++ b/pkg/services/ngalert/provisioning/alert_rules_test.go @@ -229,6 +229,97 @@ func TestAlertRuleService(t *testing.T) { require.Equal(t, ruleMetadata, readGroup.Rules[0].Metadata) }) + t.Run("updating a group with editor settings should override its prometheus rule definition", func(t *testing.T) { + namespaceUID := "my-namespace" + groupTitle := "test-group-123" + + // create the rule group via the rule store, to persist the editor settings + rule := createTestRule(util.GenerateShortUID(), groupTitle, orgID, namespaceUID) + ruleMetadata := models.AlertRuleMetadata{ + EditorSettings: models.EditorSettings{ + SimplifiedQueryAndExpressionsSection: true, + }, + PrometheusStyleRule: &models.PrometheusStyleRule{ + OriginalRuleDefinition: "old", + }, + } + rule.Metadata = ruleMetadata + r, err := ruleService.ruleStore.InsertAlertRules(context.Background(), models.NewUserUID(u), []models.AlertRule{rule}) + require.NoError(t, err) + require.Len(t, r, 1) + + // Set the UID for the rule to update it + rule.UID = r[0].UID + // clear the editor settings in the metadata to check that the existing setting is not overridden + rule.Metadata = models.AlertRuleMetadata{ + PrometheusStyleRule: &models.PrometheusStyleRule{ + OriginalRuleDefinition: "new", + }, + } + + // Now update the rule group with the rule to update its metadata + group := models.AlertRuleGroup{ + Title: groupTitle, + Interval: 60, + FolderUID: namespaceUID, + Rules: []models.AlertRule{rule}, + } + + err = ruleService.ReplaceRuleGroup(context.Background(), u, group, models.ProvenanceAPI) + require.NoError(t, err) + + readGroup, err := ruleService.GetRuleGroup(context.Background(), u, namespaceUID, groupTitle) + require.NoError(t, err) + require.NotEmpty(t, readGroup.Rules) + require.Len(t, readGroup.Rules, 1) + + // check that the editor settings are still there + require.True(t, readGroup.Rules[0].Metadata.EditorSettings.SimplifiedQueryAndExpressionsSection) + // check the new prometheus rule definition + require.Equal(t, "new", readGroup.Rules[0].Metadata.PrometheusStyleRule.OriginalRuleDefinition) + }) + + t.Run("updating a group should override its prometheus rule definition", func(t *testing.T) { + namespaceUID := "my-namespace" + groupTitle := "test-group-123" + + // create the rule group via the rule store, to persist the editor settings + rule := createTestRule(util.GenerateShortUID(), groupTitle, orgID, namespaceUID) + ruleMetadata := models.AlertRuleMetadata{ + PrometheusStyleRule: &models.PrometheusStyleRule{ + OriginalRuleDefinition: "old", + }, + } + rule.Metadata = ruleMetadata + r, err := ruleService.ruleStore.InsertAlertRules(context.Background(), models.NewUserUID(u), []models.AlertRule{rule}) + require.NoError(t, err) + require.Len(t, r, 1) + + // Set the UID for the rule to update it + rule.UID = r[0].UID + // make the metadata empty + rule.Metadata = models.AlertRuleMetadata{} + + // Now update the rule group with the rule to update its metadata + group := models.AlertRuleGroup{ + Title: groupTitle, + Interval: 60, + FolderUID: namespaceUID, + Rules: []models.AlertRule{rule}, + } + + err = ruleService.ReplaceRuleGroup(context.Background(), u, group, models.ProvenanceAPI) + require.NoError(t, err) + + readGroup, err := ruleService.GetRuleGroup(context.Background(), u, namespaceUID, groupTitle) + require.NoError(t, err) + require.NotEmpty(t, readGroup.Rules) + require.Len(t, readGroup.Rules, 1) + + // check that the prometheus rule definition is empty + require.Nil(t, readGroup.Rules[0].Metadata.PrometheusStyleRule) + }) + t.Run("updating a rule should not override its editor settings", func(t *testing.T) { rule := createTestRule(util.GenerateShortUID(), "my-group", orgID, "my-folder") ruleMetadata := models.AlertRuleMetadata{ @@ -1508,6 +1599,40 @@ func TestReplaceGroup(t *testing.T) { require.Len(t, updates, 1) }) }) + + t.Run("alert rule metadata should be updated correctly", func(t *testing.T) { + service, _, _, _ := initServiceWithData(t) + + rule := dummyRule("test#3", orgID) + // the rule must have a UID to be updated, otherwise it will be created as new + // and the previous version will be deleted + rule.UID = util.GenerateShortUID() + rule.Metadata = models.AlertRuleMetadata{ + EditorSettings: models.EditorSettings{ + SimplifiedQueryAndExpressionsSection: true, + }, + PrometheusStyleRule: &models.PrometheusStyleRule{ + OriginalRuleDefinition: "old", + }, + } + group := models.AlertRuleGroup{ + Title: rule.RuleGroup, + Interval: rule.IntervalSeconds, + FolderUID: rule.NamespaceUID, + Rules: []models.AlertRule{rule}, + } + + err := service.ReplaceRuleGroup(context.Background(), u, group, models.ProvenanceNone) + require.NoError(t, err) + + rule.Metadata.PrometheusStyleRule.OriginalRuleDefinition = "new" + err = service.ReplaceRuleGroup(context.Background(), u, group, models.ProvenanceNone) + require.NoError(t, err) + + rule, _, err = service.GetAlertRule(context.Background(), u, rule.UID) + require.NoError(t, err) + require.Equal(t, "new", rule.Metadata.PrometheusStyleRule.OriginalRuleDefinition) + }) } func TestDeleteRuleGroup(t *testing.T) { diff --git a/pkg/services/ngalert/store/deltas_test.go b/pkg/services/ngalert/store/deltas_test.go index fc27fbe9af2..7381df4397a 100644 --- a/pkg/services/ngalert/store/deltas_test.go +++ b/pkg/services/ngalert/store/deltas_test.go @@ -81,7 +81,7 @@ func TestCalculateChanges(t *testing.T) { submittedMap := groupByUID(t, rules) submitted := make([]*models.AlertRuleWithOptionals, 0, len(rules)) for _, rule := range rules { - submitted = append(submitted, &models.AlertRuleWithOptionals{AlertRule: *rule, HasMetadata: true}) + submitted = append(submitted, &models.AlertRuleWithOptionals{AlertRule: *rule, HasEditorSettings: true}) } fakeStore := fakes.NewRuleStore(t) @@ -216,7 +216,7 @@ func TestCalculateChanges(t *testing.T) { submittedMap := groupByUID(t, rules) submitted := make([]*models.AlertRuleWithOptionals, 0, len(rules)) for _, rule := range rules { - submitted = append(submitted, &models.AlertRuleWithOptionals{AlertRule: *rule, HasMetadata: true}) + submitted = append(submitted, &models.AlertRuleWithOptionals{AlertRule: *rule, HasEditorSettings: true}) } changes, err := CalculateChanges(context.Background(), fakeStore, groupKey, submitted) diff --git a/pkg/tests/api/alerting/api_convert_prometheus_test.go b/pkg/tests/api/alerting/api_convert_prometheus_test.go index cb248fba7f3..780e11a1d15 100644 --- a/pkg/tests/api/alerting/api_convert_prometheus_test.go +++ b/pkg/tests/api/alerting/api_convert_prometheus_test.go @@ -213,6 +213,94 @@ func TestIntegrationConvertPrometheusEndpoints(t *testing.T) { }) } +func TestIntegrationConvertPrometheusEndpoints_UpdateRule(t *testing.T) { + runTest := func(t *testing.T, enableLokiPaths bool) { + testinfra.SQLiteIntegrationTest(t) + + // Setup Grafana and its Database + dir, gpath := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ + DisableLegacyAlerting: true, + EnableUnifiedAlerting: true, + DisableAnonymous: true, + AppModeProduction: true, + EnableFeatureToggles: []string{"alertingConversionAPI"}, + }) + + grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, gpath) + + // Create a user to make authenticated requests + createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ + DefaultOrgRole: string(org.RoleAdmin), + Password: "password", + Login: "admin", + }) + apiClient := newAlertingApiClient(grafanaListedAddr, "admin", "password") + apiClient.prometheusConversionUseLokiPaths = enableLokiPaths + + createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ + DefaultOrgRole: string(org.RoleViewer), + Password: "password", + Login: "viewer", + }) + + namespace1 := "test-namespace-1" + + ds := apiClient.CreateDatasource(t, datasources.DS_PROMETHEUS) + + promGroup := apimodels.PrometheusRuleGroup{ + Name: "test-group-for-an-update", + Interval: prommodel.Duration(60 * time.Second), + Rules: []apimodels.PrometheusRule{ + { + Alert: "HighDiskUsage", + Expr: "disk_usage > 80", + For: util.Pointer(prommodel.Duration(1 * time.Minute)), + Labels: map[string]string{ + "severity": "low", + "team": "alerting", + }, + Annotations: map[string]string{ + "annotation-5": "value-5", + }, + }, + }, + } + + t.Run("update a rule", func(t *testing.T) { + // Create the rule group + _, status, body := apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup, nil) + requireStatusCode(t, http.StatusAccepted, status, body) + + // Now get the group + group1 := apiClient.ConvertPrometheusGetRuleGroupRules(t, namespace1, promGroup.Name) + require.Equal(t, promGroup, group1) + + // Update the rule group interval + promGroup.Interval = prommodel.Duration(30 * time.Second) + // Update the query + promGroup.Rules[0].Expr = "disk_usage > 90" + // Labels, and annotations too + promGroup.Rules[0].Labels["another-label"] = "something" + promGroup.Rules[0].Annotations["another-annotation"] = "also-something" + // Update the group + _, status, body = apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup, nil) + requireStatusCode(t, http.StatusAccepted, status, body) + + // Now get the group again and check that the rule group has been updated + group1 = apiClient.ConvertPrometheusGetRuleGroupRules(t, namespace1, promGroup.Name) + require.Equal(t, promGroup, group1) + }) + } + + t.Run("with the mimirtool paths", func(t *testing.T) { + runTest(t, false) + }) + + t.Run("with the cortextool Loki paths", func(t *testing.T) { + runTest(t, true) + }) +} + func TestIntegrationConvertPrometheusEndpoints_Conflict(t *testing.T) { runTest := func(t *testing.T, enableLokiPaths bool) { testinfra.SQLiteIntegrationTest(t) From e73b78a13439ba81047e938f07fc3cba28d34236 Mon Sep 17 00:00:00 2001 From: Sonia Aguilar <33540275+soniaAguilarPeiron@users.noreply.github.com> Date: Fri, 28 Feb 2025 12:14:23 +0100 Subject: [PATCH 33/74] Alerting: Rule history restore feature (#100609) * Restore feature: wip * Refactor modal to separate component * fix restoring from the drawer * rename components folder to version-history, and move version-utils.file there * skip fetching rule when uid is empty, add returnTo when restoring manually * Fix drawer fetching infinitely * Move drawer to separate file * add tracking for restore success and restore failure * Fix name of error interaction * Add `compare` to each row in version history * Add warning when manually restoring and trigger form validation * Fix initial validation for contact point selector * Wait for successful fetch before potential error * Add disabled state when loading * Fix loading check for contact point selector * Fix typo * Move hook to separate file and move other method into utils * Update imports and remove manual state management * Fix infinite render * Remove onError from dep array * Use separate flag for showing manual restore alert * Rename to createdAt * add and use ability to restore to check if retore is allowed * Fix test and add isGrafanaManagedAlertRule to the ability check * Address PR feedback * Change to isManualRestore for trigger check * udpate AlertRuleAction.Restore ability * make the alertingRuleVersionHistoryRestore ff , enabled by default * fix ff --------- Co-authored-by: Tom Ratcliffe --- pkg/services/featuremgmt/registry.go | 3 +- pkg/services/featuremgmt/toggles_gen.csv | 2 +- pkg/services/featuremgmt/toggles_gen.json | 9 +- .../VersionHistoryComparison.tsx | 40 +++-- .../features/alerting/unified/Analytics.ts | 11 ++ .../ContactPointSelector.tsx | 12 +- .../alert-rule-form/AlertRuleForm.tsx | 33 +++- .../contactPoint/ContactPointSelector.tsx | 13 +- .../components/rule-viewer/RuleViewer.tsx | 2 +- .../rule-viewer/tabs/AlertVersionHistory.tsx | 155 ++++++++++-------- .../components/rule-viewer/tabs/Details.tsx | 2 +- .../tabs/version-history/ComparisonDrawer.tsx | 67 ++++++++ .../ConfirmVersionRestoreModal.tsx | 121 ++++++++++++++ .../UpdatedBy.tsx | 2 +- .../VersionHistoryTable.tsx | 137 ++++++++-------- .../tabs/version-history/useRestoreVersion.ts | 27 +++ .../{ => version-history}/versions-utils.tsx | 34 +++- .../__snapshots__/useAbilities.test.tsx.snap | 8 + .../alerting/unified/hooks/useAbilities.ts | 3 + .../alerting/unified/hooks/useCombinedRule.ts | 14 +- .../rule-editor/ExistingRuleEditor.tsx | 10 +- .../unified/rule-editor/RuleEditor.tsx | 2 +- public/locales/en-US/grafana.json | 13 +- public/locales/pseudo-LOCALE/grafana.json | 13 +- 24 files changed, 558 insertions(+), 175 deletions(-) create mode 100644 public/app/features/alerting/unified/components/rule-viewer/tabs/version-history/ComparisonDrawer.tsx create mode 100644 public/app/features/alerting/unified/components/rule-viewer/tabs/version-history/ConfirmVersionRestoreModal.tsx rename public/app/features/alerting/unified/components/rule-viewer/tabs/{components => version-history}/UpdatedBy.tsx (96%) rename public/app/features/alerting/unified/components/rule-viewer/tabs/{components => version-history}/VersionHistoryTable.tsx (54%) create mode 100644 public/app/features/alerting/unified/components/rule-viewer/tabs/version-history/useRestoreVersion.ts rename public/app/features/alerting/unified/components/rule-viewer/tabs/{ => version-history}/versions-utils.tsx (79%) diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go index d84ae066775..f3b1da31b5c 100644 --- a/pkg/services/featuremgmt/registry.go +++ b/pkg/services/featuremgmt/registry.go @@ -1752,10 +1752,11 @@ var ( Name: "alertingRuleVersionHistoryRestore", Description: "Enables the alert rule version history restore feature", FrontendOnly: true, - Stage: FeatureStageExperimental, + Stage: FeatureStageGeneralAvailability, Owner: grafanaAlertingSquad, HideFromAdminPage: true, HideFromDocs: true, + Expression: "true", // enabled by default }, { Name: "newShareReportDrawer", diff --git a/pkg/services/featuremgmt/toggles_gen.csv b/pkg/services/featuremgmt/toggles_gen.csv index feb0e5d5d4b..fc0b0c8dfb7 100644 --- a/pkg/services/featuremgmt/toggles_gen.csv +++ b/pkg/services/featuremgmt/toggles_gen.csv @@ -232,6 +232,6 @@ newLogsPanel,experimental,@grafana/observability-logs,false,false,true grafanaconThemes,experimental,@grafana/grafana-frontend-platform,false,true,false pluginsCDNSyncLoader,experimental,@grafana/plugins-platform-backend,false,false,false alertingJiraIntegration,experimental,@grafana/alerting-squad,false,false,true -alertingRuleVersionHistoryRestore,experimental,@grafana/alerting-squad,false,false,true +alertingRuleVersionHistoryRestore,GA,@grafana/alerting-squad,false,false,true newShareReportDrawer,experimental,@grafana/sharing-squad,false,false,false rendererDisableAppPluginsPreload,experimental,@grafana/sharing-squad,false,false,true diff --git a/pkg/services/featuremgmt/toggles_gen.json b/pkg/services/featuremgmt/toggles_gen.json index 569c2cbfc1d..3f5045123d9 100644 --- a/pkg/services/featuremgmt/toggles_gen.json +++ b/pkg/services/featuremgmt/toggles_gen.json @@ -405,19 +405,20 @@ { "metadata": { "name": "alertingRuleVersionHistoryRestore", - "resourceVersion": "1738831836776", + "resourceVersion": "1740740039764", "creationTimestamp": "2025-01-16T14:08:12Z", "annotations": { - "grafana.app/updatedTimestamp": "2025-02-06 08:50:36.776739 +0000 UTC" + "grafana.app/updatedTimestamp": "2025-02-28 10:53:59.764894 +0000 UTC" } }, "spec": { "description": "Enables the alert rule version history restore feature", - "stage": "experimental", + "stage": "GA", "codeowner": "@grafana/alerting-squad", "frontend": true, "hideFromAdminPage": true, - "hideFromDocs": true + "hideFromDocs": true, + "expression": "true" } }, { diff --git a/public/app/core/components/VersionHistory/VersionHistoryComparison.tsx b/public/app/core/components/VersionHistory/VersionHistoryComparison.tsx index fd1bc5f9468..193c50d2233 100644 --- a/public/app/core/components/VersionHistory/VersionHistoryComparison.tsx +++ b/public/app/core/components/VersionHistory/VersionHistoryComparison.tsx @@ -12,7 +12,7 @@ import { jsonDiff } from 'app/features/dashboard-scene/settings/version-history/ export interface RevisionModel { version: number | string; /** When was this version created? */ - created: string; + createdAt: string; /** Who created/edited this version? */ createdBy: string; /** Optional message describing change encapsulated in this version */ @@ -36,11 +36,17 @@ type DiffViewProps = { * e.g. mapping machine IDs to translated names, removing fields that the user can't control anyway etc. */ preprocessVersion?: (version: T) => DiffArgument; + /** + * Should we show the restore button? + */ + showRestoreButton?: boolean; + /** Method invoked when restore button is clicked */ + onRestore: () => void; }; const VersionChangeSummary = ({ info }: { info: RevisionModel }) => { - const { created, createdBy, version, message = '' } = info; - const ageString = dateTimeFormatTimeAgo(created); + const { createdAt, createdBy, version, message = '' } = info; + const ageString = dateTimeFormatTimeAgo(createdAt); return ( Version {{ version }} updated by {{ createdBy }} ({{ ageString }}) {{ message }} @@ -54,6 +60,8 @@ export const VersionHistoryComparison = ({ oldVersion, newVersion, preprocessVersion = identity, + showRestoreButton = false, + onRestore, }: DiffViewProps) => { const diff = jsonDiff(preprocessVersion(oldVersion), preprocessVersion(newVersion)); const noHumanReadableDiffs = Object.entries(diff).length === 0; @@ -83,18 +91,28 @@ export const VersionHistoryComparison = ({ ))} - - {showJsonDiff && ( - - )} - {!showJsonDiff && ( - + {showRestoreButton && ( + )} - + {showJsonDiff && ( )} diff --git a/public/app/features/alerting/unified/Analytics.ts b/public/app/features/alerting/unified/Analytics.ts index 9f3cf849cda..e546d215574 100644 --- a/public/app/features/alerting/unified/Analytics.ts +++ b/public/app/features/alerting/unified/Analytics.ts @@ -8,6 +8,7 @@ import { contextSrv } from 'app/core/core'; import { RuleNamespace } from '../../../types/unified-alerting'; import { RulerRulesConfigDTO } from '../../../types/unified-alerting-dto'; +import { Origin } from './components/rule-viewer/tabs/version-history/ConfirmVersionRestoreModal'; import { FilterType } from './components/rules/central-state-history/EventListSceneObject'; import { RulesFilter, getSearchFilterFromQuery } from './search/rulesSearchParser'; import { RuleFormType } from './types/rule-form'; @@ -229,6 +230,16 @@ export const trackRuleVersionsComparisonClick = async (payload: RuleVersionCompa reportInteraction('grafana_alerting_rule_versions_comparison_click', { ...payload }); }; +export const trackRuleVersionsRestoreSuccess = async (payload: RuleVersionComparisonProps & { origin: Origin }) => { + reportInteraction('grafana_alerting_rule_versions_restore_success', { ...payload }); +}; + +export const trackRuleVersionsRestoreFail = async ( + payload: RuleVersionComparisonProps & { origin: Origin; error: Error } +) => { + reportInteraction('grafana_alerting_rule_versions_restore_error', { ...payload }); +}; + interface RulesSearchInteractionPayload { filter: string; triggeredBy: 'typing' | 'component'; diff --git a/public/app/features/alerting/unified/components/notification-policies/ContactPointSelector.tsx b/public/app/features/alerting/unified/components/notification-policies/ContactPointSelector.tsx index 69cb19ebee2..03eaff1c808 100644 --- a/public/app/features/alerting/unified/components/notification-policies/ContactPointSelector.tsx +++ b/public/app/features/alerting/unified/components/notification-policies/ContactPointSelector.tsx @@ -1,5 +1,5 @@ import { css, cx, keyframes } from '@emotion/css'; -import { useMemo, useState } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { GrafanaTheme2, SelectableValue } from '@grafana/data'; import { Alert, IconButton, Select, SelectCommonProps, Stack, Text, useStyles2 } from '@grafana/ui'; @@ -20,12 +20,14 @@ type ContactPointSelectorProps = { showRefreshButton?: boolean; /** Name of a contact point to optionally find and set as the preset value on the dropdown */ selectedContactPointName?: string | null; + onError?: (error: Error) => void; }; export const ContactPointSelector = ({ selectProps, showRefreshButton, selectedContactPointName, + onError = () => {}, }: ContactPointSelectorProps) => { const { selectedAlertmanager } = useAlertmanager(); const { contactPoints, isLoading, error, refetch } = useContactPointsWithStatus({ @@ -58,6 +60,13 @@ export const ContactPointSelector = ({ }); }; + useEffect(() => { + // If the contact points are fetched successfully and the selected contact point is not in the list, show an error + if (!isLoading && selectedContactPointName && !matchedContactPoint) { + onError(new Error(`Contact point "${selectedContactPointName}" could not be found`)); + } + }, [isLoading, matchedContactPoint, onError, selectedContactPointName]); + // TODO error handling if (error) { return ; @@ -71,6 +80,7 @@ export const ContactPointSelector = ({ value={matchedContactPoint} {...selectProps} isLoading={isLoading} + disabled={isLoading} /> {showRefreshButton && ( ; // Existing implies we modify existing rule. Prefill only provides default form values + isManualRestore?: boolean; }; const prometheusRulesPrimary = shouldUsePrometheusRulesPrimary(); -export const AlertRuleForm = ({ existing, prefill }: Props) => { +export const AlertRuleForm = ({ existing, prefill, isManualRestore }: Props) => { const styles = useStyles2(getStyles); const notifyApp = useAppNotification(); const [showEditYaml, setShowEditYaml] = useState(false); @@ -96,6 +97,11 @@ export const AlertRuleForm = ({ existing, prefill }: Props) => { const [showDeleteModal, setShowDeleteModal] = useState(false); const defaultValues: RuleFormValues = useMemo(() => { + // If we have an existing AND a prefill, then we're coming from the restore dialog + // and we want to merge the two + if (existing && prefill) { + return { ...formValuesFromExistingRule(existing), ...formValuesFromPrefill(prefill) }; + } if (existing) { return formValuesFromExistingRule(existing); } @@ -119,8 +125,16 @@ export const AlertRuleForm = ({ existing, prefill }: Props) => { handleSubmit, watch, formState: { isSubmitting }, + trigger, } = formAPI; + useEffect(() => { + // If the user is manually restoring an old version of a rule, + // we should trigger validation on the form so any problem areas are clearly highlighted for them to action + if (isManualRestore) { + trigger(); + } + }, [isManualRestore, trigger]); const type = watch('type'); const grafanaTypeRule = isGrafanaManagedRuleByType(type ?? RuleFormType.grafana); @@ -290,6 +304,17 @@ export const AlertRuleForm = ({ existing, prefill }: Props) => {
e.preventDefault()} className={styles.form}>
+ {isManualRestore && ( + + + You are manually restoring an old version of this alert rule. Please review the changes carefully before + saving the rule definition. + + + )} {isPaused && } {/* Step 1 */} diff --git a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/contactPoint/ContactPointSelector.tsx b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/contactPoint/ContactPointSelector.tsx index c3e9883f923..4c0cf9ea5aa 100644 --- a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/contactPoint/ContactPointSelector.tsx +++ b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/contactPoint/ContactPointSelector.tsx @@ -15,10 +15,20 @@ export interface ContactPointSelectorProps { } export function ContactPointSelector({ alertManager, onSelectContactPoint }: ContactPointSelectorProps) { - const { control, watch, trigger } = useFormContext(); + const { control, watch, trigger, setError } = useFormContext(); const contactPointInForm = watch(`contactPoints.${alertManager}.selectedContactPoint`); + // Wrap in useCallback to avoid infinite render loop + const handleError = useCallback( + (err: Error) => { + setError(`contactPoints.${alertManager}.selectedContactPoint`, { + message: err.message, + }); + }, + [alertManager, setError] + ); + // if we have a contact point selected, check if it still exists in the event that someone has deleted it const validateContactPoint = useCallback(() => { if (contactPointInForm) { @@ -49,6 +59,7 @@ export function ContactPointSelector({ alertManager, onSelectContactPoint }: Con }} showRefreshButton selectedContactPointName={contactPointInForm} + onError={handleError} /> diff --git a/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.tsx b/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.tsx index 5faad744839..e714277c490 100644 --- a/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.tsx +++ b/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.tsx @@ -130,7 +130,7 @@ const RuleViewer = () => { {activeTab === ActiveTab.Routing && } {activeTab === ActiveTab.Details &&
} {activeTab === ActiveTab.VersionHistory && isGrafanaRulerRule(rule.rulerRule) && ( - + )} diff --git a/public/app/features/alerting/unified/components/rule-viewer/tabs/AlertVersionHistory.tsx b/public/app/features/alerting/unified/components/rule-viewer/tabs/AlertVersionHistory.tsx index abd042bc5b5..1018b04b5c9 100644 --- a/public/app/features/alerting/unified/components/rule-viewer/tabs/AlertVersionHistory.tsx +++ b/public/app/features/alerting/unified/components/rule-viewer/tabs/AlertVersionHistory.tsx @@ -1,22 +1,31 @@ -import { useMemo, useState } from 'react'; +import { useCallback, useMemo, useState } from 'react'; import { config } from '@grafana/runtime'; -import { Alert, Box, Button, Drawer, EmptyState, LoadingPlaceholder, Stack, Text, Tooltip } from '@grafana/ui'; -import { RevisionModel, VersionHistoryComparison } from 'app/core/components/VersionHistory/VersionHistoryComparison'; +import { Alert, Button, EmptyState, LoadingPlaceholder, Stack, Text, Tooltip } from '@grafana/ui'; import { Trans, t } from 'app/core/internationalization'; +import { RuleGroupIdentifierV2, RuleIdentifier } from 'app/types/unified-alerting'; import { GrafanaRuleDefinition, RulerGrafanaRuleDTO } from 'app/types/unified-alerting-dto'; -import { LogMessages, logInfo, trackRuleVersionsComparisonClick } from '../../../Analytics'; +import { + LogMessages, + logInfo, + trackRuleVersionsComparisonClick, + trackRuleVersionsRestoreFail, + trackRuleVersionsRestoreSuccess, +} from '../../../Analytics'; import { alertRuleApi } from '../../../api/alertRuleApi'; +import { AlertRuleAction, useRulerRuleAbility } from '../../../hooks/useAbilities'; +import { GRAFANA_RULES_SOURCE_NAME } from '../../../utils/datasource'; import { stringifyErrorLike } from '../../../utils/misc'; -import { VersionHistoryTable } from './components/VersionHistoryTable'; -import { getSpecialUidsDisplayMap, preprocessRuleForDiffDisplay } from './versions-utils'; +import { ComparisonDrawer } from './version-history/ComparisonDrawer'; +import { Origin } from './version-history/ConfirmVersionRestoreModal'; +import { VersionHistoryTable } from './version-history/VersionHistoryTable'; const { useGetAlertVersionHistoryQuery } = alertRuleApi; interface AlertVersionHistoryProps { - ruleUid: string; + rule: RulerGrafanaRuleDTO; } /** List of (top level) properties to exclude from being shown in human readable summary of version changes */ @@ -32,9 +41,15 @@ export const grafanaAlertPropertiesToIgnore: Array * Render the version history of a given Grafana managed alert rule, showing different edits * and allowing to restore to a previous version. */ -export function AlertVersionHistory({ ruleUid }: AlertVersionHistoryProps) { +export function AlertVersionHistory({ rule }: AlertVersionHistoryProps) { + const ruleUid = rule.grafana_alert.uid; const { isLoading, currentData: ruleVersions = [], error } = useGetAlertVersionHistoryQuery({ uid: ruleUid }); + const ruleIdentifier: RuleIdentifier = useMemo( + () => ({ ruleSourceName: GRAFANA_RULES_SOURCE_NAME, uid: ruleUid }), + [ruleUid] + ); + const [oldVersion, setOldVersion] = useState>(); const [newVersion, setNewVersion] = useState>(); const [showDrawer, setShowDrawer] = useState(false); @@ -42,6 +57,42 @@ export function AlertVersionHistory({ ruleUid }: AlertVersionHistoryProps) { const [checkedVersions, setCheckedVersions] = useState(new Set()); const canCompare = useMemo(() => checkedVersions.size > 1, [checkedVersions]); + // check if restoring is allowed/enabled + const groupIdentifier: RuleGroupIdentifierV2 = { + namespace: { uid: rule.grafana_alert.namespace_uid }, + groupName: rule.grafana_alert.rule_group, + groupOrigin: 'grafana', + }; + const [restoreSupported, restoreAllowed] = useRulerRuleAbility(rule, groupIdentifier, AlertRuleAction.Restore); + const canRestore = + restoreAllowed && restoreSupported && Boolean(config.featureToggles.alertingRuleVersionHistoryRestore); + + //tracking functions for restore action + const onRestoreSuccess = useCallback( + (origin: Origin) => { + trackRuleVersionsRestoreSuccess({ + origin, + latest: newVersion === ruleVersions[0], + oldVersion: oldVersion?.grafana_alert.version || 0, + newVersion: newVersion?.grafana_alert.version || 0, + }); + }, + [oldVersion, newVersion, ruleVersions] + ); + + const onRestoreFail = useCallback( + (origin: Origin, error: Error) => { + trackRuleVersionsRestoreFail({ + origin, + latest: newVersion === ruleVersions[0], + oldVersion: oldVersion?.grafana_alert.version || 0, + newVersion: newVersion?.grafana_alert.version || 0, + error, + }); + }, + [oldVersion, newVersion, ruleVersions] + ); + if (error) { return ( @@ -65,7 +116,8 @@ export function AlertVersionHistory({ ruleUid }: AlertVersionHistoryProps) { ); } - const compareVersions = () => { + const compareSelectedVersions = () => { + // precondition: we have only two versions selected in checkedVersions const [older, newer] = ruleVersions .filter((rule) => { const version = rule.grafana_alert.version; @@ -89,8 +141,16 @@ export function AlertVersionHistory({ ruleUid }: AlertVersionHistoryProps) { newVersion: newer?.grafana_alert.version || 0, }); - setOldVersion(older); - setNewVersion(newer); + // setting the versions to compare + compareVersions(older, newer); + }; + + const compareVersions = ( + oldRule: RulerGrafanaRuleDTO, + newRule: RulerGrafanaRuleDTO + ) => { + setOldVersion(oldRule); + setNewVersion(newRule); setShowDrawer(true); }; @@ -104,6 +164,8 @@ export function AlertVersionHistory({ ruleUid }: AlertVersionHistoryProps) { setNewVersion(undefined); } + const isNewLatest = ruleVersions[0].grafana_alert.version === newVersion?.grafana_alert.version; + return ( @@ -117,74 +179,33 @@ export function AlertVersionHistory({ ruleUid }: AlertVersionHistoryProps) { content={t('core.versionHistory.comparison.select', 'Select two versions to start comparing')} placement="bottom" > - {showDrawer && oldVersion && newVersion && ( - setShowDrawer(false)} - title={t('alerting.alertVersionHistory.comparing-versions', 'Comparing versions')} - > - - {config.featureToggles.alertingRuleVersionHistoryRestore && ( - - - - - - )} - + onRestoreSuccess('comparison-drawer')} + onRestoreError={(err: Error) => onRestoreFail('comparison-drawer', err)} + canRestore={canRestore} + /> )} - compareVersions(rule, ruleVersions[0])} onVersionsChecked={handleCheckedVersionChange} ruleVersions={ruleVersions} disableSelection={canCompare} checkedVersions={checkedVersions} + onRestoreSuccess={() => onRestoreSuccess('version-list')} + onRestoreError={(err: Error) => onRestoreFail('version-list', err)} + canRestore={canRestore} /> ); } - -/** - * Turns a version of a Grafana rule definition into data structure - * used to display the version summary when comparing versions - */ -function parseVersionInfoToSummary(version: RulerGrafanaRuleDTO): RevisionModel { - const unknown = t('alerting.alertVersionHistory.unknown', 'Unknown'); - const SPECIAL_UID_MAP = getSpecialUidsDisplayMap(); - const createdBy = (() => { - const updatedBy = version?.grafana_alert.updated_by; - const uid = updatedBy?.uid; - const name = updatedBy?.name; - - if (!updatedBy) { - return unknown; - } - if (uid && SPECIAL_UID_MAP[uid]) { - return SPECIAL_UID_MAP[uid].name; - } - if (name) { - return name; - } - return uid ? t('alerting.alertVersionHistory.user-id', 'User ID {{uid}}', { uid }) : unknown; - })(); - - return { - created: version.grafana_alert.updated || unknown, - createdBy, - version: version.grafana_alert.version || unknown, - }; -} diff --git a/public/app/features/alerting/unified/components/rule-viewer/tabs/Details.tsx b/public/app/features/alerting/unified/components/rule-viewer/tabs/Details.tsx index 3faaa60744b..218e6cf0420 100644 --- a/public/app/features/alerting/unified/components/rule-viewer/tabs/Details.tsx +++ b/public/app/features/alerting/unified/components/rule-viewer/tabs/Details.tsx @@ -18,7 +18,7 @@ import { isNullDate } from '../../../utils/time'; import { Tokenize } from '../../Tokenize'; import { DetailText } from '../../common/DetailText'; -import { UpdatedByUser } from './components/UpdatedBy'; +import { UpdatedByUser } from './version-history/UpdatedBy'; enum RuleType { GrafanaManagedAlertRule = 'Grafana-managed alert rule', diff --git a/public/app/features/alerting/unified/components/rule-viewer/tabs/version-history/ComparisonDrawer.tsx b/public/app/features/alerting/unified/components/rule-viewer/tabs/version-history/ComparisonDrawer.tsx new file mode 100644 index 00000000000..940b107659d --- /dev/null +++ b/public/app/features/alerting/unified/components/rule-viewer/tabs/version-history/ComparisonDrawer.tsx @@ -0,0 +1,67 @@ +import { useCallback, useState } from 'react'; + +import { Drawer } from '@grafana/ui'; +import { VersionHistoryComparison } from 'app/core/components/VersionHistory/VersionHistoryComparison'; +import { t } from 'app/core/internationalization'; +import { GrafanaRuleIdentifier } from 'app/types/unified-alerting'; +import { GrafanaRuleDefinition, RulerGrafanaRuleDTO } from 'app/types/unified-alerting-dto'; + +import { ConfirmVersionRestoreModal } from './ConfirmVersionRestoreModal'; +import { parseVersionInfoToSummary, preprocessRuleForDiffDisplay } from './versions-utils'; + +interface ComparisonDrawerProps { + oldVersion: RulerGrafanaRuleDTO; + newVersion: RulerGrafanaRuleDTO; + ruleIdentifier: GrafanaRuleIdentifier; + isNewLatest: boolean; + setShowDrawer: (show: boolean) => void; + onRestoreSuccess: () => void; + onRestoreError: (error: Error) => void; + canRestore: boolean; +} + +export const ComparisonDrawer = ({ + oldVersion, + newVersion, + ruleIdentifier, + isNewLatest, + setShowDrawer, + onRestoreSuccess, + onRestoreError, + canRestore, +}: ComparisonDrawerProps) => { + const [showConfirmModal, setShowConfirmModal] = useState(false); + const onDismiss = useCallback(() => setShowDrawer(false), [setShowDrawer]); + + const oldVersionSummary = parseVersionInfoToSummary(oldVersion); + const newVersionSummary = parseVersionInfoToSummary(newVersion); + return ( + <> + setShowDrawer(false)} + title={t('alerting.alertVersionHistory.comparing-versions', 'Comparing versions')} + > + setShowConfirmModal(true)} + /> + + {showConfirmModal && ( + + )} + + ); +}; diff --git a/public/app/features/alerting/unified/components/rule-viewer/tabs/version-history/ConfirmVersionRestoreModal.tsx b/public/app/features/alerting/unified/components/rule-viewer/tabs/version-history/ConfirmVersionRestoreModal.tsx new file mode 100644 index 00000000000..95336c85016 --- /dev/null +++ b/public/app/features/alerting/unified/components/rule-viewer/tabs/version-history/ConfirmVersionRestoreModal.tsx @@ -0,0 +1,121 @@ +import { ComponentProps } from 'react'; +import { useNavigate } from 'react-router-dom-v5-compat'; + +import { urlUtil } from '@grafana/data'; +import { Alert, ConfirmModal, Stack, Text } from '@grafana/ui'; +import { Trans, t } from 'app/core/internationalization'; +import { useRuleWithLocation } from 'app/features/alerting/unified/hooks/useCombinedRule'; +import { stringifyErrorLike } from 'app/features/alerting/unified/utils/misc'; +import { rulerRuleToFormValues } from 'app/features/alerting/unified/utils/rule-form'; +import { DiffGroup } from 'app/features/dashboard-scene/settings/version-history/DiffGroup'; +import { jsonDiff } from 'app/features/dashboard-scene/settings/version-history/utils'; +import { GrafanaRuleIdentifier } from 'app/types/unified-alerting'; +import { GrafanaRuleDefinition, RulerGrafanaRuleDTO } from 'app/types/unified-alerting-dto'; + +import { useRestoreVersion } from './useRestoreVersion'; +import { preprocessRuleForDiffDisplay } from './versions-utils'; + +export type Origin = 'version-list' | 'comparison-drawer'; + +type ModalProps = Pick, 'isOpen' | 'onDismiss'> & { + isOpen: boolean; + baseVersion?: RulerGrafanaRuleDTO; + versionToRestore?: RulerGrafanaRuleDTO; + ruleIdentifier: GrafanaRuleIdentifier; + onRestoreSucess: () => void; + onRestoreError: (error: Error) => void; +}; + +export const ConfirmVersionRestoreModal = ({ + isOpen, + baseVersion, + versionToRestore, + ruleIdentifier, + onDismiss, + onRestoreSucess, + onRestoreError, +}: ModalProps) => { + const { result: ruleWithLocation } = useRuleWithLocation({ ruleIdentifier }); + const navigate = useNavigate(); + const [restoreMethod, { error }] = useRestoreVersion(); + + const title = t('alerting.alertVersionHistory.restore-modal.title', 'Restore version'); + const errorTitle = t('alerting.alertVersionHistory.restore-modal.error', 'Could not restore alert rule version '); + const confirmText = !error + ? t('alerting.alertVersionHistory.restore-modal.confirm', 'Yes, restore configuration') + : 'Manually restore rule'; + + const diff = + baseVersion && versionToRestore + ? jsonDiff(preprocessRuleForDiffDisplay(baseVersion), preprocessRuleForDiffDisplay(versionToRestore)) + : undefined; + + async function onRestoreConfirm() { + if (!versionToRestore || !ruleWithLocation) { + return; + } + return restoreMethod + .execute(versionToRestore, ruleWithLocation) + .then(() => { + onDismiss(); + onRestoreSucess(); + }) + .catch((err) => { + onRestoreError(err); + }); + } + + async function onManualRestore() { + if (!versionToRestore || !ruleWithLocation) { + return; + } + const payload = rulerRuleToFormValues({ ...ruleWithLocation, rule: versionToRestore }); + const ruleFormUrl = urlUtil.renderUrl(`/alerting/${ruleIdentifier.uid}/edit`, { + isManualRestore: true, + defaults: JSON.stringify(payload), + returnTo: location.pathname + location.search, + }); + + navigate(ruleFormUrl); + } + + return ( + + {!error && ( + + Are you sure you want to restore the alert rule definition to this version? All unsaved changes will be + lost. + + )} + + + Summary of changes to be applied: + + +
+ {diff && Object.entries(diff).map(([key, diffs]) => )} +
+ {error && ( + + + Your alert rule could not be restored. This may be due to changes to other entities such as contact + points, data sources etc. Please manually restore the rule version + +
+                {stringifyErrorLike(error)}
+              
+
+ )} + + } + onConfirm={!error ? onRestoreConfirm : onManualRestore} + onDismiss={onDismiss} + /> + ); +}; diff --git a/public/app/features/alerting/unified/components/rule-viewer/tabs/components/UpdatedBy.tsx b/public/app/features/alerting/unified/components/rule-viewer/tabs/version-history/UpdatedBy.tsx similarity index 96% rename from public/app/features/alerting/unified/components/rule-viewer/tabs/components/UpdatedBy.tsx rename to public/app/features/alerting/unified/components/rule-viewer/tabs/version-history/UpdatedBy.tsx index c391f13af83..095e7912ddb 100644 --- a/public/app/features/alerting/unified/components/rule-viewer/tabs/components/UpdatedBy.tsx +++ b/public/app/features/alerting/unified/components/rule-viewer/tabs/version-history/UpdatedBy.tsx @@ -4,7 +4,7 @@ import { Badge, Icon, Tooltip, useStyles2 } from '@grafana/ui'; import { t } from 'app/core/internationalization'; import { UpdatedBy } from 'app/types/unified-alerting-dto'; -import { getSpecialUidsDisplayMap } from '../versions-utils'; +import { getSpecialUidsDisplayMap } from './versions-utils'; export const UpdatedByUser = ({ user }: { user: UpdatedBy | null | undefined }) => { const unknown = t('alerting.alertVersionHistory.unknown', 'Unknown'); diff --git a/public/app/features/alerting/unified/components/rule-viewer/tabs/components/VersionHistoryTable.tsx b/public/app/features/alerting/unified/components/rule-viewer/tabs/version-history/VersionHistoryTable.tsx similarity index 54% rename from public/app/features/alerting/unified/components/rule-viewer/tabs/components/VersionHistoryTable.tsx rename to public/app/features/alerting/unified/components/rule-viewer/tabs/version-history/VersionHistoryTable.tsx index 29edbfcda20..e3f9e518e18 100644 --- a/public/app/features/alerting/unified/components/rule-viewer/tabs/components/VersionHistoryTable.tsx +++ b/public/app/features/alerting/unified/components/rule-viewer/tabs/version-history/VersionHistoryTable.tsx @@ -1,51 +1,58 @@ -import { useState } from 'react'; +import { useMemo, useState } from 'react'; import { dateTimeFormat, dateTimeFormatTimeAgo } from '@grafana/data'; -import { config } from '@grafana/runtime'; -import { Badge, Button, Checkbox, Column, ConfirmModal, InteractiveTable, Stack, Text } from '@grafana/ui'; +import { Badge, Button, Checkbox, Column, InteractiveTable, Stack, Text } from '@grafana/ui'; import { Trans, t } from 'app/core/internationalization'; +import { GRAFANA_RULES_SOURCE_NAME } from 'app/features/alerting/unified/utils/datasource'; import { computeVersionDiff } from 'app/features/alerting/unified/utils/diff'; -import { DiffGroup } from 'app/features/dashboard-scene/settings/version-history/DiffGroup'; -import { Diffs, jsonDiff } from 'app/features/dashboard-scene/settings/version-history/utils'; +import { RuleIdentifier } from 'app/types/unified-alerting'; import { GrafanaRuleDefinition, RulerGrafanaRuleDTO } from 'app/types/unified-alerting-dto'; +import { ConfirmVersionRestoreModal } from './ConfirmVersionRestoreModal'; import { UpdatedByUser } from './UpdatedBy'; const VERSIONS_PAGE_SIZE = 20; -export function VersionHistoryTable({ - onVersionsChecked, - ruleVersions, - disableSelection, - checkedVersions, -}: { +export interface VersionHistoryTableProps { onVersionsChecked(id: string): void; + onCompareSingleVersion(rule: RulerGrafanaRuleDTO): void; ruleVersions: Array>; disableSelection: boolean; checkedVersions: Set; -}) { - //----> restore code : no need to review as it's behind a feature flag - const [confirmRestore, setConfirmRestore] = useState(false); - const [restoreDiff, setRestoreDiff] = useState(); + onRestoreSuccess: () => void; + onRestoreError: (error: Error) => void; + canRestore: boolean; +} +export function VersionHistoryTable({ + onVersionsChecked, + onCompareSingleVersion, + ruleVersions, + disableSelection, + checkedVersions, + onRestoreSuccess, + onRestoreError, + canRestore, +}: VersionHistoryTableProps) { + const [showConfirmModal, setShowConfirmModal] = useState(false); + const [ruleToRestore, setRuleToRestore] = useState>(); + const ruleToRestoreUid = ruleToRestore?.grafana_alert?.uid ?? ''; + const ruleIdentifier: RuleIdentifier = useMemo( + () => ({ ruleSourceName: GRAFANA_RULES_SOURCE_NAME, uid: ruleToRestoreUid }), + [ruleToRestoreUid] + ); - const showConfirmation = (id: string) => { - const currentVersion = ruleVersions[0]; - const restoreVersion = ruleVersions.find((rule) => String(rule.grafana_alert.version) === id); - if (!restoreVersion) { - return; - } - - setConfirmRestore(true); - setRestoreDiff(jsonDiff(currentVersion, restoreVersion)); + const showConfirmation = (ruleToRestore: RulerGrafanaRuleDTO) => { + setShowConfirmModal(true); + setRuleToRestore(ruleToRestore); }; const hideConfirmation = () => { - setConfirmRestore(false); + setShowConfirmModal(false); }; - //----> end of restore code + const unknown = t('alerting.alertVersionHistory.unknown', 'Unknown'); - const columns: Array> = [ + const columns: Array>> = [ { disableGrow: true, id: 'id', @@ -116,22 +123,36 @@ export function VersionHistoryTable({ disableGrow: true, cell: ({ row }) => { const isFirstItem = row.index === 0; + const compareWithLatest = t('alerting.alertVersionHistory.compare-with-latest', 'Compare with latest version'); return ( {isFirstItem ? ( - ) : config.featureToggles.alertingRuleVersionHistoryRestore ? ( - + ) : canRestore ? ( + <> + + + ) : null} ); @@ -147,39 +168,15 @@ export function VersionHistoryTable({ data={ruleVersions} getRowId={(row) => `${row.grafana_alert.version}`} /> - {/* ---------------------> restore code: no need to review for this pr as it's behind a feature flag */} - - - Are you sure you want to restore the alert rule definition to this version? All unsaved changes will be - lost. - - - - Summary of changes to be applied: - - -
- {restoreDiff && ( - <> - {Object.entries(restoreDiff).map(([key, diffs]) => ( - - ))} - - )} -
- - } - confirmText={'Yes, restore configuration'} - onConfirm={() => { - hideConfirmation(); - }} - onDismiss={() => hideConfirmation()} + - {/* ------------------------------------> END OF RESTORING CODE */} ); } diff --git a/public/app/features/alerting/unified/components/rule-viewer/tabs/version-history/useRestoreVersion.ts b/public/app/features/alerting/unified/components/rule-viewer/tabs/version-history/useRestoreVersion.ts new file mode 100644 index 00000000000..ec6d6fdf31d --- /dev/null +++ b/public/app/features/alerting/unified/components/rule-viewer/tabs/version-history/useRestoreVersion.ts @@ -0,0 +1,27 @@ +import { useUpdateRuleInRuleGroup } from 'app/features/alerting/unified/hooks/ruleGroup/useUpsertRuleFromRuleGroup'; +import { useAsync } from 'app/features/alerting/unified/hooks/useAsync'; +import { GRAFANA_RULES_SOURCE_NAME } from 'app/features/alerting/unified/utils/datasource'; +import { fromRulerRuleAndRuleGroupIdentifier } from 'app/features/alerting/unified/utils/rule-id'; +import { getRuleGroupLocationFromRuleWithLocation } from 'app/features/alerting/unified/utils/rules'; +import { RuleWithLocation } from 'app/types/unified-alerting'; +import { GrafanaRuleDefinition, RulerGrafanaRuleDTO, RulerRuleDTO } from 'app/types/unified-alerting-dto'; + +export function useRestoreVersion() { + const [updateRuleInRuleGroup] = useUpdateRuleInRuleGroup(); + + return useAsync( + async ( + newVersion: RulerGrafanaRuleDTO, + ruleWithLocation: RuleWithLocation + ) => { + const ruleGroupIdentifier = getRuleGroupLocationFromRuleWithLocation(ruleWithLocation); + const ruleIdentifier = fromRulerRuleAndRuleGroupIdentifier(ruleGroupIdentifier, newVersion); + // restore version + return updateRuleInRuleGroup.execute(ruleGroupIdentifier, ruleIdentifier, newVersion, { + dataSourceName: GRAFANA_RULES_SOURCE_NAME, + namespaceName: newVersion.grafana_alert.namespace_uid, + groupName: newVersion.grafana_alert.rule_group, + }); + } + ); +} diff --git a/public/app/features/alerting/unified/components/rule-viewer/tabs/versions-utils.tsx b/public/app/features/alerting/unified/components/rule-viewer/tabs/version-history/versions-utils.tsx similarity index 79% rename from public/app/features/alerting/unified/components/rule-viewer/tabs/versions-utils.tsx rename to public/app/features/alerting/unified/components/rule-viewer/tabs/version-history/versions-utils.tsx index b7ef95c8961..c1748cc1d04 100644 --- a/public/app/features/alerting/unified/components/rule-viewer/tabs/versions-utils.tsx +++ b/public/app/features/alerting/unified/components/rule-viewer/tabs/version-history/versions-utils.tsx @@ -1,5 +1,6 @@ import { IconName } from '@grafana/data'; import { BadgeColor } from '@grafana/ui'; +import { RevisionModel } from 'app/core/components/VersionHistory/VersionHistoryComparison'; import { t } from 'app/core/internationalization'; import { GrafanaAlertRuleDTOField, @@ -8,7 +9,7 @@ import { TopLevelGrafanaRuleDTOField, } from 'app/types/unified-alerting-dto'; -import { grafanaAlertPropertiesToIgnore } from './AlertVersionHistory'; +import { grafanaAlertPropertiesToIgnore } from '../AlertVersionHistory'; interface SpecialUidsDisplayMapEntry { name: string; @@ -104,3 +105,34 @@ export function preprocessRuleForDiffDisplay(rulerRule: RulerGrafanaRuleDTO): RevisionModel { + const unknown = t('alerting.alertVersionHistory.unknown', 'Unknown'); + const SPECIAL_UID_MAP = getSpecialUidsDisplayMap(); + const createdBy = (() => { + const updatedBy = version?.grafana_alert.updated_by; + const uid = updatedBy?.uid; + const name = updatedBy?.name; + + if (!updatedBy) { + return unknown; + } + if (uid && SPECIAL_UID_MAP[uid]) { + return SPECIAL_UID_MAP[uid].name; + } + if (name) { + return name; + } + return uid ? t('alerting.alertVersionHistory.user-id', 'User ID {{uid}}', { uid }) : unknown; + })(); + + return { + createdAt: version.grafana_alert.updated || unknown, + createdBy, + version: version.grafana_alert.version || unknown, + }; +} diff --git a/public/app/features/alerting/unified/hooks/__snapshots__/useAbilities.test.tsx.snap b/public/app/features/alerting/unified/hooks/__snapshots__/useAbilities.test.tsx.snap index 5a9da03ba29..45a27ea0e07 100644 --- a/public/app/features/alerting/unified/hooks/__snapshots__/useAbilities.test.tsx.snap +++ b/public/app/features/alerting/unified/hooks/__snapshots__/useAbilities.test.tsx.snap @@ -22,6 +22,10 @@ exports[`AlertRule abilities should report no permissions while we are loading d false, false, ], + "restore-alert-rule": [ + false, + false, + ], "silence-alert-rule": [ false, false, @@ -59,6 +63,10 @@ exports[`AlertRule abilities should report that all actions are supported for a true, false, ], + "restore-alert-rule": [ + true, + false, + ], "silence-alert-rule": [ true, false, diff --git a/public/app/features/alerting/unified/hooks/useAbilities.ts b/public/app/features/alerting/unified/hooks/useAbilities.ts index f7a623a2c64..8bace1f93e9 100644 --- a/public/app/features/alerting/unified/hooks/useAbilities.ts +++ b/public/app/features/alerting/unified/hooks/useAbilities.ts @@ -87,6 +87,7 @@ export enum AlertRuleAction { Silence = 'silence-alert-rule', ModifyExport = 'modify-export-rule', Pause = 'pause-alert-rule', + Restore = 'restore-alert-rule', } // this enum lists all of the actions we can perform within alerting in general, not linked to a specific @@ -231,6 +232,7 @@ export function useAllAlertRuleAbilities(rule: CombinedRule): Abilities { + const validIdentifier = (() => { + if (isGrafanaRuleIdentifier(ruleIdentifier) && ruleIdentifier.uid !== '') { + return { uid: ruleIdentifier.uid }; + } + return skipToken; + })(); + const { isLoading, currentData, error, isUninitialized } = alertRuleApi.endpoints.getAlertRule.useQuery( - { uid: isGrafanaRuleIdentifier(ruleIdentifier) ? ruleIdentifier.uid : '' }, - { skip: !isGrafanaRuleIdentifier(ruleIdentifier), refetchOnMountOrArgChange: true } + validIdentifier, + { + refetchOnMountOrArgChange: true, + } ); return useMemo(() => { diff --git a/public/app/features/alerting/unified/rule-editor/ExistingRuleEditor.tsx b/public/app/features/alerting/unified/rule-editor/ExistingRuleEditor.tsx index fe33ee855ec..00641db1eda 100644 --- a/public/app/features/alerting/unified/rule-editor/ExistingRuleEditor.tsx +++ b/public/app/features/alerting/unified/rule-editor/ExistingRuleEditor.tsx @@ -1,23 +1,29 @@ import { Alert, LoadingPlaceholder } from '@grafana/ui'; +import { useQueryParams } from 'app/core/hooks/useQueryParams'; import { RuleIdentifier } from 'app/types/unified-alerting'; import { AlertWarning } from '../AlertWarning'; import { AlertRuleForm } from '../components/rule-editor/alert-rule-form/AlertRuleForm'; import { useRuleWithLocation } from '../hooks/useCombinedRule'; import { useIsRuleEditable } from '../hooks/useIsRuleEditable'; +import { RuleFormValues } from '../types/rule-form'; import { stringifyErrorLike } from '../utils/misc'; import * as ruleId from '../utils/rule-id'; interface ExistingRuleEditorProps { identifier: RuleIdentifier; + /** Provide prefill if we are trying to restore an old version of an alert rule but we need the user to manually tweak the values */ + prefill?: Partial; } -export function ExistingRuleEditor({ identifier }: ExistingRuleEditorProps) { +export function ExistingRuleEditor({ identifier, prefill }: ExistingRuleEditorProps) { const { loading: loadingAlertRule, result: ruleWithLocation, error, } = useRuleWithLocation({ ruleIdentifier: identifier }); + const [queryParams] = useQueryParams(); + const isManualRestore = Boolean(queryParams.isManualRestore); const ruleSourceName = ruleId.ruleIdentifierToRuleSourceName(identifier); @@ -45,5 +51,5 @@ export function ExistingRuleEditor({ identifier }: ExistingRuleEditorProps) { return Sorry! You do not have permission to edit this rule.; } - return ; + return ; } diff --git a/public/app/features/alerting/unified/rule-editor/RuleEditor.tsx b/public/app/features/alerting/unified/rule-editor/RuleEditor.tsx index 42585600052..5c1859b5865 100644 --- a/public/app/features/alerting/unified/rule-editor/RuleEditor.tsx +++ b/public/app/features/alerting/unified/rule-editor/RuleEditor.tsx @@ -61,7 +61,7 @@ const RuleEditor = () => { } if (identifier) { - return ; + return ; } if (copyFromIdentifier) { diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index fe2fea8fc02..2447f89a826 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -209,6 +209,8 @@ "alerting": "Alerting", "alerting-change-description": "This update was made by the alerting system due to other changes. For example, when renaming a contact point that is used for simplified routing, this will update affected rules", "annotations": "Annotations", + "compare": "Compare", + "compare-with-latest": "Compare with latest version", "compareVersions": "Compare versions", "comparing-versions": "Comparing versions", "condition": "Alert condition", @@ -228,17 +230,22 @@ "provisioning": "Provisioning", "provisioning-change-description": "Version update was made via provisioning", "queryAndAlertCondition": "Query and alert condition", - "reset": "Reset to version {{version}}", "restore": "Restore", + "restore-manually": "Your alert rule could not be restored. This may be due to changes to other entities such as contact points, data sources etc. Please manually restore the rule version", "restore-modal": { "body": "Are you sure you want to restore the alert rule definition to this version? All unsaved changes will be lost.", + "confirm": "Yes, restore configuration", + "error": "Could not restore alert rule version ", "summary": "Summary of changes to be applied:", - "title": "Restore Version" + "title": "Restore version" }, + "restore-version": "Restore to version {{version}}", "rule_group": "Rule group", "unknown": "Unknown", "unknown-change-description": "This update was made prior to the implementation of alert rule version history. The user who made the change is not tracked, but future changes will include the user", - "user-id": "User ID {{uid}}" + "user-id": "User ID {{uid}}", + "warning-restore-manually": "You are manually restoring an old version of this alert rule. Please review the changes carefully before saving the rule definition.", + "warning-restore-manually-title": "Restoring rule manually" }, "annotations": { "description": "Add more context to your alert notifications.", diff --git a/public/locales/pseudo-LOCALE/grafana.json b/public/locales/pseudo-LOCALE/grafana.json index d6af162cbf2..9bd26c9e45a 100644 --- a/public/locales/pseudo-LOCALE/grafana.json +++ b/public/locales/pseudo-LOCALE/grafana.json @@ -209,6 +209,8 @@ "alerting": "Åľęřŧįʼnģ", "alerting-change-description": "Ŧĥįş ūpđäŧę ŵäş mäđę þy ŧĥę äľęřŧįʼnģ şyşŧęm đūę ŧő őŧĥęř čĥäʼnģęş. Főř ęχämpľę, ŵĥęʼn řęʼnämįʼnģ ä čőʼnŧäčŧ pőįʼnŧ ŧĥäŧ įş ūşęđ ƒőř şįmpľįƒįęđ řőūŧįʼnģ, ŧĥįş ŵįľľ ūpđäŧę 䃃ęčŧęđ řūľęş", "annotations": "Åʼnʼnőŧäŧįőʼnş", + "compare": "Cőmpäřę", + "compare-with-latest": "Cőmpäřę ŵįŧĥ ľäŧęşŧ vęřşįőʼn", "compareVersions": "Cőmpäřę vęřşįőʼnş", "comparing-versions": "Cőmpäřįʼnģ vęřşįőʼnş", "condition": "Åľęřŧ čőʼnđįŧįőʼn", @@ -228,17 +230,22 @@ "provisioning": "Přővįşįőʼnįʼnģ", "provisioning-change-description": "Vęřşįőʼn ūpđäŧę ŵäş mäđę vįä přővįşįőʼnįʼnģ", "queryAndAlertCondition": "Qūęřy äʼnđ äľęřŧ čőʼnđįŧįőʼn", - "reset": "Ŗęşęŧ ŧő vęřşįőʼn {{version}}", "restore": "Ŗęşŧőřę", + "restore-manually": "Ÿőūř äľęřŧ řūľę čőūľđ ʼnőŧ þę řęşŧőřęđ. Ŧĥįş mäy þę đūę ŧő čĥäʼnģęş ŧő őŧĥęř ęʼnŧįŧįęş şūčĥ äş čőʼnŧäčŧ pőįʼnŧş, đäŧä şőūřčęş ęŧč. Pľęäşę mäʼnūäľľy řęşŧőřę ŧĥę řūľę vęřşįőʼn", "restore-modal": { "body": "Åřę yőū şūřę yőū ŵäʼnŧ ŧő řęşŧőřę ŧĥę äľęřŧ řūľę đęƒįʼnįŧįőʼn ŧő ŧĥįş vęřşįőʼn? Åľľ ūʼnşävęđ čĥäʼnģęş ŵįľľ þę ľőşŧ.", + "confirm": "Ÿęş, řęşŧőřę čőʼnƒįģūřäŧįőʼn", + "error": "Cőūľđ ʼnőŧ řęşŧőřę äľęřŧ řūľę vęřşįőʼn ", "summary": "Ŝūmmäřy őƒ čĥäʼnģęş ŧő þę äppľįęđ:", - "title": "Ŗęşŧőřę Vęřşįőʼn" + "title": "Ŗęşŧőřę vęřşįőʼn" }, + "restore-version": "Ŗęşŧőřę ŧő vęřşįőʼn {{version}}", "rule_group": "Ŗūľę ģřőūp", "unknown": "Ůʼnĸʼnőŵʼn", "unknown-change-description": "Ŧĥįş ūpđäŧę ŵäş mäđę přįőř ŧő ŧĥę įmpľęmęʼnŧäŧįőʼn őƒ äľęřŧ řūľę vęřşįőʼn ĥįşŧőřy. Ŧĥę ūşęř ŵĥő mäđę ŧĥę čĥäʼnģę įş ʼnőŧ ŧřäčĸęđ, þūŧ ƒūŧūřę čĥäʼnģęş ŵįľľ įʼnčľūđę ŧĥę ūşęř", - "user-id": "Ůşęř ĨĐ {{uid}}" + "user-id": "Ůşęř ĨĐ {{uid}}", + "warning-restore-manually": "Ÿőū äřę mäʼnūäľľy řęşŧőřįʼnģ äʼn őľđ vęřşįőʼn őƒ ŧĥįş äľęřŧ řūľę. Pľęäşę řęvįęŵ ŧĥę čĥäʼnģęş čäřęƒūľľy þęƒőřę şävįʼnģ ŧĥę řūľę đęƒįʼnįŧįőʼn.", + "warning-restore-manually-title": "Ŗęşŧőřįʼnģ řūľę mäʼnūäľľy" }, "annotations": { "description": "Åđđ mőřę čőʼnŧęχŧ ŧő yőūř äľęřŧ ʼnőŧįƒįčäŧįőʼnş.", From 7fb0d1b3e6c379d6d2c4bf36ec5b8dd361c49f61 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 28 Feb 2025 12:09:33 +0000 Subject: [PATCH 34/74] Update dependency @floating-ui/react to v0.27.5 (#101451) 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 07870be6c31..1660de6b891 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.3", + "@floating-ui/react": "0.27.5", "@formatjs/intl-durationformat": "^0.7.0", "@glideapps/glide-data-grid": "^6.0.0", "@grafana/aws-sdk": "0.6.0", diff --git a/packages/grafana-prometheus/package.json b/packages/grafana-prometheus/package.json index 4232a385393..9cf1a0c1100 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.3", + "@floating-ui/react": "0.27.5", "@grafana/data": "11.6.0-pre", "@grafana/e2e-selectors": "11.6.0-pre", "@grafana/plugin-ui": "0.10.1", diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index cce6ef25960..1116e1b2980 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.3", + "@floating-ui/react": "0.27.5", "@grafana/data": "11.6.0-pre", "@grafana/e2e-selectors": "11.6.0-pre", "@grafana/faro-web-sdk": "^1.13.2", diff --git a/yarn.lock b/yarn.lock index 67d212cde43..c1864d839a9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2389,9 +2389,9 @@ __metadata: languageName: node linkType: hard -"@floating-ui/react@npm:0.27.3": - version: 0.27.3 - resolution: "@floating-ui/react@npm:0.27.3" +"@floating-ui/react@npm:0.27.5": + version: 0.27.5 + resolution: "@floating-ui/react@npm:0.27.5" dependencies: "@floating-ui/react-dom": "npm:^2.1.2" "@floating-ui/utils": "npm:^0.2.9" @@ -2399,7 +2399,7 @@ __metadata: peerDependencies: react: ">=17.0.0" react-dom: ">=17.0.0" - checksum: 10/91eef58241b2225420fa73dfc501934463310489e08f2a0681b320e0c639c9ee59044ab66645f2901b74a88328208ff4cc4afabe93917a7a28f9d18037965cb6 + checksum: 10/7728dc43b85e40dc01e5aae19da3e3f88ccfcbecb331a1c978a95e0b5c4e95f9ca6927bd216ae556e0a0e2839524fbf317fd0df93946b3cd0510ddb266746c9a languageName: node linkType: hard @@ -3436,7 +3436,7 @@ __metadata: resolution: "@grafana/prometheus@workspace:packages/grafana-prometheus" dependencies: "@emotion/css": "npm:11.13.5" - "@floating-ui/react": "npm:0.27.3" + "@floating-ui/react": "npm:0.27.5" "@grafana/data": "npm:11.6.0-pre" "@grafana/e2e-selectors": "npm:11.6.0-pre" "@grafana/plugin-ui": "npm:0.10.1" @@ -3805,7 +3805,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.3" + "@floating-ui/react": "npm:0.27.5" "@grafana/data": "npm:11.6.0-pre" "@grafana/e2e-selectors": "npm:11.6.0-pre" "@grafana/faro-web-sdk": "npm:^1.13.2" @@ -18102,7 +18102,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.3" + "@floating-ui/react": "npm:0.27.5" "@formatjs/intl-durationformat": "npm:^0.7.0" "@glideapps/glide-data-grid": "npm:^6.0.0" "@grafana/aws-sdk": "npm:0.6.0" From f5e5824babbc5cc51749c7f27ce042c4c65aaa41 Mon Sep 17 00:00:00 2001 From: Will Assis <35489495+gassiss@users.noreply.github.com> Date: Fri, 28 Feb 2025 09:39:39 -0300 Subject: [PATCH 35/74] fix (unified-storage): stop registering unified storage metrics in global state (#101322) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * move prometheus.register for unified storage metrics into metrics.go and do most of the plumbing to get it to work * convert StorageApiMetrics to pointer and check for nil before using it * rename type and variables to something more sensible --------- Co-authored-by: Jean-Philippe Quéméner --- go.work.sum | 4 +- .../datamigrations/to_unified_storage.go | 2 +- pkg/server/module_server.go | 11 ++-- pkg/server/wire.go | 2 + pkg/server/wireexts_oss.go | 3 + pkg/storage/unified/client.go | 7 +- pkg/storage/unified/resource/metrics.go | 65 +++++++------------ pkg/storage/unified/resource/server.go | 62 +++++++++--------- pkg/storage/unified/sql/backend.go | 7 +- pkg/storage/unified/sql/notifier.go | 1 + pkg/storage/unified/sql/notifier_sql.go | 15 +++-- pkg/storage/unified/sql/server.go | 4 +- pkg/storage/unified/sql/service.go | 27 ++++---- .../unified/sql/test/integration_test.go | 2 +- pkg/tests/testinfra/testinfra.go | 2 +- 15 files changed, 108 insertions(+), 106 deletions(-) diff --git a/go.work.sum b/go.work.sum index 25fc8254a99..49a43b5d80b 100644 --- a/go.work.sum +++ b/go.work.sum @@ -501,7 +501,6 @@ github.com/elastic/go-sysinfo v1.11.2/go.mod h1:GKqR8bbMK/1ITnez9NIsIfXQr25aLhRJ github.com/elastic/go-windows v1.0.1 h1:AlYZOldA+UJ0/2nBuqWdo90GFCgG9xuyw9SYzGUtJm0= github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss= github.com/elazarl/goproxy v1.3.0/go.mod h1:X/5W/t+gzDyLfHW4DrMdpjqYjpXsURlBt9lpBDxZZZQ= -github.com/elazarl/goproxy v1.7.1 h1:1P7LPSxbqtNxusFnXclj6O56pjfq1xOQZ6a0mwwKUlY= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= @@ -585,7 +584,6 @@ github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs0 github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/cel-go v0.22.0/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8= -github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= github.com/google/go-jsonnet v0.18.0 h1:/6pTy6g+Jh1a1I2UMoAODkqELFiVIdOxbNwv0DDzoOg= github.com/google/go-jsonnet v0.18.0/go.mod h1:C3fTzyVJDslXdiTqw/bTFk7vSGyCtH3MGRbDfvEwGd0= @@ -629,6 +627,7 @@ github.com/grafana/grafana/apps/investigation v0.0.0-20250121113133-e747350fee2d github.com/grafana/grafana/apps/playlist v0.0.0-20250121113133-e747350fee2d/go.mod h1:DjJe5osrW/BKrzN9hAAOSElNWutj1bcriExa7iDP7kA= github.com/grafana/grafana/pkg/aggregator v0.0.0-20250121113133-e747350fee2d/go.mod h1:1sq0guad+G4SUTlBgx7SXfhnzy7D86K/LcVOtiQCiMA= github.com/grafana/grafana/pkg/build v0.0.0-20250220114259-be81314e2118/go.mod h1:STVpVboMYeBAfyn6Zw6XHhTHqUxzMy7pzRiVgk1l0W0= +github.com/grafana/grafana/pkg/build v0.0.0-20250227163402-d78c646f93bb/go.mod h1:Vw0LdoMma64VgIMVpRY3i0D156jddgUGjTQBOcyeF3k= github.com/grafana/grafana/pkg/semconv v0.0.0-20250121113133-e747350fee2d/go.mod h1:tfLnBpPYgwrBMRz4EXqPCZJyCjEG4Ev37FSlXnocJ2c= github.com/grafana/grafana/pkg/storage/unified/apistore v0.0.0-20250121113133-e747350fee2d/go.mod h1:CXpwZ3Mkw6xVlGKc0SqUxqXCP3Uv182q6qAQnLaLxRg= github.com/grafana/tail v0.0.0-20230510142333-77b18831edf0 h1:bjh0PVYSVVFxzINqPFYJmAmJNrWPgnVjuSdYJGHmtFU= @@ -1187,7 +1186,6 @@ google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojt google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= diff --git a/pkg/cmd/grafana-cli/commands/datamigrations/to_unified_storage.go b/pkg/cmd/grafana-cli/commands/datamigrations/to_unified_storage.go index 27e2fe15e05..bd876a1c194 100644 --- a/pkg/cmd/grafana-cli/commands/datamigrations/to_unified_storage.go +++ b/pkg/cmd/grafana-cli/commands/datamigrations/to_unified_storage.go @@ -196,7 +196,7 @@ func newUnifiedClient(cfg *setting.Cfg, sqlStore db.DB) (resource.ResourceClient Reg: prometheus.NewPedanticRegistry(), Authzc: authlib.FixedAccessClient(true), // always true! Docs: nil, // document supplier - }) + }, nil) } func newParquetClient(file *os.File) (resource.BulkStoreClient, error) { diff --git a/pkg/server/module_server.go b/pkg/server/module_server.go index f20225cba5b..2f0e7a1a03c 100644 --- a/pkg/server/module_server.go +++ b/pkg/server/module_server.go @@ -16,13 +16,14 @@ import ( "github.com/grafana/grafana/pkg/services/authz" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/setting" + "github.com/grafana/grafana/pkg/storage/unified/resource" "github.com/grafana/grafana/pkg/storage/unified/sql" ) // NewModule returns an instance of a ModuleServer, responsible for managing // dskit modules (services). -func NewModule(opts Options, apiOpts api.ServerOptions, features featuremgmt.FeatureToggles, cfg *setting.Cfg) (*ModuleServer, error) { - s, err := newModuleServer(opts, apiOpts, features, cfg) +func NewModule(opts Options, apiOpts api.ServerOptions, features featuremgmt.FeatureToggles, cfg *setting.Cfg, storageMetrics *resource.StorageMetrics) (*ModuleServer, error) { + s, err := newModuleServer(opts, apiOpts, features, cfg, storageMetrics) if err != nil { return nil, err } @@ -34,7 +35,7 @@ func NewModule(opts Options, apiOpts api.ServerOptions, features featuremgmt.Fea return s, nil } -func newModuleServer(opts Options, apiOpts api.ServerOptions, features featuremgmt.FeatureToggles, cfg *setting.Cfg) (*ModuleServer, error) { +func newModuleServer(opts Options, apiOpts api.ServerOptions, features featuremgmt.FeatureToggles, cfg *setting.Cfg, storageMetrics *resource.StorageMetrics) (*ModuleServer, error) { rootCtx, shutdownFn := context.WithCancel(context.Background()) s := &ModuleServer{ @@ -50,6 +51,7 @@ func newModuleServer(opts Options, apiOpts api.ServerOptions, features featuremg version: opts.Version, commit: opts.Commit, buildBranch: opts.BuildBranch, + storageMetrics: storageMetrics, } return s, nil @@ -71,6 +73,7 @@ type ModuleServer struct { shutdownFinished chan struct{} isInitialized bool mtx sync.Mutex + storageMetrics *resource.StorageMetrics pidFile string version string @@ -135,7 +138,7 @@ func (s *ModuleServer) Run() error { if err != nil { return nil, err } - return sql.ProvideUnifiedStorageGrpcService(s.cfg, s.features, nil, s.log, nil, docBuilders) + return sql.ProvideUnifiedStorageGrpcService(s.cfg, s.features, nil, s.log, nil, docBuilders, s.storageMetrics) }) m.RegisterModule(modules.ZanzanaServer, func() (services.Service, error) { diff --git a/pkg/server/wire.go b/pkg/server/wire.go index e44039bd2ca..5bbd477bb2d 100644 --- a/pkg/server/wire.go +++ b/pkg/server/wire.go @@ -400,6 +400,8 @@ var wireBasicSet = wire.NewSet( connectors.ProvideOrgRoleMapper, wire.Bind(new(user.Verifier), new(*userimpl.Verifier)), authz.WireSet, + // Unified storage + resource.ProvideStorageMetrics, // Kubernetes API server grafanaapiserver.WireSet, apiregistry.WireSet, diff --git a/pkg/server/wireexts_oss.go b/pkg/server/wireexts_oss.go index 96927f3ddba..8f10bfd32e3 100644 --- a/pkg/server/wireexts_oss.go +++ b/pkg/server/wireexts_oss.go @@ -52,6 +52,7 @@ import ( "github.com/grafana/grafana/pkg/services/validations" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/storage/unified" + "github.com/grafana/grafana/pkg/storage/unified/resource" search2 "github.com/grafana/grafana/pkg/storage/unified/search" ) @@ -155,6 +156,8 @@ var wireExtsBaseCLISet = wire.NewSet( var wireExtsModuleServerSet = wire.NewSet( NewModule, wireExtsBaseCLISet, + // Unified storage + resource.ProvideStorageMetrics, ) var wireExtsStandaloneAPIServerSet = wire.NewSet( diff --git a/pkg/storage/unified/client.go b/pkg/storage/unified/client.go index a0ddcce31a0..75c6cbdf9fa 100644 --- a/pkg/storage/unified/client.go +++ b/pkg/storage/unified/client.go @@ -51,7 +51,7 @@ type clientMetrics struct { } // This adds a UnifiedStorage client into the wire dependency tree -func ProvideUnifiedStorageClient(opts *Options) (resource.ResourceClient, error) { +func ProvideUnifiedStorageClient(opts *Options, storageMetrics *resource.StorageMetrics) (resource.ResourceClient, error) { // See: apiserver.ApplyGrafanaConfig(cfg, features, o) apiserverCfg := opts.Cfg.SectionWithEnvOverrides("grafana-apiserver") client, err := newClient(options.StorageOptions{ @@ -59,7 +59,7 @@ func ProvideUnifiedStorageClient(opts *Options) (resource.ResourceClient, error) DataPath: apiserverCfg.Key("storage_path").MustString(filepath.Join(opts.Cfg.DataPath, "grafana-apiserver")), Address: apiserverCfg.Key("address").MustString(""), // client address BlobStoreURL: apiserverCfg.Key("blob_url").MustString(""), - }, opts.Cfg, opts.Features, opts.DB, opts.Tracer, opts.Reg, opts.Authzc, opts.Docs) + }, opts.Cfg, opts.Features, opts.DB, opts.Tracer, opts.Reg, opts.Authzc, opts.Docs, storageMetrics) if err == nil { // Used to get the folder stats client = federated.NewFederatedClient( @@ -79,6 +79,7 @@ func newClient(opts options.StorageOptions, reg prometheus.Registerer, authzc types.AccessClient, docs resource.DocumentBuilderSupplier, + storageMetrics *resource.StorageMetrics, ) (resource.ResourceClient, error) { ctx := context.Background() switch opts.StorageType { @@ -134,7 +135,7 @@ func newClient(opts options.StorageOptions, if err != nil { return nil, err } - server, err := sql.NewResourceServer(db, cfg, tracer, reg, authzc, searchOptions) + server, err := sql.NewResourceServer(db, cfg, tracer, reg, authzc, searchOptions, storageMetrics) if err != nil { return nil, err } diff --git a/pkg/storage/unified/resource/metrics.go b/pkg/storage/unified/resource/metrics.go index f17d0133b2f..6194f30bb10 100644 --- a/pkg/storage/unified/resource/metrics.go +++ b/pkg/storage/unified/resource/metrics.go @@ -1,56 +1,37 @@ package resource import ( - "sync" "time" "github.com/grafana/dskit/instrument" "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" ) -var ( - once sync.Once - StorageServerMetrics *StorageApiMetrics -) - -type StorageApiMetrics struct { +type StorageMetrics struct { WatchEventLatency *prometheus.HistogramVec PollerLatency prometheus.Histogram } -func NewStorageMetrics() *StorageApiMetrics { - once.Do(func() { - StorageServerMetrics = &StorageApiMetrics{ - WatchEventLatency: prometheus.NewHistogramVec(prometheus.HistogramOpts{ - Namespace: "storage_server", - Name: "watch_latency_seconds", - Help: "Time (in seconds) spent waiting for watch events to be sent", - Buckets: instrument.DefBuckets, - NativeHistogramBucketFactor: 1.1, // enable native histograms - NativeHistogramMaxBucketNumber: 160, - NativeHistogramMinResetDuration: time.Hour, - }, []string{"resource"}), - PollerLatency: prometheus.NewHistogram(prometheus.HistogramOpts{ - Namespace: "storage_server", - Name: "poller_query_latency_seconds", - Help: "poller query latency", - Buckets: instrument.DefBuckets, - NativeHistogramBucketFactor: 1.1, // enable native histograms - NativeHistogramMaxBucketNumber: 160, - NativeHistogramMinResetDuration: time.Hour, - }), - } - }) - - return StorageServerMetrics -} - -func (s *StorageApiMetrics) Collect(ch chan<- prometheus.Metric) { - s.WatchEventLatency.Collect(ch) - s.PollerLatency.Collect(ch) -} - -func (s *StorageApiMetrics) Describe(ch chan<- *prometheus.Desc) { - s.WatchEventLatency.Describe(ch) - s.PollerLatency.Describe(ch) +func ProvideStorageMetrics(reg prometheus.Registerer) *StorageMetrics { + return &StorageMetrics{ + WatchEventLatency: promauto.With(reg).NewHistogramVec(prometheus.HistogramOpts{ + Namespace: "storage_server", + Name: "watch_latency_seconds", + Help: "Time (in seconds) spent waiting for watch events to be sent", + Buckets: instrument.DefBuckets, + NativeHistogramBucketFactor: 1.1, // enable native histograms + NativeHistogramMaxBucketNumber: 160, + NativeHistogramMinResetDuration: time.Hour, + }, []string{"resource"}), + PollerLatency: promauto.With(reg).NewHistogram(prometheus.HistogramOpts{ + Namespace: "storage_server", + Name: "poller_query_latency_seconds", + Help: "poller query latency", + Buckets: instrument.DefBuckets, + NativeHistogramBucketFactor: 1.1, // enable native histograms + NativeHistogramMaxBucketNumber: 160, + NativeHistogramMinResetDuration: time.Hour, + }), + } } diff --git a/pkg/storage/unified/resource/server.go b/pkg/storage/unified/resource/server.go index 89b07c616a0..3314cdd6ffc 100644 --- a/pkg/storage/unified/resource/server.go +++ b/pkg/storage/unified/resource/server.go @@ -182,6 +182,8 @@ type ResourceServerOptions struct { // Registerer to register prometheus Metrics for the Resource server Reg prometheus.Registerer + + storageMetrics *StorageMetrics } func NewResourceServer(opts ResourceServerOptions) (ResourceServer, error) { @@ -230,25 +232,22 @@ func NewResourceServer(opts ResourceServerOptions) (ResourceServer, error) { } logger := slog.Default().With("logger", "resource-server") - // register metrics - if err := prometheus.Register(NewStorageMetrics()); err != nil { - logger.Warn("failed to register storage metrics", "error", err) - } // Make this cancelable ctx, cancel := context.WithCancel(context.Background()) s := &server{ - tracer: opts.Tracer, - log: logger, - backend: opts.Backend, - blob: blobstore, - diagnostics: opts.Diagnostics, - access: opts.AccessClient, - writeHooks: opts.WriteHooks, - lifecycle: opts.Lifecycle, - now: opts.Now, - ctx: ctx, - cancel: cancel, + tracer: opts.Tracer, + log: logger, + backend: opts.Backend, + blob: blobstore, + diagnostics: opts.Diagnostics, + access: opts.AccessClient, + writeHooks: opts.WriteHooks, + lifecycle: opts.Lifecycle, + now: opts.Now, + ctx: ctx, + cancel: cancel, + storageMetrics: opts.storageMetrics, } if opts.Search.Resources != nil { @@ -271,17 +270,18 @@ func NewResourceServer(opts ResourceServerOptions) (ResourceServer, error) { var _ ResourceServer = &server{} type server struct { - tracer trace.Tracer - log *slog.Logger - backend StorageBackend - blob BlobSupport - search *searchSupport - diagnostics DiagnosticsServer - access claims.AccessClient - writeHooks WriteAccessHooks - lifecycle LifecycleHooks - now func() int64 - mostRecentRV atomic.Int64 // The most recent resource version seen by the server + tracer trace.Tracer + log *slog.Logger + backend StorageBackend + blob BlobSupport + search *searchSupport + diagnostics DiagnosticsServer + access claims.AccessClient + writeHooks WriteAccessHooks + lifecycle LifecycleHooks + now func() int64 + mostRecentRV atomic.Int64 // The most recent resource version seen by the server + storageMetrics *StorageMetrics // Background watch task -- this has permissions for everything ctx context.Context @@ -1073,10 +1073,12 @@ func (s *server) Watch(req *WatchRequest, srv ResourceStore_WatchServer) error { return err } - // record latency - resource version is a unix timestamp in microseconds so we convert to seconds - latencySeconds := float64(time.Now().UnixMicro()-event.ResourceVersion) / 1e6 - if latencySeconds > 0 { - StorageServerMetrics.WatchEventLatency.WithLabelValues(event.Key.Resource).Observe(latencySeconds) + if s.storageMetrics != nil { + // record latency - resource version is a unix timestamp in microseconds so we convert to seconds + latencySeconds := float64(time.Now().UnixMicro()-event.ResourceVersion) / 1e6 + if latencySeconds > 0 { + s.storageMetrics.WatchEventLatency.WithLabelValues(event.Key.Resource).Observe(latencySeconds) + } } } } diff --git a/pkg/storage/unified/sql/backend.go b/pkg/storage/unified/sql/backend.go index 3c4d1ab5164..f0ad22bbdff 100644 --- a/pkg/storage/unified/sql/backend.go +++ b/pkg/storage/unified/sql/backend.go @@ -40,6 +40,7 @@ type BackendOptions struct { PollingInterval time.Duration WatchBufferSize int IsHA bool + storageMetrics *resource.StorageMetrics // testing SimulatedNetworkLatency time.Duration // slows down the create transactions by a fixed amount @@ -69,6 +70,7 @@ func NewBackend(opts BackendOptions) (Backend, error) { dbProvider: opts.DBProvider, pollingInterval: opts.PollingInterval, watchBufferSize: opts.WatchBufferSize, + storageMetrics: opts.storageMetrics, bulkLock: &bulkLock{running: make(map[string]bool)}, simulatedNetworkLatency: opts.SimulatedNetworkLatency, }, nil @@ -85,8 +87,9 @@ type backend struct { initErr error // o11y - log log.Logger - tracer trace.Tracer + log log.Logger + tracer trace.Tracer + storageMetrics *resource.StorageMetrics // database dbProvider db.DBProvider diff --git a/pkg/storage/unified/sql/notifier.go b/pkg/storage/unified/sql/notifier.go index b7ba320122c..59cee87f642 100644 --- a/pkg/storage/unified/sql/notifier.go +++ b/pkg/storage/unified/sql/notifier.go @@ -31,6 +31,7 @@ func newNotifier(b *backend) (eventNotifier, error) { tracer: b.tracer, bulkLock: b.bulkLock, listLatestRVs: b.listLatestRVs, + storageMetrics: b.storageMetrics, historyPoll: func(ctx context.Context, grp string, res string, since int64) ([]*historyPollResponse, error) { var records []*historyPollResponse err := b.db.WithTx(ctx, ReadCommittedRO, func(ctx context.Context, tx db.Tx) error { diff --git a/pkg/storage/unified/sql/notifier_sql.go b/pkg/storage/unified/sql/notifier_sql.go index 98f2c1fe655..9170e87eec9 100644 --- a/pkg/storage/unified/sql/notifier_sql.go +++ b/pkg/storage/unified/sql/notifier_sql.go @@ -31,8 +31,9 @@ type pollingNotifier struct { pollingInterval time.Duration watchBufferSize int - log log.Logger - tracer trace.Tracer + log log.Logger + tracer trace.Tracer + storageMetrics *resource.StorageMetrics bulkLock *bulkLock listLatestRVs func(ctx context.Context) (groupResourceRV, error) @@ -46,8 +47,9 @@ type pollingNotifierConfig struct { pollingInterval time.Duration watchBufferSize int - log log.Logger - tracer trace.Tracer + log log.Logger + tracer trace.Tracer + storageMetrics *resource.StorageMetrics bulkLock *bulkLock listLatestRVs func(ctx context.Context) (groupResourceRV, error) @@ -101,6 +103,7 @@ func newPollingNotifier(cfg *pollingNotifierConfig) (*pollingNotifier, error) { listLatestRVs: cfg.listLatestRVs, historyPoll: cfg.historyPoll, done: cfg.done, + storageMetrics: cfg.storageMetrics, }, nil } @@ -172,7 +175,9 @@ func (p *pollingNotifier) poll(ctx context.Context, grp string, res string, sinc if err != nil { return 0, fmt.Errorf("poll history: %w", err) } - resource.NewStorageMetrics().PollerLatency.Observe(time.Since(start).Seconds()) + if p.storageMetrics != nil { + p.storageMetrics.PollerLatency.Observe(time.Since(start).Seconds()) + } var nextRV int64 for _, rec := range records { diff --git a/pkg/storage/unified/sql/server.go b/pkg/storage/unified/sql/server.go index 0bd5e6976a6..69738f96f21 100644 --- a/pkg/storage/unified/sql/server.go +++ b/pkg/storage/unified/sql/server.go @@ -18,7 +18,7 @@ import ( // Creates a new ResourceServer func NewResourceServer(db infraDB.DB, cfg *setting.Cfg, - tracer tracing.Tracer, reg prometheus.Registerer, ac types.AccessClient, searchOptions resource.SearchOptions) (resource.ResourceServer, error) { + tracer tracing.Tracer, reg prometheus.Registerer, ac types.AccessClient, searchOptions resource.SearchOptions, storageMetrics *resource.StorageMetrics) (resource.ResourceServer, error) { apiserverCfg := cfg.SectionWithEnvOverrides("grafana-apiserver") opts := resource.ResourceServerOptions{ Tracer: tracer, @@ -47,7 +47,7 @@ func NewResourceServer(db infraDB.DB, cfg *setting.Cfg, isHA := isHighAvailabilityEnabled(cfg.SectionWithEnvOverrides("database")) - store, err := NewBackend(BackendOptions{DBProvider: eDB, Tracer: tracer, IsHA: isHA}) + store, err := NewBackend(BackendOptions{DBProvider: eDB, Tracer: tracer, IsHA: isHA, storageMetrics: storageMetrics}) if err != nil { return nil, err } diff --git a/pkg/storage/unified/sql/service.go b/pkg/storage/unified/sql/service.go index 287f39f33d8..8decdf96055 100644 --- a/pkg/storage/unified/sql/service.go +++ b/pkg/storage/unified/sql/service.go @@ -49,8 +49,9 @@ type service struct { authenticator interceptors.Authenticator - log log.Logger - reg prometheus.Registerer + log log.Logger + reg prometheus.Registerer + storageMetrics *resource.StorageMetrics docBuilders resource.DocumentBuilderSupplier } @@ -62,6 +63,7 @@ func ProvideUnifiedStorageGrpcService( log log.Logger, reg prometheus.Registerer, docBuilders resource.DocumentBuilderSupplier, + storageMetrics *resource.StorageMetrics, ) (UnifiedStorageGrpcService, error) { tracingCfg, err := tracing.ProvideTracingConfig(cfg) if err != nil { @@ -84,15 +86,16 @@ func ProvideUnifiedStorageGrpcService( authn := grpcutils.NewAuthenticatorWithFallback(cfg, reg, tracing, &grpc.Authenticator{Tracer: tracing}) s := &service{ - cfg: cfg, - features: features, - stopCh: make(chan struct{}), - authenticator: authn, - tracing: tracing, - db: db, - log: log, - reg: reg, - docBuilders: docBuilders, + cfg: cfg, + features: features, + stopCh: make(chan struct{}), + authenticator: authn, + tracing: tracing, + db: db, + log: log, + reg: reg, + docBuilders: docBuilders, + storageMetrics: storageMetrics, } // This will be used when running as a dskit service @@ -112,7 +115,7 @@ func (s *service) start(ctx context.Context) error { return err } - server, err := NewResourceServer(s.db, s.cfg, s.tracing, s.reg, authzClient, searchOptions) + server, err := NewResourceServer(s.db, s.cfg, s.tracing, s.reg, authzClient, searchOptions, s.storageMetrics) if err != nil { return err } diff --git a/pkg/storage/unified/sql/test/integration_test.go b/pkg/storage/unified/sql/test/integration_test.go index d7679d1527c..64164300dea 100644 --- a/pkg/storage/unified/sql/test/integration_test.go +++ b/pkg/storage/unified/sql/test/integration_test.go @@ -83,7 +83,7 @@ func TestClientServer(t *testing.T) { features := featuremgmt.WithFeatures() - svc, err := sql.ProvideUnifiedStorageGrpcService(cfg, features, dbstore, nil, prometheus.NewPedanticRegistry(), nil) + svc, err := sql.ProvideUnifiedStorageGrpcService(cfg, features, dbstore, nil, prometheus.NewPedanticRegistry(), nil, nil) require.NoError(t, err) var client resource.ResourceStoreClient diff --git a/pkg/tests/testinfra/testinfra.go b/pkg/tests/testinfra/testinfra.go index eaeb4db521d..d0d0a574443 100644 --- a/pkg/tests/testinfra/testinfra.go +++ b/pkg/tests/testinfra/testinfra.go @@ -104,7 +104,7 @@ func StartGrafanaEnv(t *testing.T, grafDir, cfgPath string) (string, *server.Tes var storage sql.UnifiedStorageGrpcService if runstore { storage, err = sql.ProvideUnifiedStorageGrpcService(env.Cfg, env.FeatureToggles, env.SQLStore, - env.Cfg.Logger, prometheus.NewPedanticRegistry(), nil) + env.Cfg.Logger, prometheus.NewPedanticRegistry(), nil, nil) require.NoError(t, err) ctx := context.Background() err = storage.StartAsync(ctx) From ec29f6cb60204c6803d6354dc508ab91d01f72e2 Mon Sep 17 00:00:00 2001 From: xavi <114113189+volcanonoodle@users.noreply.github.com> Date: Fri, 28 Feb 2025 13:41:58 +0100 Subject: [PATCH 36/74] Add OpenAPI annotations for query params of `getOrgUsersForCurrentOrg` API route (#101419) --- pkg/api/org_users.go | 10 ++++++++++ public/api-merged.json | 13 +++++++++++++ public/openapi3.json | 17 +++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/pkg/api/org_users.go b/pkg/api/org_users.go index 1b83b4e3b77..4dd9e444fb3 100644 --- a/pkg/api/org_users.go +++ b/pkg/api/org_users.go @@ -542,6 +542,16 @@ type AddOrgUserParams struct { OrgID int64 `json:"org_id"` } +// swagger:parameters getOrgUsersForCurrentOrg +type GetOrgUsersForCurrentOrgParams struct { + // in:query + // required:false + Query string `json:"query"` + // in:query + // required:false + Limit int `json:"limit"` +} + // swagger:parameters getOrgUsersForCurrentOrgLookup type LookupOrgUsersParams struct { // in:query diff --git a/public/api-merged.json b/public/api-merged.json index 9ddc287f6f6..990ca6cbc86 100644 --- a/public/api-merged.json +++ b/public/api-merged.json @@ -6457,6 +6457,19 @@ ], "summary": "Get all users within the current organization.", "operationId": "getOrgUsersForCurrentOrg", + "parameters": [ + { + "type": "string", + "name": "query", + "in": "query" + }, + { + "type": "integer", + "format": "int64", + "name": "limit", + "in": "query" + } + ], "responses": { "200": { "$ref": "#/responses/getOrgUsersForCurrentOrgResponse" diff --git a/public/openapi3.json b/public/openapi3.json index 8f339a39b59..784e75b95cf 100644 --- a/public/openapi3.json +++ b/public/openapi3.json @@ -20308,6 +20308,23 @@ "get": { "description": "Returns all org users within the current organization. Accessible to users with org admin role.\nIf you are running Grafana Enterprise and have Fine-grained access control enabled\nyou need to have a permission with action: `org.users:read` with scope `users:*`.", "operationId": "getOrgUsersForCurrentOrg", + "parameters": [ + { + "in": "query", + "name": "query", + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "limit", + "schema": { + "format": "int64", + "type": "integer" + } + } + ], "responses": { "200": { "$ref": "#/components/responses/getOrgUsersForCurrentOrgResponse" From fc6f841942f387e30735732de560a6d120833922 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 28 Feb 2025 13:03:26 +0000 Subject: [PATCH 37/74] Update dependency @formatjs/intl-durationformat to v0.7.3 (#101456) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/yarn.lock b/yarn.lock index c1864d839a9..cb307fe09ce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2434,15 +2434,15 @@ __metadata: languageName: node linkType: hard -"@formatjs/ecma402-abstract@npm:2.3.2": - version: 2.3.2 - resolution: "@formatjs/ecma402-abstract@npm:2.3.2" +"@formatjs/ecma402-abstract@npm:2.3.3": + version: 2.3.3 + resolution: "@formatjs/ecma402-abstract@npm:2.3.3" dependencies: "@formatjs/fast-memoize": "npm:2.2.6" - "@formatjs/intl-localematcher": "npm:0.5.10" + "@formatjs/intl-localematcher": "npm:0.6.0" decimal.js: "npm:10" tslib: "npm:2" - checksum: 10/db31d3d9b36033ea11ec905638ac0c1d2282f5bf53c9c06ee1d0ffd924f4bf64030702c92b56261756c4998dfa6235462689d8eda82d5913f2d7cf636a9416ae + checksum: 10/c73a704d5cba3b929a9a303a04b4e8a708bb2dea000ee41808c55b22941a70da01b065697cbc5a25898b2007405abd71f414ab8c327fe953f63ae4120c2cc98d languageName: node linkType: hard @@ -2486,13 +2486,13 @@ __metadata: linkType: hard "@formatjs/intl-durationformat@npm:^0.7.0": - version: 0.7.2 - resolution: "@formatjs/intl-durationformat@npm:0.7.2" + version: 0.7.3 + resolution: "@formatjs/intl-durationformat@npm:0.7.3" dependencies: - "@formatjs/ecma402-abstract": "npm:2.3.2" - "@formatjs/intl-localematcher": "npm:0.5.10" + "@formatjs/ecma402-abstract": "npm:2.3.3" + "@formatjs/intl-localematcher": "npm:0.6.0" tslib: "npm:2" - checksum: 10/863784f3ac51779516fa29c87705af6d4f1b32191a2a48172d2ce16a99e385887a5641703a222ca2b1a0d334e1ab2587be5ef65f48c5ae8a16ba55138356a232 + checksum: 10/781c4f1574e01d2155ca90593b0605de883937ade3d5057a6adf19e21379fd80fb5985cf7115d348f572fb25b281add8d851fb9011fea770e9b1ea1cf5e9b5a1 languageName: node linkType: hard @@ -2505,12 +2505,12 @@ __metadata: languageName: node linkType: hard -"@formatjs/intl-localematcher@npm:0.5.10": - version: 0.5.10 - resolution: "@formatjs/intl-localematcher@npm:0.5.10" +"@formatjs/intl-localematcher@npm:0.6.0": + version: 0.6.0 + resolution: "@formatjs/intl-localematcher@npm:0.6.0" dependencies: tslib: "npm:2" - checksum: 10/119e36974607d5d3586570db93358c1f316c0736b83acc81dce88468435a9519a9e58a5abe6ed3078ffe40d6b4ad4613c6371e2a39cd570c9b6f561372ffb14d + checksum: 10/d8fd984c14121949d0ba60732a096aed6dccb2ab93770c4bffaea1170c85f5639d2a71fe6e2c68ab62bf6f3583a9c4b1fcd11bd5fb8837bfb2582228c33398c1 languageName: node linkType: hard From 9eaaf95701e5236620b1773ca60c5d2bb4d5ceee Mon Sep 17 00:00:00 2001 From: Matheus Macabu Date: Fri, 28 Feb 2025 15:11:11 +0100 Subject: [PATCH 38/74] Hackaton 12: Add some unit tests, take 1 (#101457) * tsdb/graphite: add happy path test for QueryData * infra/httpclient/httpclientprovider: add tests for RedirectLimitMiddleware --- ...ost_redirect_validation_middleware_test.go | 117 ++++++++++++++++++ pkg/tsdb/graphite/graphite_test.go | 73 +++++++++-- 2 files changed, 178 insertions(+), 12 deletions(-) create mode 100644 pkg/infra/httpclient/httpclientprovider/host_redirect_validation_middleware_test.go diff --git a/pkg/infra/httpclient/httpclientprovider/host_redirect_validation_middleware_test.go b/pkg/infra/httpclient/httpclientprovider/host_redirect_validation_middleware_test.go new file mode 100644 index 00000000000..ba6a473793a --- /dev/null +++ b/pkg/infra/httpclient/httpclientprovider/host_redirect_validation_middleware_test.go @@ -0,0 +1,117 @@ +package httpclientprovider + +import ( + "errors" + "net/http" + "net/http/httptest" + "testing" + + "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" + "github.com/stretchr/testify/require" +) + +func TestRedirectLimitMiddleware(t *testing.T) { + t.Parallel() + + t.Run("when the server responds with a status code 3xx", func(t *testing.T) { + t.Parallel() + + t.Run("but there is no Location header in the response, then the response is not validated", func(t *testing.T) { + t.Parallel() + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusTemporaryRedirect) + })) + t.Cleanup(server.Close) + + mw := RedirectLimitMiddleware(&fakeValidator{err: errors.New("this wont be called")}) + rt := mw.CreateMiddleware(httpclient.Options{}, http.DefaultTransport) + require.NotNil(t, rt) + + middlewareName, ok := mw.(httpclient.MiddlewareName) + require.True(t, ok) + require.Equal(t, HostRedirectValidationMiddlewareName, middlewareName.MiddlewareName()) + + req, err := http.NewRequest(http.MethodGet, server.URL, nil) + require.NoError(t, err) + + res, err := rt.RoundTrip(req) + require.NoError(t, err) + require.NotNil(t, res) + + if res.Body != nil { + require.NoError(t, res.Body.Close()) + } + }) + + t.Run("and there is a Location header in the response", func(t *testing.T) { + t.Parallel() + + t.Run("but the validation function fails, it returns the validation error", func(t *testing.T) { + t.Parallel() + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Location", "http://www.example.com") + w.WriteHeader(http.StatusTemporaryRedirect) + })) + t.Cleanup(server.Close) + + fakeErr := errors.New("fake error") + + mw := RedirectLimitMiddleware(&fakeValidator{err: fakeErr}) + rt := mw.CreateMiddleware(httpclient.Options{}, http.DefaultTransport) + require.NotNil(t, rt) + + middlewareName, ok := mw.(httpclient.MiddlewareName) + require.True(t, ok) + require.Equal(t, HostRedirectValidationMiddlewareName, middlewareName.MiddlewareName()) + + req, err := http.NewRequest(http.MethodGet, server.URL, nil) + require.NoError(t, err) + + res, err := rt.RoundTrip(req) + require.ErrorIs(t, err, fakeErr) + require.Nil(t, res) + + if res != nil && res.Body != nil { + require.NoError(t, res.Body.Close()) + } + }) + + t.Run("and the validation function succeeds, it returns the response", func(t *testing.T) { + t.Parallel() + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Location", "http://www.example.com") + w.WriteHeader(http.StatusTemporaryRedirect) + })) + t.Cleanup(server.Close) + + mw := RedirectLimitMiddleware(&fakeValidator{}) + rt := mw.CreateMiddleware(httpclient.Options{}, http.DefaultTransport) + require.NotNil(t, rt) + + middlewareName, ok := mw.(httpclient.MiddlewareName) + require.True(t, ok) + require.Equal(t, HostRedirectValidationMiddlewareName, middlewareName.MiddlewareName()) + + req, err := http.NewRequest(http.MethodGet, server.URL, nil) + require.NoError(t, err) + + res, err := rt.RoundTrip(req) + require.NoError(t, err) + require.NotNil(t, res) + + if res.Body != nil { + require.NoError(t, res.Body.Close()) + } + }) + }) + }) +} + +type fakeValidator struct { + err error +} + +func (v *fakeValidator) Validate(_ string) error { return v.err } diff --git a/pkg/tsdb/graphite/graphite_test.go b/pkg/tsdb/graphite/graphite_test.go index 2bb94f71dea..e5946ac5cd3 100644 --- a/pkg/tsdb/graphite/graphite_test.go +++ b/pkg/tsdb/graphite/graphite_test.go @@ -6,18 +6,20 @@ import ( "fmt" "io" "net/http" + "net/http/httptest" "reflect" "strings" "testing" "time" "github.com/grafana/grafana-plugin-sdk-go/backend" - "github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt" "github.com/grafana/grafana-plugin-sdk-go/data" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/infra/httpclient" + "github.com/grafana/grafana/pkg/infra/tracing" ) func TestFixIntervalFormat(t *testing.T) { @@ -141,14 +143,71 @@ func TestProcessQueries(t *testing.T) { }, } - service.im = fakeInstanceManager{} + service := ProvideService(httpclient.NewProvider(), tracing.NewNoopTracerService()) + rsp, err := service.QueryData(context.Background(), &backend.QueryDataRequest{ + PluginContext: backend.PluginContext{ + DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{ + ID: 0, + URL: "http://localhost", + }, + }, Queries: queries, }) assert.NoError(t, err) expectedResponse := backend.ErrDataResponseWithSource(400, backend.ErrorSourceDownstream, "no query target found for the alert rule") assert.Equal(t, expectedResponse, rsp.Responses["A"]) }) + + t.Run("QueryData with no queries returns an error", func(t *testing.T) { + service := &Service{} + + rsp, err := service.QueryData(context.Background(), &backend.QueryDataRequest{}) + assert.Nil(t, rsp) + assert.Error(t, err) + }) + + t.Run("QueryData happy path with service provider and plugin context", func(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write([]byte(`[ + { + "target": "target A", + "tags": { "fooTag": "fooValue", "barTag": "barValue", "int": 100, "float": 3.14 }, + "datapoints": [[50, 1], [null, 2], [100, 3]] + } + ]`)) + })) + t.Cleanup(server.Close) + + service := ProvideService(httpclient.NewProvider(), tracing.NewNoopTracerService()) + + queries := []backend.DataQuery{ + { + RefID: "A", + JSON: []byte(`{ + "target": "app.grafana.*.dashboards.views.1M.count" + }`), + }, + { + RefID: "B", + JSON: []byte(`{ + "query": "app.grafana.*.dashboards.views.1M.count" + }`), + }, + } + + rsp, err := service.QueryData(context.Background(), &backend.QueryDataRequest{ + PluginContext: backend.PluginContext{ + DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{ + ID: 0, + URL: server.URL, + }, + }, + Queries: queries, + }) + assert.NoError(t, err) + assert.NotNil(t, rsp) + }) } func TestConvertResponses(t *testing.T) { @@ -289,13 +348,3 @@ func TestConvertResponses(t *testing.T) { require.Error(t, err) }) } - -type fakeInstanceManager struct{} - -func (f fakeInstanceManager) Get(_ context.Context, _ backend.PluginContext) (instancemgmt.Instance, error) { - return datasourceInfo{}, nil -} - -func (f fakeInstanceManager) Do(_ context.Context, _ backend.PluginContext, _ instancemgmt.InstanceCallbackFunc) error { - return nil -} From 879b1211366dc539c27ac44c90be6eadda5b86a5 Mon Sep 17 00:00:00 2001 From: Yuri Tseretyan Date: Fri, 28 Feb 2025 09:47:25 -0500 Subject: [PATCH 39/74] Alerting: Add GUID to alert rule tables (#101321) * add column guid to alert rule table and rule_guid to rule version table + populate the new field with UUID * update storage and domain models * patch GUID * ignore GUID in fingerprint tests --- pkg/services/ngalert/models/alert_rule.go | 9 +- .../ngalert/models/alert_rule_test.go | 9 ++ pkg/services/ngalert/models/testing.go | 8 ++ .../ngalert/schedule/registry_test.go | 4 +- pkg/services/ngalert/store/alert_rule.go | 6 ++ pkg/services/ngalert/store/compat.go | 4 + pkg/services/ngalert/store/deltas_test.go | 6 ++ pkg/services/ngalert/store/models.go | 7 +- .../sqlstore/migrations/migrations.go | 2 + .../ualert/alert_rule_version_guid_mig.go | 83 +++++++++++++++++++ .../sqlstore/migrations/ualert/tables.go | 6 +- 11 files changed, 138 insertions(+), 6 deletions(-) create mode 100644 pkg/services/sqlstore/migrations/ualert/alert_rule_version_guid_mig.go diff --git a/pkg/services/ngalert/models/alert_rule.go b/pkg/services/ngalert/models/alert_rule.go index cdbc2a35b20..743d2295389 100644 --- a/pkg/services/ngalert/models/alert_rule.go +++ b/pkg/services/ngalert/models/alert_rule.go @@ -266,7 +266,9 @@ func NewUserUID(requester interface{ GetIdentifier() string }) *UserUID { // AlertRule is the model for alert rules in unified alerting. type AlertRule struct { - ID int64 + ID int64 + // Uniquely identifies alert rule across all organizations and time + GUID string OrgID int64 Title string Condition string @@ -708,6 +710,7 @@ func (alertRule *AlertRule) Copy() *AlertRule { } result := AlertRule{ ID: alertRule.ID, + GUID: alertRule.GUID, OrgID: alertRule.OrgID, Title: alertRule.Title, Condition: alertRule.Condition, @@ -940,6 +943,10 @@ func PatchPartialAlertRule(existingRule *AlertRule, ruleToPatch *AlertRuleWithOp if !ruleToPatch.HasEditorSettings { ruleToPatch.Metadata.EditorSettings = existingRule.Metadata.EditorSettings } + + if ruleToPatch.GUID == "" { + ruleToPatch.GUID = existingRule.GUID + } } func ValidateRuleGroupInterval(intervalSeconds, baseIntervalSeconds int64) error { diff --git a/pkg/services/ngalert/models/alert_rule_test.go b/pkg/services/ngalert/models/alert_rule_test.go index 84cbed48175..43d5092842a 100644 --- a/pkg/services/ngalert/models/alert_rule_test.go +++ b/pkg/services/ngalert/models/alert_rule_test.go @@ -418,6 +418,15 @@ func TestDiff(t *testing.T) { assert.Equal(t, rule2.ID, diff[0].Right.Int()) difCnt++ } + + if rule1.GUID != rule2.GUID { + diff := diffs.GetDiffsForField("GUID") + assert.Len(t, diff, 1) + assert.Equal(t, rule1.GUID, diff[0].Left.String()) + assert.Equal(t, rule2.GUID, diff[0].Right.String()) + difCnt++ + } + if rule1.OrgID != rule2.OrgID { diff := diffs.GetDiffsForField("OrgID") assert.Len(t, diff, 1) diff --git a/pkg/services/ngalert/models/testing.go b/pkg/services/ngalert/models/testing.go index 6d553057000..eb9d838f8df 100644 --- a/pkg/services/ngalert/models/testing.go +++ b/pkg/services/ngalert/models/testing.go @@ -11,6 +11,7 @@ import ( "time" "github.com/go-openapi/strfmt" + "github.com/google/uuid" alertingNotify "github.com/grafana/alerting/notify" "github.com/grafana/grafana-plugin-sdk-go/data" amv2 "github.com/prometheus/alertmanager/api/v2/models" @@ -103,6 +104,7 @@ func (g *AlertRuleGenerator) Generate() AlertRule { rule := AlertRule{ ID: 0, + GUID: uuid.NewString(), OrgID: rand.Int63n(1500) + 1, // Prevent OrgID=0 as this does not pass alert rule validation. Title: fmt.Sprintf("title-%s", util.GenerateShortUID()), Condition: "A", @@ -584,6 +586,12 @@ func (a *AlertRuleMutators) WithMetadata(meta AlertRuleMetadata) AlertRuleMutato } } +func (a AlertRuleMutators) WithGUID(guid string) AlertRuleMutator { + return func(r *AlertRule) { + r.GUID = guid + } +} + func (g *AlertRuleGenerator) GenerateLabels(min, max int, prefix string) data.Labels { count := max if min > max { diff --git a/pkg/services/ngalert/schedule/registry_test.go b/pkg/services/ngalert/schedule/registry_test.go index fb779c346ea..2a52f67b264 100644 --- a/pkg/services/ngalert/schedule/registry_test.go +++ b/pkg/services/ngalert/schedule/registry_test.go @@ -151,13 +151,14 @@ func TestRuleWithFolderFingerprint(t *testing.T) { f2 := ruleWithFolder{rule: rule, folderTitle: uuid.NewString()}.Fingerprint() require.NotEqual(t, f, f2) }) - t.Run("Version, Updated, IntervalSeconds and Annotations should be excluded from fingerprint", func(t *testing.T) { + t.Run("Version, Updated, IntervalSeconds, GUID and Annotations should be excluded from fingerprint", func(t *testing.T) { cp := models.CopyRule(rule) cp.Version++ cp.Updated = cp.Updated.Add(1 * time.Second) cp.IntervalSeconds++ cp.Annotations = make(map[string]string) cp.Annotations["test"] = "test" + cp.GUID = uuid.NewString() f2 := ruleWithFolder{rule: cp, folderTitle: title}.Fingerprint() require.Equal(t, f, f2) @@ -264,6 +265,7 @@ func TestRuleWithFolderFingerprint(t *testing.T) { "Annotations": {}, "ID": {}, "OrgID": {}, + "GUID": {}, } tp := reflect.TypeOf(rule).Elem() diff --git a/pkg/services/ngalert/store/alert_rule.go b/pkg/services/ngalert/store/alert_rule.go index c95c8de835f..b56c660876b 100644 --- a/pkg/services/ngalert/store/alert_rule.go +++ b/pkg/services/ngalert/store/alert_rule.go @@ -261,6 +261,11 @@ func (st DBstore) InsertAlertRules(ctx context.Context, user *ngmodels.UserUID, if err != nil { return fmt.Errorf("failed to convert alert rule %q to storage model: %w", r.Title, err) } + + // assign unique identifier that will identify resource across space and time. The probability of collision is so low that we do not need to check for uniqueness. + // The unique keys will ensure uniqueness in rule and versions tables + converted.GUID = uuid.NewString() + newRules = append(newRules, converted) ruleVersions = append(ruleVersions, alertRuleToAlertRuleVersion(converted)) } @@ -313,6 +318,7 @@ func (st DBstore) UpdateAlertRules(ctx context.Context, user *ngmodels.UserUID, r := rules[i] r.New.ID = r.Existing.ID r.New.Version = r.Existing.Version // xorm will take care of increasing it (see https://xorm.io/docs/chapter-06/1.lock/) + r.New.GUID = r.Existing.GUID if err := st.validateAlertRule(r.New); err != nil { return err } diff --git a/pkg/services/ngalert/store/compat.go b/pkg/services/ngalert/store/compat.go index cdb85d526c6..8021233ee93 100644 --- a/pkg/services/ngalert/store/compat.go +++ b/pkg/services/ngalert/store/compat.go @@ -20,6 +20,7 @@ func alertRuleToModelsAlertRule(ar alertRule, l log.Logger) (models.AlertRule, e result := models.AlertRule{ ID: ar.ID, OrgID: ar.OrgID, + GUID: ar.GUID, Title: ar.Title, Condition: ar.Condition, Data: data, @@ -107,6 +108,7 @@ func parseNotificationSettings(s string) ([]models.NotificationSettings, error) func alertRuleFromModelsAlertRule(ar models.AlertRule) (alertRule, error) { result := alertRule{ ID: ar.ID, + GUID: ar.GUID, OrgID: ar.OrgID, Title: ar.Title, Condition: ar.Condition, @@ -180,6 +182,7 @@ func alertRuleFromModelsAlertRule(ar models.AlertRule) (alertRule, error) { func alertRuleToAlertRuleVersion(rule alertRule) alertRuleVersion { return alertRuleVersion{ RuleOrgID: rule.OrgID, + RuleGUID: rule.GUID, RuleUID: rule.UID, RuleNamespaceUID: rule.NamespaceUID, RuleGroup: rule.RuleGroup, @@ -208,6 +211,7 @@ func alertRuleToAlertRuleVersion(rule alertRule) alertRuleVersion { func alertRuleVersionToAlertRule(version alertRuleVersion) alertRule { return alertRule{ ID: version.ID, + GUID: version.RuleGUID, OrgID: version.RuleOrgID, Title: version.Title, Condition: version.Condition, diff --git a/pkg/services/ngalert/store/deltas_test.go b/pkg/services/ngalert/store/deltas_test.go index 7381df4397a..dbfeb556ce4 100644 --- a/pkg/services/ngalert/store/deltas_test.go +++ b/pkg/services/ngalert/store/deltas_test.go @@ -169,6 +169,12 @@ func TestCalculateChanges(t *testing.T) { r.For = 0 }, }, + { + name: "GUID is empty", + mutator: func(r *models.AlertRule) { + r.GUID = "" + }, + }, } dbRule := gen.With(gen.WithOrgID(orgId)).GenerateRef() diff --git a/pkg/services/ngalert/store/models.go b/pkg/services/ngalert/store/models.go index ed9456036c2..8c5d44a9d8e 100644 --- a/pkg/services/ngalert/store/models.go +++ b/pkg/services/ngalert/store/models.go @@ -4,8 +4,9 @@ import "time" // alertRule represents a record in alert_rule table type alertRule struct { - ID int64 `xorm:"pk autoincr 'id'"` - OrgID int64 `xorm:"org_id"` + ID int64 `xorm:"pk autoincr 'id'"` + GUID string `xorm:"guid"` + OrgID int64 `xorm:"org_id"` Title string Condition string Data string @@ -38,6 +39,7 @@ func (a alertRule) TableName() string { type alertRuleVersion struct { ID int64 `xorm:"pk autoincr 'id'"` RuleOrgID int64 `xorm:"rule_org_id"` + RuleGUID string `xorm:"rule_guid"` RuleUID string `xorm:"rule_uid"` RuleNamespaceUID string `xorm:"rule_namespace_uid"` RuleGroup string @@ -69,6 +71,7 @@ type alertRuleVersion struct { // The comparison is very basic and can produce false-negative. Fields excluded: ID, ParentVersion, RestoredFrom, Version, Created and CreatedBy func (a alertRuleVersion) EqualSpec(b alertRuleVersion) bool { return a.RuleOrgID == b.RuleOrgID && + a.RuleGUID == b.RuleGUID && a.RuleUID == b.RuleUID && a.RuleNamespaceUID == b.RuleNamespaceUID && a.RuleGroup == b.RuleGroup && diff --git a/pkg/services/sqlstore/migrations/migrations.go b/pkg/services/sqlstore/migrations/migrations.go index 40704dac838..47cc25c2888 100644 --- a/pkg/services/sqlstore/migrations/migrations.go +++ b/pkg/services/sqlstore/migrations/migrations.go @@ -145,4 +145,6 @@ func (oss *OSSMigrations) AddMigration(mg *Migrator) { ualert.AddAlertRuleUpdatedByMigration(mg) ualert.AddAlertRuleStateTable(mg) + + ualert.AddAlertRuleGuidMigration(mg) } diff --git a/pkg/services/sqlstore/migrations/ualert/alert_rule_version_guid_mig.go b/pkg/services/sqlstore/migrations/ualert/alert_rule_version_guid_mig.go new file mode 100644 index 00000000000..600167f4829 --- /dev/null +++ b/pkg/services/sqlstore/migrations/ualert/alert_rule_version_guid_mig.go @@ -0,0 +1,83 @@ +package ualert + +import ( + "github.com/google/uuid" + + "github.com/grafana/grafana/pkg/services/sqlstore/migrator" + "xorm.io/xorm" +) + +// AddAlertRuleGuidMigration sets up migrations for adding and managing GUID columns in alert_rule and alert_rule_version tables. +func AddAlertRuleGuidMigration(mg *migrator.Migrator) { + alertRuleVersion := migrator.Table{Name: "alert_rule_version"} + alertRule := migrator.Table{Name: "alert_rule"} + mg.AddMigration("add guid column to alert_rule table", migrator.NewAddColumnMigration(alertRule, &migrator.Column{ + Name: "guid", + Type: migrator.DB_Varchar, + Length: 36, + Nullable: false, + Default: "''", + })) + mg.AddMigration("add rule_guid column to alert_rule_version table", migrator.NewAddColumnMigration(alertRuleVersion, &migrator.Column{ + Name: "rule_guid", + Type: migrator.DB_Varchar, + Length: 36, + Nullable: false, + Default: "''", + })) + mg.AddMigration("drop index in alert_rule_version table on rule_org_id, rule_uid and version columns", migrator.NewDropIndexMigration(alertRuleVersion, alertRuleVersionUDX_OrgIdRuleUIDVersion)) + + mg.AddMigration("populate rule guid in alert rule table", &setRuleGuidMigration{}) + + mg.AddMigration("add index in alert_rule_version table on rule_org_id, rule_uid, rule_guid and version columns", + migrator.NewAddIndexMigration(alertRuleVersion, + &migrator.Index{Cols: []string{"rule_org_id", "rule_uid", "rule_guid", "version"}, Type: migrator.UniqueIndex}, + ), + ) + + mg.AddMigration("add index in alert_rule_version table on rule_guid and version columns", + migrator.NewAddIndexMigration(alertRuleVersion, + &migrator.Index{Cols: []string{"rule_guid", "version"}, Type: migrator.UniqueIndex}, + ), + ) + + mg.AddMigration("add index in alert_rule table on guid columns", + migrator.NewAddIndexMigration(alertRule, + &migrator.Index{Cols: []string{"guid"}, Type: migrator.UniqueIndex}, + )) +} + +type setRuleGuidMigration struct { + migrator.MigrationBase +} + +var _ migrator.CodeMigration = (*setRuleGuidMigration)(nil) + +func (c setRuleGuidMigration) SQL(migrator.Dialect) string { + return codeMigration +} + +func (c setRuleGuidMigration) Exec(sess *xorm.Session, mg *migrator.Migrator) error { + var results []string + if err := sess.SQL("SELECT uid FROM alert_rule").Find(&results); err != nil { + return err + } + if len(results) == 0 { + mg.Logger.Debug("no rules found") + return nil + } + for _, uid := range results { + u := uuid.NewString() + _, err := sess.Exec("UPDATE alert_rule_version SET rule_guid = ? WHERE rule_uid = ?", u, uid) + if err != nil { + mg.Logger.Error("Failed to update alert_rule_version table", "error", err) + return err + } + _, err = sess.Exec("UPDATE alert_rule SET guid = ? WHERE uid = ?", u, uid) + if err != nil { + mg.Logger.Error("Failed to update alert_rule table", "error", err) + return err + } + } + return nil +} diff --git a/pkg/services/sqlstore/migrations/ualert/tables.go b/pkg/services/sqlstore/migrations/ualert/tables.go index 1ef0587efe3..023deb2a3cb 100644 --- a/pkg/services/sqlstore/migrations/ualert/tables.go +++ b/pkg/services/sqlstore/migrations/ualert/tables.go @@ -302,6 +302,8 @@ func addAlertRuleMigrations(mg *migrator.Migrator, defaultIntervalSeconds int64) UPDATE alert_rule SET is_paused = false;`)) } +var alertRuleVersionUDX_OrgIdRuleUIDVersion = &migrator.Index{Cols: []string{"rule_org_id", "rule_uid", "version"}, Type: migrator.UniqueIndex} + func addAlertRuleVersionMigrations(mg *migrator.Migrator) { // DO NOT EDIT alertRuleVersion := migrator.Table{ @@ -325,12 +327,12 @@ func addAlertRuleVersionMigrations(mg *migrator.Migrator) { {Name: "exec_err_state", Type: migrator.DB_NVarchar, Length: 15, Nullable: false, Default: "'Alerting'"}, }, Indices: []*migrator.Index{ - {Cols: []string{"rule_org_id", "rule_uid", "version"}, Type: migrator.UniqueIndex}, + alertRuleVersionUDX_OrgIdRuleUIDVersion, {Cols: []string{"rule_org_id", "rule_namespace_uid", "rule_group"}, Type: migrator.IndexType}, }, } mg.AddMigration("create alert_rule_version table", migrator.NewAddTableMigration(alertRuleVersion)) - mg.AddMigration("add index in alert_rule_version table on rule_org_id, rule_uid and version columns", migrator.NewAddIndexMigration(alertRuleVersion, alertRuleVersion.Indices[0])) + mg.AddMigration("add index in alert_rule_version table on rule_org_id, rule_uid and version columns", migrator.NewAddIndexMigration(alertRuleVersion, alertRuleVersionUDX_OrgIdRuleUIDVersion)) mg.AddMigration("add index in alert_rule_version table on rule_org_id, rule_namespace_uid and rule_group columns", migrator.NewAddIndexMigration(alertRuleVersion, alertRuleVersion.Indices[1])) mg.AddMigration("alter alert_rule_version table data column to mediumtext in mysql", migrator.NewRawSQLMigration(""). From 620d21385630b1c809889ee3116e688dcecf78c7 Mon Sep 17 00:00:00 2001 From: Todd Treece <360020+toddtreece@users.noreply.github.com> Date: Fri, 28 Feb 2025 10:39:41 -0500 Subject: [PATCH 40/74] K8s: Set priority for aggregated discovery (#101427) --- pkg/services/apiserver/builder/helper.go | 12 ++++++++++++ pkg/services/apiserver/service.go | 9 ++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/pkg/services/apiserver/builder/helper.go b/pkg/services/apiserver/builder/helper.go index 8f6fe0e3783..5fdf11c51a8 100644 --- a/pkg/services/apiserver/builder/helper.go +++ b/pkg/services/apiserver/builder/helper.go @@ -245,6 +245,18 @@ func SetupConfig( serverConfig.EffectiveVersion = v + // set priority for aggregated discovery + for i, b := range builders { + gvs := GetGroupVersions(b) + if len(gvs) == 0 { + return fmt.Errorf("builder did not return any API group versions: %T", b) + } + pvs := scheme.PrioritizedVersionsForGroup(gvs[0].Group) + for j, gv := range pvs { + serverConfig.AggregatedDiscoveryGroupManager.SetGroupVersionPriority(metav1.GroupVersion(gv), 15000+i, len(pvs)-j) + } + } + if err := AddPostStartHooks(serverConfig, builders); err != nil { return err } diff --git a/pkg/services/apiserver/service.go b/pkg/services/apiserver/service.go index dd9d39874e8..1105604aee1 100644 --- a/pkg/services/apiserver/service.go +++ b/pkg/services/apiserver/service.go @@ -278,18 +278,21 @@ func (s *service) start(ctx context.Context) error { groupVersions := make([]schema.GroupVersion, 0, len(builders)) // Install schemas - initialSize := len(kubeaggregator.APIVersionPriorities) for i, b := range builders { gvs := builder.GetGroupVersions(b) groupVersions = append(groupVersions, gvs...) + if len(gvs) == 0 { + return fmt.Errorf("no group versions found for builder %T", b) + } if err := b.InstallSchema(Scheme); err != nil { return err } + pvs := Scheme.PrioritizedVersionsForGroup(gvs[0].Group) - for _, gv := range gvs { + for j, gv := range pvs { if s.features.IsEnabledGlobally(featuremgmt.FlagKubernetesAggregator) { // set the priority for the group+version - kubeaggregator.APIVersionPriorities[gv] = kubeaggregator.Priority{Group: 15000, Version: int32(i + initialSize)} + kubeaggregator.APIVersionPriorities[gv] = kubeaggregator.Priority{Group: int32(15000 + i), Version: int32(len(pvs) - j)} } if a, ok := b.(builder.APIGroupAuthorizer); ok { From 87a9188bb481be8f666c15e9002b07a32ce2e0ff Mon Sep 17 00:00:00 2001 From: Drew Slobodnjak <60050885+drew08t@users.noreply.github.com> Date: Fri, 28 Feb 2025 08:13:20 -0800 Subject: [PATCH 41/74] Geomap: Fix Fit to Data for Route Layer (#101391) * Geomap: Fix Fit to Data for Route Layer * Update gdev panel tests to cover fit to data * Add layer value to layer select value --- .../panel-geomap/geomap-route-layer.json | 209 +++++++++++++----- .../panel/geomap/editor/FitMapViewEditor.tsx | 2 +- .../panel/geomap/utils/getLayersExtent.ts | 34 ++- 3 files changed, 187 insertions(+), 58 deletions(-) diff --git a/devenv/dev-dashboards/panel-geomap/geomap-route-layer.json b/devenv/dev-dashboards/panel-geomap/geomap-route-layer.json index f91036ace8b..c6b1752bd2a 100644 --- a/devenv/dev-dashboards/panel-geomap/geomap-route-layer.json +++ b/devenv/dev-dashboards/panel-geomap/geomap-route-layer.json @@ -29,20 +29,22 @@ "liveNow": false, "panels": [ { - "datasource": { - "type": "testdata", - "uid": "PD8C576611E62080A" + "id": 2, + "type": "geomap", + "title": "Multiple Layer Types", + "gridPos": { + "x": 0, + "y": 0, + "h": 16, + "w": 18 }, "fieldConfig": { "defaults": { - "color": { - "mode": "continuous-RdYlGr" - }, "custom": { "hideFrom": { - "legend": false, "tooltip": false, - "viz": false + "viz": false, + "legend": false } }, "mappings": [], @@ -51,7 +53,7 @@ "steps": [ { "color": "dark-red", - "value": 0 + "value": null }, { "color": "yellow", @@ -62,18 +64,59 @@ "value": 100 } ] + }, + "color": { + "mode": "continuous-RdYlGr" } }, "overrides": [] }, - "gridPos": { - "h": 16, - "w": 18, - "x": 0, - "y": 0 + "pluginVersion": "11.6.0-pre", + "targets": [ + { + "csvContent": "lat,lon,val\n-5,2,0\n1,5,25\n6,10,50\n9,15,75\n10,20,100", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_content" + }, + { + "scenarioId": "csv_content", + "refId": "B", + "datasource": { + "uid": "PD8C576611E62080A", + "type": "grafana-testdata-datasource" + }, + "csvContent": "lat,lon,alt\n45,0,0\n40,5,5\n35,10,10\n30,15, 15\n25,20,20" + } + ], + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" }, - "id": 2, "options": { + "view": { + "allLayers": true, + "id": "fit", + "lat": 2.359794, + "lon": 8.135816, + "zoom": 15, + "lastOnly": false, + "layer": "markers" + }, + "controls": { + "showZoom": true, + "mouseWheelZoom": true, + "showAttribution": true, + "showScale": false, + "showMeasure": false, + "showDebug": false + }, + "tooltip": { + "mode": "details" + }, "basemap": { "config": { "server": "streets" @@ -81,14 +124,6 @@ "name": "Layer 0", "type": "esri-xyz" }, - "controls": { - "mouseWheelZoom": true, - "showAttribution": true, - "showDebug": false, - "showMeasure": false, - "showScale": false, - "showZoom": true - }, "layers": [ { "config": { @@ -128,36 +163,108 @@ "location": { "mode": "auto" }, - "name": "Layer 2", + "name": "route", "tooltip": true, "type": "route" - } - ], - "tooltip": { - "mode": "details" - }, - "view": { - "allLayers": true, - "id": "coords", - "lat": 2.359794, - "lon": 8.135816, - "zoom": 4.45 - } - }, - "pluginVersion": "9.4.0-pre", - "targets": [ - { - "csvContent": "lat,lon,val\n-5,2,0\n1,5,25\n6,10,50\n9,15,75\n10,20,100", - "datasource": { - "type": "testdata", - "uid": "PD8C576611E62080A" }, - "refId": "A", - "scenarioId": "csv_content" - } - ], - "title": "Route with Colors", - "type": "geomap" + { + "type": "geojson", + "name": "geojson", + "config": { + "src": "public/maps/example-with-style.geojson", + "rules": [], + "style": { + "size": { + "fixed": 5, + "min": 2, + "max": 15 + }, + "color": { + "fixed": "dark-green" + }, + "opacity": 0.4, + "symbol": { + "mode": "fixed", + "fixed": "img/icons/marker/circle.svg" + }, + "symbolAlign": { + "horizontal": "center", + "vertical": "center" + }, + "textConfig": { + "fontSize": 12, + "textAlign": "center", + "textBaseline": "middle", + "offsetX": 0, + "offsetY": 0 + }, + "rotation": { + "fixed": 0, + "mode": "mod", + "min": -360, + "max": 360 + } + } + }, + "location": { + "mode": "auto" + }, + "tooltip": true, + "filterData": { + "id": "byRefId", + "options": "B" + } + }, + { + "type": "markers", + "name": "markers", + "config": { + "style": { + "size": { + "fixed": 5, + "min": 2, + "max": 15 + }, + "color": { + "fixed": "dark-green", + "field": "alt" + }, + "opacity": 0.4, + "symbol": { + "mode": "fixed", + "fixed": "img/icons/marker/circle.svg" + }, + "symbolAlign": { + "horizontal": "center", + "vertical": "center" + }, + "textConfig": { + "fontSize": 12, + "textAlign": "center", + "textBaseline": "middle", + "offsetX": 0, + "offsetY": 0 + }, + "rotation": { + "fixed": 0, + "mode": "mod", + "min": -360, + "max": 360 + } + }, + "showLegend": true + }, + "location": { + "mode": "auto" + }, + "tooltip": true, + "filterData": { + "id": "byRefId", + "options": "B" + } + } + ] + } } ], "schemaVersion": 37, @@ -171,7 +278,7 @@ }, "timepicker": {}, "timezone": "", - "title": "Panel Tests - Geomap Route Layer", + "title": "Panel Tests - Geomap Fit to Data - Multiple Layer Types", "uid": "OYTKK3DVk", "version": 25, "weekStart": "" diff --git a/public/app/plugins/panel/geomap/editor/FitMapViewEditor.tsx b/public/app/plugins/panel/geomap/editor/FitMapViewEditor.tsx index 51817507c8a..d0a05b262af 100644 --- a/public/app/plugins/panel/geomap/editor/FitMapViewEditor.tsx +++ b/public/app/plugins/panel/geomap/editor/FitMapViewEditor.tsx @@ -54,7 +54,7 @@ export const FitMapViewEditor = ({ labelWidth, value, onChange, context }: Props const allLayersEditorFragment = ( - ); diff --git a/public/app/plugins/panel/geomap/utils/getLayersExtent.ts b/public/app/plugins/panel/geomap/utils/getLayersExtent.ts index 2ab535a61d7..ed5a46442d9 100644 --- a/public/app/plugins/panel/geomap/utils/getLayersExtent.ts +++ b/public/app/plugins/panel/geomap/utils/getLayersExtent.ts @@ -14,14 +14,19 @@ export function getLayersExtent( return layers .filter((l) => l.layer instanceof VectorLayer || l.layer instanceof LayerGroup || l.layer instanceof VectorImage) .flatMap((ll) => { + const layerName = ll.options.name; const l = ll.layer; if (l instanceof LayerGroup) { - return getLayerGroupExtent(l); + // If not all layers check for matching layer name + if (!allLayers && layerName !== layer) { + return []; + } + return getLayerGroupExtent(l, lastOnly); } else if (l instanceof VectorLayer || l instanceof VectorImage) { if (allLayers) { // Return everything from all layers return [l.getSource().getExtent()]; - } else if (lastOnly && layer === ll.options.name) { + } else if (lastOnly && layer === layerName) { // Return last only for selected layer const feat = l.getSource().getFeatures(); const featOfInterest = feat[feat.length - 1]; @@ -30,7 +35,7 @@ export function getLayersExtent( return [geo.getExtent()]; } return []; - } else if (!lastOnly && layer === ll.options.name) { + } else if (!lastOnly && layer === layerName) { // Return all points for selected layer return [l.getSource().getExtent()]; } @@ -42,13 +47,30 @@ export function getLayersExtent( .reduce(extend, createEmpty()); } -export function getLayerGroupExtent(lg: LayerGroup) { +export function getLayerGroupExtent(lg: LayerGroup, lastOnly: boolean) { return lg .getLayers() .getArray() - .filter((l) => l instanceof VectorLayer) + .filter((l) => l instanceof VectorLayer || l instanceof VectorImage) .map((l) => { - if (l instanceof VectorLayer) { + if (l instanceof VectorLayer || l instanceof VectorImage) { + if (lastOnly) { + // Return last coordinate only + const feat = l.getSource().getFeatures(); + const featOfInterest = feat[feat.length - 1]; + const geo = featOfInterest?.getGeometry(); + if (geo) { + // Look at flatCoordinates for more robust support including route layer + const flatCoordinates = geo.flatCoordinates; + const flatCoordinatesLength = flatCoordinates.length; + if (flatCoordinatesLength > 1) { + const lastX = flatCoordinates[flatCoordinatesLength - 2]; + const lastY = flatCoordinates[flatCoordinatesLength - 1]; + return [lastX, lastY, lastX, lastY]; + } + } + return []; + } return l.getSource().getExtent() ?? []; } else { return []; From 1d54850a682c9f8131e8bb6e06a99ad53393182c Mon Sep 17 00:00:00 2001 From: Yuri Tseretyan Date: Fri, 28 Feb 2025 11:27:46 -0500 Subject: [PATCH 42/74] Alerting: Get alert rule versions by GUID (#101469) * get alert rule versions by GUID * protect guid field from accidental update --- pkg/services/ngalert/api/api_ruler.go | 4 ++-- pkg/services/ngalert/api/api_ruler_test.go | 20 +++++++++++-------- pkg/services/ngalert/api/persist.go | 2 +- pkg/services/ngalert/store/alert_rule.go | 6 +++--- pkg/services/ngalert/store/alert_rule_test.go | 4 ++-- pkg/services/ngalert/tests/fakes/rules.go | 14 ++++++------- 6 files changed, 27 insertions(+), 23 deletions(-) diff --git a/pkg/services/ngalert/api/api_ruler.go b/pkg/services/ngalert/api/api_ruler.go index 12d6b63c198..359b3c1a5b7 100644 --- a/pkg/services/ngalert/api/api_ruler.go +++ b/pkg/services/ngalert/api/api_ruler.go @@ -339,7 +339,7 @@ func (srv RulerSrv) RouteGetRuleByUID(c *contextmodel.ReqContext, ruleUID string func (srv RulerSrv) RouteGetRuleVersionsByUID(c *contextmodel.ReqContext, ruleUID string) response.Response { ctx := c.Req.Context() // make sure the user has access to the current version of the rule. Also, check if it exists - _, err := srv.getAuthorizedRuleByUid(ctx, c, ruleUID) + rule, err := srv.getAuthorizedRuleByUid(ctx, c, ruleUID) if err != nil { if errors.Is(err, ngmodels.ErrAlertRuleNotFound) { return response.Empty(http.StatusNotFound) @@ -347,7 +347,7 @@ func (srv RulerSrv) RouteGetRuleVersionsByUID(c *contextmodel.ReqContext, ruleUI return response.ErrOrFallback(http.StatusInternalServerError, "failed to get rule by UID", err) } - rules, err := srv.store.GetAlertRuleVersions(ctx, ngmodels.AlertRuleKey{OrgID: c.OrgID, UID: ruleUID}) + rules, err := srv.store.GetAlertRuleVersions(ctx, rule.OrgID, rule.GUID) if err != nil { return response.ErrOrFallback(http.StatusInternalServerError, "failed to get rule history", err) } diff --git a/pkg/services/ngalert/api/api_ruler_test.go b/pkg/services/ngalert/api/api_ruler_test.go index e61258a7110..17b0d8334ab 100644 --- a/pkg/services/ngalert/api/api_ruler_test.go +++ b/pkg/services/ngalert/api/api_ruler_test.go @@ -13,6 +13,7 @@ import ( "testing" "time" + "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -486,7 +487,7 @@ func TestRouteGetRuleHistoryByUID(t *testing.T) { } ruleStore.PutRule(context.Background(), rule) - ruleStore.History[rule.GetKey()] = append(ruleStore.History[rule.GetKey()], history...) + ruleStore.History[rule.GUID] = append(ruleStore.History[rule.GUID], history...) perms := createPermissionsForRules([]*models.AlertRule{rule}, orgID) req := createRequestContextWithPerms(orgID, perms, nil) @@ -516,8 +517,9 @@ func TestRouteGetRuleHistoryByUID(t *testing.T) { OrgID: orgID, UID: "test", } - history := gen.With(gen.WithKey(ruleKey)).GenerateManyRef(3) - ruleStore.History[ruleKey] = append(ruleStore.History[ruleKey], history...) // even if history is full of records + guid := uuid.NewString() + history := gen.With(gen.WithGUID(guid), gen.WithKey(ruleKey)).GenerateManyRef(3) + ruleStore.History[guid] = append(ruleStore.History[guid], history...) // even if history is full of records perms := createPermissionsForRules(history, orgID) req := createRequestContextWithPerms(orgID, perms, nil) @@ -533,9 +535,10 @@ func TestRouteGetRuleHistoryByUID(t *testing.T) { OrgID: orgID, UID: "test", } - rule := gen.With(gen.WithKey(ruleKey)).GenerateRef() + guid := uuid.NewString() + rule := gen.With(gen.WithKey(ruleKey), gen.WithGUID(guid)).GenerateRef() ruleStore.PutRule(context.Background(), rule) - ruleStore.History[ruleKey] = nil + ruleStore.History[guid] = nil perms := createPermissionsForRules([]*models.AlertRule{rule}, orgID) req := createRequestContextWithPerms(orgID, perms, nil) @@ -556,10 +559,11 @@ func TestRouteGetRuleHistoryByUID(t *testing.T) { OrgID: orgID, UID: "test", } - rule := gen.With(gen.WithKey(ruleKey), gen.WithNamespaceUID(anotherFolder.UID)).GenerateRef() + guid := uuid.NewString() + rule := gen.With(gen.WithGUID(guid), gen.WithKey(ruleKey), gen.WithNamespaceUID(anotherFolder.UID)).GenerateRef() ruleStore.PutRule(context.Background(), rule) - history := gen.With(gen.WithKey(ruleKey)).GenerateManyRef(3) - ruleStore.History[ruleKey] = history + history := gen.With(gen.WithGUID(guid), gen.WithKey(ruleKey)).GenerateManyRef(3) + ruleStore.History[guid] = history perms := createPermissionsForRules(history, orgID) // grant permissions to all records in history but not the rule itself req := createRequestContextWithPerms(orgID, perms, nil) diff --git a/pkg/services/ngalert/api/persist.go b/pkg/services/ngalert/api/persist.go index 57eda01631d..228f62cf24e 100644 --- a/pkg/services/ngalert/api/persist.go +++ b/pkg/services/ngalert/api/persist.go @@ -30,6 +30,6 @@ type RuleStore interface { // IncreaseVersionForAllRulesInNamespaces Increases version for all rules that have specified namespace uids IncreaseVersionForAllRulesInNamespaces(ctx context.Context, orgID int64, namespaceUIDs []string) ([]ngmodels.AlertRuleKeyWithVersion, error) - GetAlertRuleVersions(ctx context.Context, key ngmodels.AlertRuleKey) ([]*ngmodels.AlertRule, error) + GetAlertRuleVersions(ctx context.Context, orgID int64, guid string) ([]*ngmodels.AlertRule, error) accesscontrol.RuleUIDToNamespaceStore } diff --git a/pkg/services/ngalert/store/alert_rule.go b/pkg/services/ngalert/store/alert_rule.go index b56c660876b..7a97d7f02ca 100644 --- a/pkg/services/ngalert/store/alert_rule.go +++ b/pkg/services/ngalert/store/alert_rule.go @@ -125,10 +125,10 @@ func (st DBstore) GetAlertRuleByUID(ctx context.Context, query *ngmodels.GetAler return result, err } -func (st DBstore) GetAlertRuleVersions(ctx context.Context, key ngmodels.AlertRuleKey) ([]*ngmodels.AlertRule, error) { +func (st DBstore) GetAlertRuleVersions(ctx context.Context, orgID int64, guid string) ([]*ngmodels.AlertRule, error) { alertRules := make([]*ngmodels.AlertRule, 0) err := st.SQLStore.WithDbSession(ctx, func(sess *db.Session) error { - rows, err := sess.Table(new(alertRuleVersion)).Where("rule_org_id = ? AND rule_uid = ?", key.OrgID, key.UID).Asc("id").Rows(new(alertRuleVersion)) + rows, err := sess.Table(new(alertRuleVersion)).Where("rule_org_id = ? AND rule_guid = ?", orgID, guid).Asc("id").Rows(new(alertRuleVersion)) if err != nil { return err } @@ -330,7 +330,7 @@ func (st DBstore) UpdateAlertRules(ctx context.Context, user *ngmodels.UserUID, return fmt.Errorf("failed to convert alert rule %s to storage model: %w", r.New.UID, err) } // no way to update multiple rules at once - if updated, err := sess.ID(r.Existing.ID).AllCols().Update(converted); err != nil || updated == 0 { + if updated, err := sess.ID(r.Existing.ID).AllCols().Omit("rule_guid").Update(converted); err != nil || updated == 0 { if err != nil { if st.SQLStore.GetDialect().IsUniqueConstraintViolation(err) { return ruleConstraintViolationToErr(sess, r.New, err, st.Logger) diff --git a/pkg/services/ngalert/store/alert_rule_test.go b/pkg/services/ngalert/store/alert_rule_test.go index 1f833a3e10f..1e60dfc9249 100644 --- a/pkg/services/ngalert/store/alert_rule_test.go +++ b/pkg/services/ngalert/store/alert_rule_test.go @@ -1599,7 +1599,7 @@ func TestGetRuleVersions(t *testing.T) { require.NoError(t, err) t.Run("should return rule versions sorted in decreasing order", func(t *testing.T) { - versions, err := store.GetAlertRuleVersions(context.Background(), ruleV2.GetKey()) + versions, err := store.GetAlertRuleVersions(context.Background(), ruleV2.OrgID, ruleV2.GUID) require.NoError(t, err) assert.Len(t, versions, 2) assert.IsDecreasing(t, versions[0].ID, versions[1].ID) @@ -1630,7 +1630,7 @@ func TestGetRuleVersions(t *testing.T) { }, }) - versions, err := store.GetAlertRuleVersions(context.Background(), ruleV3.GetKey()) + versions, err := store.GetAlertRuleVersions(context.Background(), ruleV3.OrgID, ruleV3.GUID) require.NoError(t, err) assert.Len(t, versions, 3) diff := versions[0].Diff(versions[1], AlertRuleFieldsToIgnoreInDiff[:]...) diff --git a/pkg/services/ngalert/tests/fakes/rules.go b/pkg/services/ngalert/tests/fakes/rules.go index 728ae6bd76f..1a3e4ce9a63 100644 --- a/pkg/services/ngalert/tests/fakes/rules.go +++ b/pkg/services/ngalert/tests/fakes/rules.go @@ -23,7 +23,7 @@ type RuleStore struct { mtx sync.Mutex // OrgID -> RuleGroup -> Namespace -> Rules Rules map[int64][]*models.AlertRule - History map[models.AlertRuleKey][]*models.AlertRule + History map[string][]*models.AlertRule Hook func(cmd any) error // use Hook if you need to intercept some query and return an error RecordedOps []any Folders map[int64][]*folder.Folder @@ -42,7 +42,7 @@ func NewRuleStore(t *testing.T) *RuleStore { return nil }, Folders: map[int64][]*folder.Folder{}, - History: map[models.AlertRuleKey][]*models.AlertRule{}, + History: map[string][]*models.AlertRule{}, } } @@ -54,7 +54,7 @@ mainloop: for _, r := range rules { rgs := f.Rules[r.OrgID] cp := models.CopyRule(r) - f.History[r.GetKey()] = append(f.History[r.GetKey()], cp) + f.History[r.GUID] = append(f.History[r.GUID], cp) for idx, rulePtr := range rgs { if rulePtr.UID == r.UID { rgs[idx] = r @@ -426,21 +426,21 @@ func (f *RuleStore) GetNamespacesByRuleUID(ctx context.Context, orgID int64, uid return namespacesMap, nil } -func (f *RuleStore) GetAlertRuleVersions(_ context.Context, key models.AlertRuleKey) ([]*models.AlertRule, error) { +func (f *RuleStore) GetAlertRuleVersions(_ context.Context, orgID int64, guid string) ([]*models.AlertRule, error) { f.mtx.Lock() defer f.mtx.Unlock() q := GenericRecordedQuery{ Name: "GetAlertRuleVersions", - Params: []any{key}, + Params: []any{orgID, guid}, } defer func() { f.RecordedOps = append(f.RecordedOps, q) }() - if err := f.Hook(key); err != nil { + if err := f.Hook([]any{orgID, guid}); err != nil { return nil, err } - return f.History[key], nil + return f.History[guid], nil } From 10f17a296a091283a94859646df34167426424be Mon Sep 17 00:00:00 2001 From: Yuri Tseretyan Date: Fri, 28 Feb 2025 12:06:33 -0500 Subject: [PATCH 43/74] Alerting: Update Github Action to update alerting module to support version branches (#101472) --- .github/workflows/alerting-update-module.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/alerting-update-module.yml b/.github/workflows/alerting-update-module.yml index 1d919f3dc4b..213b243f9b1 100644 --- a/.github/workflows/alerting-update-module.yml +++ b/.github/workflows/alerting-update-module.yml @@ -38,14 +38,19 @@ jobs: FROM_COMMIT=$(go list -m -json github.com/grafana/alerting | jq -r '.Version' | grep -oP '(?<=-)[a-f0-9]+$') echo "from_commit=$FROM_COMMIT" >> $GITHUB_OUTPUT + - name: Get current branch name + id: current-branch-name + run: echo "name=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> "$GITHUB_OUTPUT" + - name: Get latest commit id: latest-commit env: GH_TOKEN: ${{ github.token }} run: | - TO_COMMIT=$(gh api repos/grafana/alerting/commits/main --jq '.sha') - if [ -z "$TO_COMMIT" ]; then - echo "Failed to fetch latest commit" + BRANCH="${{ steps.current-branch-name.outputs.name }}" + TO_COMMIT=$(gh api repos/grafana/alerting/commits/$BRANCH --jq '.sha') + if [ -z "$TO_COMMIT" ]; then + echo "Branch $BRANCH not found in alerting repo, falling back to main branch" exit 1 fi echo "to_commit=$TO_COMMIT" >> $GITHUB_OUTPUT From 2466685a41a8722335c3d81697b848fba31b50cd Mon Sep 17 00:00:00 2001 From: Matthew Jacobson Date: Fri, 28 Feb 2025 13:27:27 -0500 Subject: [PATCH 44/74] Alerting: Improve template testing by trying non-root scopes (#101471) Expand template testing to try additional scopes if the root scope fails. This mitigates errors for definitions like pagerduty.default.instances, which require the .Alerts scope. Added support for .Alerts and .Alert scopes. --- go.mod | 2 +- go.sum | 4 +- pkg/services/ngalert/api/api_alertmanager.go | 5 +- .../api/tooling/definitions/alertmanager.go | 13 ++++ .../ngalert/notifier/templates_test.go | 70 +++++++++++++++---- pkg/storage/unified/apistore/go.mod | 2 +- pkg/storage/unified/apistore/go.sum | 4 +- pkg/storage/unified/resource/go.mod | 2 +- pkg/storage/unified/resource/go.sum | 4 +- 9 files changed, 83 insertions(+), 23 deletions(-) diff --git a/go.mod b/go.mod index e664a31975a..1ddd0152b12 100644 --- a/go.mod +++ b/go.mod @@ -72,7 +72,7 @@ require ( github.com/googleapis/gax-go/v2 v2.14.1 // @grafana/grafana-backend-group github.com/gorilla/mux v1.8.1 // @grafana/grafana-backend-group github.com/gorilla/websocket v1.5.3 // @grafana/grafana-app-platform-squad - github.com/grafana/alerting v0.0.0-20250224133628-2acbeef29642 // @grafana/alerting-backend + github.com/grafana/alerting v0.0.0-20250225150117-15e285d78df2 // @grafana/alerting-backend github.com/grafana/authlib v0.0.0-20250225105729-99e678595501 // @grafana/identity-access-team github.com/grafana/authlib/types v0.0.0-20250224151205-5ef97131cc82 // @grafana/identity-access-team github.com/grafana/dataplane/examples v0.0.1 // @grafana/observability-metrics diff --git a/go.sum b/go.sum index 29c820b8964..21c166a08d9 100644 --- a/go.sum +++ b/go.sum @@ -1525,8 +1525,8 @@ github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7Fsg github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grafana/alerting v0.0.0-20250224133628-2acbeef29642 h1:iQ0h/h+QoguSZDF+ZpPxcM/C+m1kjh+aXjMpxywowPA= -github.com/grafana/alerting v0.0.0-20250224133628-2acbeef29642/go.mod h1:hdGB3dSl8Ma9Rjo2YiAEAjMkZ5HiNJbNDqRKDefRZrM= +github.com/grafana/alerting v0.0.0-20250225150117-15e285d78df2 h1:kESrzm0FcRVLmGIQCgl1MCwDGLH4sLzWphr7mcFdbfI= +github.com/grafana/alerting v0.0.0-20250225150117-15e285d78df2/go.mod h1:hdGB3dSl8Ma9Rjo2YiAEAjMkZ5HiNJbNDqRKDefRZrM= github.com/grafana/authlib v0.0.0-20250225105729-99e678595501 h1:FTuDRy/Shw8yOdG+v1DnkeuaCAl8fvwgcfaG9Wccuhg= github.com/grafana/authlib v0.0.0-20250225105729-99e678595501/go.mod h1:XVpdLhaeYqz414FmGnW00/0vTe1x8c0GRH3KaeRtyg0= github.com/grafana/authlib/types v0.0.0-20250224151205-5ef97131cc82 h1:DnRUYiAotHXnrfYJCvhH1NkiyWVcPm5Pd+P7Ugqt/d8= diff --git a/pkg/services/ngalert/api/api_alertmanager.go b/pkg/services/ngalert/api/api_alertmanager.go index 1d174a149c7..90c3843b65e 100644 --- a/pkg/services/ngalert/api/api_alertmanager.go +++ b/pkg/services/ngalert/api/api_alertmanager.go @@ -353,8 +353,9 @@ func newTestTemplateResult(res *notifier.TestTemplatesResults) apimodels.TestTem apiRes := apimodels.TestTemplatesResults{} for _, r := range res.Results { apiRes.Results = append(apiRes.Results, apimodels.TestTemplatesResult{ - Name: r.Name, - Text: r.Text, + Name: r.Name, + Text: r.Text, + Scope: apimodels.TemplateScope(r.Scope), }) } for _, e := range res.Errors { diff --git a/pkg/services/ngalert/api/tooling/definitions/alertmanager.go b/pkg/services/ngalert/api/tooling/definitions/alertmanager.go index 84d29dcb249..5a9c6a5b868 100644 --- a/pkg/services/ngalert/api/tooling/definitions/alertmanager.go +++ b/pkg/services/ngalert/api/tooling/definitions/alertmanager.go @@ -369,6 +369,10 @@ type TestTemplatesResult struct { // Interpolated value of the template. Text string `json:"text"` + + // Scope that was successfully used to interpolate the template. If the root scope "." fails, more specific + // scopes will be tried, such as ".Alerts', or ".Alert". + Scope TemplateScope `json:"scope"` } type TestTemplatesErrorResult struct { @@ -390,6 +394,15 @@ const ( ExecutionError TemplateErrorKind = "execution_error" ) +// swagger:enum TemplateScope +type TemplateScope string + +const ( + RootScope TemplateScope = "." + AlertsScope TemplateScope = ".Alerts" + AlertScope TemplateScope = ".Alert" +) + // swagger:parameters RouteCreateSilence RouteCreateGrafanaSilence type CreateSilenceParams struct { // in:body diff --git a/pkg/services/ngalert/notifier/templates_test.go b/pkg/services/ngalert/notifier/templates_test.go index a5806405642..fb266ac15f9 100644 --- a/pkg/services/ngalert/notifier/templates_test.go +++ b/pkg/services/ngalert/notifier/templates_test.go @@ -53,8 +53,9 @@ CommonAnnotations: {{ range .CommonAnnotations.SortedPairs }}{{ .Name }}={{ .Val }, expected: TestTemplatesResults{ Results: []alertingNotify.TestTemplatesResult{{ - Name: "slack.title", - Text: "\nReceiver: TestReceiver\nStatus: firing\nExternalURL: http://localhost:9093\nAlerts: 1\nFiring Alerts: 1\nResolved Alerts: 0\nGroupLabels: group_label=group_label_value \nCommonLabels: alertname=alert1 grafana_folder=folder title lbl1=val1 \nCommonAnnotations: ann1=annv1 \n", + Name: "slack.title", + Text: "\nReceiver: TestReceiver\nStatus: firing\nExternalURL: http://localhost:9093\nAlerts: 1\nFiring Alerts: 1\nResolved Alerts: 0\nGroupLabels: group_label=group_label_value \nCommonLabels: alertname=alert1 grafana_folder=folder title lbl1=val1 \nCommonAnnotations: ann1=annv1 \n", + Scope: alertingNotify.TemplateScope(apimodels.RootScope), }}, Errors: nil, }, @@ -67,8 +68,9 @@ CommonAnnotations: {{ range .CommonAnnotations.SortedPairs }}{{ .Name }}={{ .Val }, expected: TestTemplatesResults{ Results: []alertingNotify.TestTemplatesResult{{ - Name: "slack.title", - Text: DefaultLabels[prometheusModel.AlertNameLabel], + Name: "slack.title", + Text: DefaultLabels[prometheusModel.AlertNameLabel], + Scope: alertingNotify.TemplateScope(apimodels.RootScope), }}, Errors: nil, }, @@ -81,8 +83,9 @@ CommonAnnotations: {{ range .CommonAnnotations.SortedPairs }}{{ .Name }}={{ .Val }, expected: TestTemplatesResults{ Results: []alertingNotify.TestTemplatesResult{{ - Name: "slack.title", - Text: DefaultLabels[alertingModels.FolderTitleLabel], + Name: "slack.title", + Text: DefaultLabels[alertingModels.FolderTitleLabel], + Scope: alertingNotify.TemplateScope(apimodels.RootScope), }}, Errors: nil, }, @@ -95,8 +98,9 @@ CommonAnnotations: {{ range .CommonAnnotations.SortedPairs }}{{ .Name }}={{ .Val }, expected: TestTemplatesResults{ Results: []alertingNotify.TestTemplatesResult{{ - Name: "slack.title", - Text: "B=22 C=1 ", + Name: "slack.title", + Text: "B=22 C=1 ", + Scope: alertingNotify.TemplateScope(apimodels.RootScope), }}, Errors: nil, }, @@ -109,8 +113,9 @@ CommonAnnotations: {{ range .CommonAnnotations.SortedPairs }}{{ .Name }}={{ .Val }, expected: TestTemplatesResults{ Results: []alertingNotify.TestTemplatesResult{{ - Name: "slack.title", - Text: DefaultAnnotations[alertingModels.ValueStringAnnotation], + Name: "slack.title", + Text: DefaultAnnotations[alertingModels.ValueStringAnnotation], + Scope: alertingNotify.TemplateScope(apimodels.RootScope), }}, Errors: nil, }, @@ -127,6 +132,7 @@ CommonAnnotations: {{ range .CommonAnnotations.SortedPairs }}{{ .Name }}={{ .Val Text: fmt.Sprintf("http://localhost:9093/d/%s?orgId=%s", DefaultAnnotations[alertingModels.DashboardUIDAnnotation], DefaultAnnotations[alertingModels.OrgIDAnnotation]), + Scope: alertingNotify.TemplateScope(apimodels.RootScope), }}, Errors: nil, }, @@ -144,6 +150,7 @@ CommonAnnotations: {{ range .CommonAnnotations.SortedPairs }}{{ .Name }}={{ .Val DefaultAnnotations[alertingModels.DashboardUIDAnnotation], DefaultAnnotations[alertingModels.OrgIDAnnotation], DefaultAnnotations[alertingModels.PanelIDAnnotation]), + Scope: alertingNotify.TemplateScope(apimodels.RootScope), }}, Errors: nil, }, @@ -156,8 +163,47 @@ CommonAnnotations: {{ range .CommonAnnotations.SortedPairs }}{{ .Name }}={{ .Val }, expected: TestTemplatesResults{ Results: []alertingNotify.TestTemplatesResult{{ - Name: "slack.title", - Text: fmt.Sprintf("http://localhost:3000?orgId=%s", DefaultAnnotations[alertingModels.OrgIDAnnotation]), + Name: "slack.title", + Text: fmt.Sprintf("http://localhost:3000?orgId=%s", DefaultAnnotations[alertingModels.OrgIDAnnotation]), + Scope: alertingNotify.TemplateScope(apimodels.RootScope), + }}, + Errors: nil, + }, + }, { + name: "Alerts scoped templated ", + input: apimodels.TestTemplatesConfigBodyParams{ + Alerts: []*amv2.PostableAlert{{Alert: amv2.Alert{GeneratorURL: "http://localhost:3000"}}}, + Name: "slack.title", + Template: `{{ define "slack.title" }} + {{ range . }} + Status: {{ .Status }} + Starts at: {{ .StartsAt }} + {{ end }} +{{ end }}`, + }, + expected: TestTemplatesResults{ + Results: []alertingNotify.TestTemplatesResult{{ + Name: "slack.title", + Text: "\n\t\n\t\tStatus: firing\n\t\tStarts at: 0001-01-01 00:00:00 +0000 UTC\n\t\n", + Scope: alertingNotify.TemplateScope(apimodels.AlertsScope), + }}, + Errors: nil, + }, + }, { + name: "Alert scoped templated ", + input: apimodels.TestTemplatesConfigBodyParams{ + Alerts: []*amv2.PostableAlert{{Alert: amv2.Alert{GeneratorURL: "http://localhost:3000"}}}, + Name: "slack.title", + Template: `{{ define "slack.title" }} + Status: {{ .Status }} + Starts at: {{ .StartsAt }} +{{ end }}`, + }, + expected: TestTemplatesResults{ + Results: []alertingNotify.TestTemplatesResult{{ + Name: "slack.title", + Text: "\n\tStatus: firing\n\tStarts at: 0001-01-01 00:00:00 +0000 UTC\n", + Scope: alertingNotify.TemplateScope(apimodels.AlertScope), }}, Errors: nil, }, diff --git a/pkg/storage/unified/apistore/go.mod b/pkg/storage/unified/apistore/go.mod index c515663008a..bc3820efab7 100644 --- a/pkg/storage/unified/apistore/go.mod +++ b/pkg/storage/unified/apistore/go.mod @@ -192,7 +192,7 @@ require ( github.com/googleapis/gax-go/v2 v2.14.1 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/websocket v1.5.3 // indirect - github.com/grafana/alerting v0.0.0-20250224133628-2acbeef29642 // indirect + github.com/grafana/alerting v0.0.0-20250225150117-15e285d78df2 // indirect github.com/grafana/authlib v0.0.0-20250225105729-99e678595501 // indirect github.com/grafana/dataplane/sdata v0.0.9 // indirect github.com/grafana/dskit v0.0.0-20241105154643-a6b453a88040 // indirect diff --git a/pkg/storage/unified/apistore/go.sum b/pkg/storage/unified/apistore/go.sum index 11a44305649..a3a38f639b9 100644 --- a/pkg/storage/unified/apistore/go.sum +++ b/pkg/storage/unified/apistore/go.sum @@ -567,8 +567,8 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grafana/alerting v0.0.0-20250224133628-2acbeef29642 h1:iQ0h/h+QoguSZDF+ZpPxcM/C+m1kjh+aXjMpxywowPA= -github.com/grafana/alerting v0.0.0-20250224133628-2acbeef29642/go.mod h1:hdGB3dSl8Ma9Rjo2YiAEAjMkZ5HiNJbNDqRKDefRZrM= +github.com/grafana/alerting v0.0.0-20250225150117-15e285d78df2 h1:kESrzm0FcRVLmGIQCgl1MCwDGLH4sLzWphr7mcFdbfI= +github.com/grafana/alerting v0.0.0-20250225150117-15e285d78df2/go.mod h1:hdGB3dSl8Ma9Rjo2YiAEAjMkZ5HiNJbNDqRKDefRZrM= github.com/grafana/authlib v0.0.0-20250225105729-99e678595501 h1:FTuDRy/Shw8yOdG+v1DnkeuaCAl8fvwgcfaG9Wccuhg= github.com/grafana/authlib v0.0.0-20250225105729-99e678595501/go.mod h1:XVpdLhaeYqz414FmGnW00/0vTe1x8c0GRH3KaeRtyg0= github.com/grafana/authlib/types v0.0.0-20250224151205-5ef97131cc82 h1:DnRUYiAotHXnrfYJCvhH1NkiyWVcPm5Pd+P7Ugqt/d8= diff --git a/pkg/storage/unified/resource/go.mod b/pkg/storage/unified/resource/go.mod index 75b69ced369..a6802a0d5b2 100644 --- a/pkg/storage/unified/resource/go.mod +++ b/pkg/storage/unified/resource/go.mod @@ -117,7 +117,7 @@ require ( github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect github.com/googleapis/gax-go/v2 v2.14.1 // indirect github.com/gorilla/mux v1.8.1 // indirect - github.com/grafana/alerting v0.0.0-20250224133628-2acbeef29642 // indirect + github.com/grafana/alerting v0.0.0-20250225150117-15e285d78df2 // indirect github.com/grafana/dataplane/sdata v0.0.9 // indirect github.com/grafana/grafana-app-sdk/logging v0.30.0 // indirect github.com/grafana/grafana-aws-sdk v0.31.5 // indirect diff --git a/pkg/storage/unified/resource/go.sum b/pkg/storage/unified/resource/go.sum index 83d766f41aa..49c224e0ad3 100644 --- a/pkg/storage/unified/resource/go.sum +++ b/pkg/storage/unified/resource/go.sum @@ -398,8 +398,8 @@ github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -github.com/grafana/alerting v0.0.0-20250224133628-2acbeef29642 h1:iQ0h/h+QoguSZDF+ZpPxcM/C+m1kjh+aXjMpxywowPA= -github.com/grafana/alerting v0.0.0-20250224133628-2acbeef29642/go.mod h1:hdGB3dSl8Ma9Rjo2YiAEAjMkZ5HiNJbNDqRKDefRZrM= +github.com/grafana/alerting v0.0.0-20250225150117-15e285d78df2 h1:kESrzm0FcRVLmGIQCgl1MCwDGLH4sLzWphr7mcFdbfI= +github.com/grafana/alerting v0.0.0-20250225150117-15e285d78df2/go.mod h1:hdGB3dSl8Ma9Rjo2YiAEAjMkZ5HiNJbNDqRKDefRZrM= github.com/grafana/authlib v0.0.0-20250225105729-99e678595501 h1:FTuDRy/Shw8yOdG+v1DnkeuaCAl8fvwgcfaG9Wccuhg= github.com/grafana/authlib v0.0.0-20250225105729-99e678595501/go.mod h1:XVpdLhaeYqz414FmGnW00/0vTe1x8c0GRH3KaeRtyg0= github.com/grafana/authlib/types v0.0.0-20250224151205-5ef97131cc82 h1:DnRUYiAotHXnrfYJCvhH1NkiyWVcPm5Pd+P7Ugqt/d8= From 6abf0434df8beac14dda6ddd5863e1e252408736 Mon Sep 17 00:00:00 2001 From: Jev Forsberg <46619047+baldm0mma@users.noreply.github.com> Date: Fri, 28 Feb 2025 14:53:17 -0700 Subject: [PATCH 45/74] Chore: Migrate backend testing from drone to gha (#100765) * baldm0mma/ add gha workflow * baldm0mma/ add codeowners * baldm0mma/ update health command * baldm0mma/ update aliases for services * baldm0mma/ rewrite migration attempt * baldm0mma/ fix package names for ubuntu * baldm0mma/ add authentication * baldm0mma/ update auth * baldm0mma/ add debugs * baldm0mma/ add continue on error * baldm0mma/ simplyfy ent fork logic * baldm0mma/ debug fork status * baldm0mma/ add debug workflow for enterprise access * chore: add workflow_dispatch trigger to backend test workflow * baldm0mma/ debug ent run * baldm0mma/ add more robust debugging info * baldm0mma/ use old drone ci app for testing * baldm0mma/ update app name * baldm0mma/ update workflow creds * baldm0mma/ rename * baldm0mma/ update codeownders * baldm0mma/ update paths to ignore paths for docs and markdown files * baldm0mma/ create 'Setup Grafana Enterprise' action and remove from current workflow * baldm0mma/ fail at git clone * baldm0mma/ absract away "Run backend tests" and "Run backend integration tests" into their own actions * baldm0mma/ update directory strcuture to adhere to GHAs best practices * baldm0mma/ remove optional configs * baldm0mma/ update codeowners * baldm0mma/ update gh app name * baldm0mma/ remove circ dep * baldm0mma/ uncomment out enterprise setup for test * baldm0mma/ update valut url * baldm0mma/ use vault instance rather than url * baldm0mma/ debug * baldm0mma/ Removed the multiline string format * baldm0mma/ add installation key * baldm0mma/ update path * baldm0mma/ debug vault access * baldm0mma/ add ent * baldm0mma/ remove debugging * baldm0mma/ update paths * baldm0mma/ update codeowners * baldm0mma/ update paths and codeowners * baldm0mma/ add continue-on-error to assure the workflow isn't blocking * baldm0mma/ simplify test action execution * baldm0mma/ remove wire install step * baldm0mma/ add conditions for coverage output * baldm0mma/ add conditions for coverage output for integration test action * baldm0mma/ add report converage file * baldm0mma/ remove uneeded action * baldm0mma/ update codeowners * baldm0mma/ push small change to go file and add log * baldm0mma/ update trigger conditions * baldm0mma/ update converage conditions * baldm0mma/ update Run backend integration tests with correct action * baldm0mma/ test 2 * baldm0mma/ update with -coverpkg flag * baldm0mma/ remove backend-coverage as it is now redundant * baldm0mma/ update codeowners * baldm0mma/ update test file * baldm0mma/ update coverage logic --- .github/CODEOWNERS | 5 +- .github/actions/report-coverage/action.yml | 46 ++++++++ .github/actions/run-backend-tests/action.yml | 24 ++++ .github/actions/setup-enterprise/action.yml | 48 ++++++++ .github/workflows/backend-coverage.yml | 109 ------------------- .github/workflows/pr-test-backend.yml | 106 ++++++++++++++++++ 6 files changed, 228 insertions(+), 110 deletions(-) create mode 100644 .github/actions/report-coverage/action.yml create mode 100644 .github/actions/run-backend-tests/action.yml create mode 100644 .github/actions/setup-enterprise/action.yml delete mode 100644 .github/workflows/backend-coverage.yml create mode 100644 .github/workflows/pr-test-backend.yml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 64363540c79..107396a4ee3 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -754,6 +754,9 @@ embed.go @grafana/grafana-as-code /.github/pr-checks.json @tolzhabayev /.github/pr-commands.json @tolzhabayev /.github/renovate.json5 @grafana/frontend-ops +/.github/actions/report-coverage @grafana/grafana-backend-group +/.github/actions/run-backend-tests @grafana/grafana-backend-group +/.github/actions/setup-enterprise @grafana/grafana-backend-group /.github/workflows/add-to-whats-new.yml @grafana/docs-tooling /.github/workflows/auto-triager/ @grafana/plugins-platform-frontend /.github/workflows/alerting-swagger-gen.yml @grafana/alerting-backend @@ -761,7 +764,6 @@ embed.go @grafana/grafana-as-code /.github/workflows/auto-milestone.yml @grafana/grafana-developer-enablement-squad /.github/workflows/backport.yml @grafana/grafana-developer-enablement-squad /.github/workflows/bump-version.yml @grafana/grafana-developer-enablement-squad -/.github/workflows/backend-coverage.yml @Proximyst /.github/workflows/close-milestone.yml @grafana/grafana-developer-enablement-squad /.github/workflows/release-pr.yml @grafana/grafana-developer-enablement-squad /.github/workflows/release-comms.yml @grafana/grafana-developer-enablement-squad @@ -787,6 +789,7 @@ embed.go @grafana/grafana-as-code /.github/workflows/pr-codeql-analysis-python.yml @DanCech /.github/workflows/pr-commands.yml @tolzhabayev /.github/workflows/pr-patch-check.yml @grafana/grafana-developer-enablement-squad +/.github/workflows/pr-test-backend.yml @grafana/grafana-backend-group /.github/workflows/sync-mirror.yml @grafana/grafana-developer-enablement-squad /.github/workflows/publish-technical-documentation-next.yml @grafana/docs-tooling /.github/workflows/publish-technical-documentation-release.yml @grafana/docs-tooling diff --git a/.github/actions/report-coverage/action.yml b/.github/actions/report-coverage/action.yml new file mode 100644 index 00000000000..c84aa806d7e --- /dev/null +++ b/.github/actions/report-coverage/action.yml @@ -0,0 +1,46 @@ +name: 'Report Coverage' +description: 'Processes and uploads coverage reports from Go tests' + +inputs: + unit-cov-path: + description: 'Path to unit test coverage file' + required: true + integration-cov-path: + description: 'Path to integration test coverage file' + required: true + +runs: + using: "composite" + steps: + - name: Join coverage outputs + shell: bash + run: | + cp ${{ inputs.unit-cov-path }} backend.cov + tail -n+2 ${{ inputs.integration-cov-path }} >> backend.cov + + - name: Convert coverage info to per-func stats + shell: bash + run: go tool cover -func backend.cov > backend-funcs.log + + - name: Convert coverage info to HTML + shell: bash + run: go tool cover -html backend.cov -o backend.html + + - name: Upload coverage file + uses: actions/upload-artifact@v4 + with: + name: backend-cov + path: | + backend.cov + backend-funcs.log + backend.html + retention-days: 30 + compression-level: 9 + + - name: Set summary to total coverage + shell: bash + run: | + echo '# Coverage' >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + grep 'total:' backend-funcs.log | tr '\t' ' ' >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY diff --git a/.github/actions/run-backend-tests/action.yml b/.github/actions/run-backend-tests/action.yml new file mode 100644 index 00000000000..6ae930fa489 --- /dev/null +++ b/.github/actions/run-backend-tests/action.yml @@ -0,0 +1,24 @@ +name: 'Run Backend Tests' +description: 'Runs Grafana backend test suites' + +inputs: + coverage-opts: + description: 'Coverage options to pass to the test command (empty for no coverage)' + required: false + default: '' + test-command: + description: 'The test command to run' + required: false + default: 'make gen-go test-go-unit' + +runs: + using: "composite" + steps: + - name: Run tests + shell: bash + run: | + if [ -n "${{ inputs.coverage-opts }}" ]; then + COVER_OPTS="${{ inputs.coverage-opts }}" ${{ inputs.test-command }} + else + ${{ inputs.test-command }} + fi diff --git a/.github/actions/setup-enterprise/action.yml b/.github/actions/setup-enterprise/action.yml new file mode 100644 index 00000000000..e87d3d7bae9 --- /dev/null +++ b/.github/actions/setup-enterprise/action.yml @@ -0,0 +1,48 @@ +name: 'Setup Grafana Enterprise' +description: 'Clones and sets up Grafana Enterprise repository for testing' + +inputs: + github-app-name: + description: 'Name of the GitHub App in Vault' + required: false + default: 'grafana-ci-bot' + +runs: + using: "composite" + steps: + - name: Retrieve GitHub App secrets + id: get-secrets + uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets-v1.0.1 + with: + repo_secrets: | + APP_ID=${{ inputs.github-app-name }}:app-id + APP_INSTALLATION_ID=${{ inputs.github-app-name }}:app-installation-id + PRIVATE_KEY=${{ inputs.github-app-name }}:private-key + + - name: Generate GitHub App token + id: generate_token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ env.APP_ID }} + private-key: ${{ env.PRIVATE_KEY }} + repositories: "grafana-enterprise" + owner: "grafana" + + - name: Setup Enterprise + shell: bash + env: + GH_TOKEN: ${{ steps.generate_token.outputs.token }} + run: | + git clone https://x-access-token:${GH_TOKEN}@github.com/grafana/grafana-enterprise.git ../grafana-enterprise; + + cd ../grafana-enterprise + + if git checkout ${GITHUB_HEAD_REF}; then + echo "checked out ${GITHUB_HEAD_REF}" + elif git checkout ${GITHUB_BASE_REF}; then + echo "checked out ${GITHUB_BASE_REF}" + else + git checkout main + fi + + ./build.sh diff --git a/.github/workflows/backend-coverage.yml b/.github/workflows/backend-coverage.yml deleted file mode 100644 index f103e5b1eed..00000000000 --- a/.github/workflows/backend-coverage.yml +++ /dev/null @@ -1,109 +0,0 @@ -name: Backend Coverage (OSS) -on: - push: - paths: - - pkg/** - - .github/workflows/backend-coverage.yml - - go.* - branches: - - main - pull_request: - -jobs: - unit-tests: - name: Run unit tests (OSS) - runs-on: ubuntu-latest - if: github.repository == 'grafana/grafana' - steps: - - name: Check out repository - uses: actions/checkout@v4.2.2 - - name: Setup Go environment - uses: actions/setup-go@v5.3.0 - with: - go-version-file: go.work - - name: Run tests - run: make gen-go test-go-unit - - name: Upload coverage file - uses: actions/upload-artifact@v4 - if: success() || failure() - with: - name: unit-cov - path: unit.cov - retention-days: 1 - compression-level: 9 # this is raw text, and includes a _lot_ of repetition. compressing it should yield pretty good results. - integration-tests: - name: Run integration tests (OSS) - runs-on: ubuntu-latest - if: github.repository == 'grafana/grafana' - steps: - - name: Check out repository - uses: actions/checkout@v4.2.2 - - name: Setup Go environment - uses: actions/setup-go@v5.3.0 - with: - go-version-file: go.work - - name: Run tests - run: make gen-go test-go-integration - - name: Upload coverage file - uses: actions/upload-artifact@v4 - if: success() || failure() - with: - name: integration-cov - path: integration.cov - retention-days: 1 - compression-level: 9 # this is raw text, and includes a _lot_ of repetition. compressing it should yield pretty good results. - report-coverage: - name: Report coverage from unit and integration tests (OSS) - needs: [unit-tests, integration-tests] - runs-on: ubuntu-latest - # we don't do always() so as to not run even if the workflow is cancelled - if: github.repository == 'grafana/grafana' && (success() || failure()) - steps: - - name: Check out repository - uses: actions/checkout@v4.2.2 - - name: Setup Go environment - uses: actions/setup-go@v5.3.0 - with: - go-version-file: go.work - - name: Generate Go - run: make gen-go - - uses: actions/download-artifact@v4 - with: - pattern: '*-cov' - path: . - merge-multiple: true - - name: Join coverage outputs - run: | - cp unit.cov backend.cov - tail -n+2 integration.cov >> backend.cov - - name: Convert coverage info to per-func stats - run: go tool cover -func backend.cov > backend-funcs.log - # The HTML can be useful in some UI to browse the artifacts easily. - - name: Convert coverage info to HTML - run: go tool cover -html backend.cov -o backend.html - - name: Upload coverage file - uses: actions/upload-artifact@v4 - with: - name: backend-cov - path: | - backend.cov - backend-funcs.log - backend.html - retention-days: 30 - compression-level: 9 # this is raw text, and includes a _lot_ of repetition. compressing it should yield pretty good results. - - name: Delete old coverage files - # This is a community tool, not one provided by GitHub. Hence it shall be pinned to a hash. - # https://github.com/GeekyEggo/delete-artifact/tree/v5 - uses: GeekyEggo/delete-artifact@f275313e70c08f6120db482d7a6b98377786765b - with: - name: | - unit-cov - integration-cov - failOnError: false # oh well, we'll just have the extra artifacts... - - name: Set summary to total coverage - # We use single quotes here to disable the bash backtick behaviour of executing commands. - run: | - echo '# Coverage' >> $GITHUB_STEP_SUMMARY - echo '```' >> $GITHUB_STEP_SUMMARY - grep 'total:' backend-funcs.log | tr '\t' ' ' >> $GITHUB_STEP_SUMMARY - echo '```' >> $GITHUB_STEP_SUMMARY \ No newline at end of file diff --git a/.github/workflows/pr-test-backend.yml b/.github/workflows/pr-test-backend.yml new file mode 100644 index 00000000000..da7e3450a54 --- /dev/null +++ b/.github/workflows/pr-test-backend.yml @@ -0,0 +1,106 @@ +name: Test Backend + +on: + workflow_dispatch: + push: + branches: + - main + paths-ignore: + - 'docs/**' + - '**/*.md' + pull_request: + paths-ignore: + - 'docs/**' + - '**/*.md' + +permissions: + contents: read + id-token: write + +env: + EDITION: 'oss' + +jobs: + test-backend: + name: Test Backend + runs-on: ubuntu-latest + continue-on-error: true + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: '1.23.5' + cache: true + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y build-essential shared-mime-info make + + - name: Get runner name + run: echo ${{ runner.name }} + + - name: Setup Enterprise (PR only) + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false + uses: ./.github/actions/setup-enterprise + + - name: Verify CUE generation + run: CODEGEN_VERIFY=1 make gen-cue + + - name: Verify Jsonnet generation + run: CODEGEN_VERIFY=1 make gen-jsonnet + + - name: Check if coverage should be generated + id: check-coverage + env: + GH_TOKEN: ${{ github.token }} + run: | + echo "Event: ${{ github.event_name }}" + echo "Ref: ${{ github.ref }}" + + if [[ "${{ github.event_name }}" == "pull_request" ]]; then + echo "PR changed files:" + files=$(gh api repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files --jq '.[].filename') + echo "$files" + if echo "$files" | grep -E "(pkg/|go\.)"; then + echo "Coverage will be generated: true (PR changes)" + echo "generate=true" >> $GITHUB_OUTPUT + else + echo "Coverage will be generated: false" + echo "generate=false" >> $GITHUB_OUTPUT + fi + elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" == "refs/heads/main" ]] && \ + [[ "${{ github.event.head_commit.modified }}" =~ (pkg/|go\.|\.github/workflows/pr-test-backend\.yml) ]]; then + echo "Coverage will be generated: true (push to main)" + echo "generate=true" >> $GITHUB_OUTPUT + else + echo "Coverage will be generated: false" + echo "generate=false" >> $GITHUB_OUTPUT + fi + + - name: Run backend tests + uses: ./.github/actions/run-backend-tests + with: + coverage-opts: ${{ steps.check-coverage.outputs.generate == 'true' && '-coverprofile=unit.cov -coverpkg=github.com/grafana/grafana/...' || '' }} + test-command: 'make gen-go test-go-unit' + + - name: Run backend integration tests + uses: ./.github/actions/run-backend-tests + with: + coverage-opts: ${{ steps.check-coverage.outputs.generate == 'true' && '-coverprofile=integration.cov -coverpkg=github.com/grafana/grafana/...' || '' }} + test-command: 'make gen-go test-go-integration' + + - name: Generate Coverage Report + if: steps.check-coverage.outputs.generate == 'true' + uses: ./.github/actions/report-coverage + with: + unit-cov-path: unit.cov + integration-cov-path: integration.cov + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true From e8b035a5f713f9437e5242f8cf46e02688bbc63d Mon Sep 17 00:00:00 2001 From: Leon Sorokin Date: Fri, 28 Feb 2025 16:25:43 -0600 Subject: [PATCH 46/74] Transformations: Fix variable interpolation when Scenes is disabled (#101438) Co-authored-by: Dominik Prokop --- .betterer.results | 8 +++++ .../src/transformations/transformDataFrame.ts | 32 ++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/.betterer.results b/.betterer.results index f6c07dd6633..d5ac5c018d3 100644 --- a/.betterer.results +++ b/.betterer.results @@ -142,6 +142,14 @@ exports[`better eslint`] = { "packages/grafana-data/src/transformations/standardTransformersRegistry.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], + "packages/grafana-data/src/transformations/transformDataFrame.ts:5381": [ + [0, 0, 0, "Unexpected any. Specify a different type.", "0"], + [0, 0, 0, "Unexpected any. Specify a different type.", "1"], + [0, 0, 0, "Unexpected any. Specify a different type.", "2"], + [0, 0, 0, "Unexpected any. Specify a different type.", "3"], + [0, 0, 0, "Unexpected any. Specify a different type.", "4"], + [0, 0, 0, "Unexpected any. Specify a different type.", "5"] + ], "packages/grafana-data/src/transformations/transformers/nulls/nullInsertThreshold.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"] diff --git a/packages/grafana-data/src/transformations/transformDataFrame.ts b/packages/grafana-data/src/transformations/transformDataFrame.ts index 477801b650e..1a923ec0d86 100644 --- a/packages/grafana-data/src/transformations/transformDataFrame.ts +++ b/packages/grafana-data/src/transformations/transformDataFrame.ts @@ -12,6 +12,9 @@ import { import { getFrameMatchers } from './matchers'; import { standardTransformersRegistry, TransformerRegistryItem } from './standardTransformersRegistry'; +// when running within Scenes, we can skip var interpolation, since it's already handled upstream +const isScenes = window.__grafanaSceneContext != null; + const getOperator = (config: DataTransformerConfig, ctx: DataTransformContext): MonoTypeOperatorFunction => (source) => { @@ -24,11 +27,20 @@ const getOperator = const defaultOptions = info.transformation.defaultOptions ?? {}; const options = { ...defaultOptions, ...config.options }; + const interpolated = isScenes + ? options + : deepIterate(options, (v) => { + if (typeof v === 'string') { + return ctx.interpolate(v); + } + return v; + }); + const matcher = config.filter?.options ? getFrameMatchers(config.filter) : undefined; return source.pipe( mergeMap((before) => of(filterInput(before, matcher)).pipe( - info.transformation.operator(options, ctx), + info.transformation.operator(interpolated, ctx), postProcessTransform(before, info, matcher) ) ) @@ -107,3 +119,21 @@ export function transformDataFrame( function isCustomTransformation(t: DataTransformerConfig | CustomTransformOperator): t is CustomTransformOperator { return typeof t === 'function'; } + +function deepIterate(obj: T, doSomething: (current: any) => any): T; +// eslint-disable-next-line no-redeclare +function deepIterate(obj: any, doSomething: (current: any) => any): any { + if (Array.isArray(obj)) { + return obj.map((o) => deepIterate(o, doSomething)); + } + + if (typeof obj === 'object') { + for (const key in obj) { + obj[key] = deepIterate(obj[key], doSomething); + } + + return obj; + } else { + return doSomething(obj) ?? obj; + } +} From 2cc6f39c5e6dbd62f1cd7a4defab3b1b189888fb Mon Sep 17 00:00:00 2001 From: Oscar Kilhed Date: Sat, 1 Mar 2025 00:38:05 +0100 Subject: [PATCH 47/74] Transformations: Fix runtime handling of old format in Add field from calc / binary (#101455) Co-authored-by: Leon Sorokin --- .../transformers/calculateField.test.ts | 314 +++++++++++------- .../transformers/calculateField.ts | 5 +- 2 files changed, 205 insertions(+), 114 deletions(-) diff --git a/packages/grafana-data/src/transformations/transformers/calculateField.test.ts b/packages/grafana-data/src/transformations/transformers/calculateField.test.ts index f9d049f309b..d633dad4db8 100644 --- a/packages/grafana-data/src/transformations/transformers/calculateField.test.ts +++ b/packages/grafana-data/src/transformations/transformers/calculateField.test.ts @@ -237,37 +237,29 @@ describe('calculateField transformer w/ timeseries', () => { await expect(transformDataFrame([cfg], [seriesA, seriesBC])).toEmitValuesWith((received) => { const data = received[0]; - expect(data).toMatchInlineSnapshot(` - [ - { - "fields": [ - { - "config": {}, - "name": "TheTime", - "state": { - "displayName": "TheTime", - "multipleFrames": true, - }, - "type": "time", - "values": [ - 1000, - 2000, - ], + expect(data).toEqual([ + { + fields: [ + { + config: {}, + name: 'TheTime', + state: { + displayName: 'TheTime', + multipleFrames: true, }, - { - "config": {}, - "name": "B + 2", - "type": "number", - "values": [ - 4, - 202, - ], - }, - ], - "length": 2, - }, - ] - `); + type: 'time', + values: [1000, 2000], + }, + { + config: {}, + name: 'B + 2', + type: 'number', + values: [4, 202], + }, + ], + length: 2, + }, + ]); }); }); @@ -321,65 +313,48 @@ describe('calculateField transformer w/ timeseries', () => { await expect(transformDataFrame([cfg], [seriesA, seriesBC])).toEmitValuesWith((received) => { const data = received[0]; - expect(data).toMatchInlineSnapshot(` - [ - { - "fields": [ - { - "config": {}, - "name": "TheTime", - "type": "time", - "values": [ - 1000, - 2000, - ], - }, - { - "config": {}, - "name": "A + 2", - "type": "number", - "values": [ - 3, - 102, - ], - }, - ], - "length": 2, - }, - { - "fields": [ - { - "config": {}, - "name": "TheTime", - "type": "time", - "values": [ - 1000, - 2000, - ], - }, - { - "config": {}, - "name": "B + 2", - "type": "number", - "values": [ - 4, - 202, - ], - }, - { - "config": {}, - "name": "C + 2", - "type": "number", - "values": [ - 5, - 302, - ], - }, - ], - "length": 2, - }, - ] - `); + expect(data).toEqual([ + { + fields: [ + { + config: {}, + name: 'TheTime', + type: 'time', + values: [1000, 2000], + }, + { + config: {}, + name: 'A + 2', + type: 'number', + values: [3, 102], + }, + ], + length: 2, + }, + { + fields: [ + { + config: {}, + name: 'TheTime', + type: 'time', + values: [1000, 2000], + }, + { + config: {}, + name: 'B + 2', + type: 'number', + values: [4, 202], + }, + { + config: {}, + name: 'C + 2', + type: 'number', + values: [5, 302], + }, + ], + length: 2, + }, + ]); }); }); @@ -479,18 +454,133 @@ describe('calculateField transformer w/ timeseries', () => { const data = received[0]; const filtered = data[0]; const rows = new DataFrameView(filtered).toArray(); - expect(rows).toMatchInlineSnapshot(` - [ - { - "E * 1": 1, - "TheTime": 1000, - }, - { - "E * 1": 0, - "TheTime": 2000, - }, - ] - `); + expect(rows).toEqual([ + { + 'E * 1': 1, + TheTime: 1000, + }, + { + 'E * 1': 0, + TheTime: 2000, + }, + ]); + }); + }); + + it('transforms multiple queries + field + field in the old format', async () => { + const cfg = { + id: DataTransformerID.calculateField, + options: { + binary: { + left: 'A', + operator: '+', + reducer: 'sum', + right: 'B', + }, + mode: CalculateFieldMode.BinaryOperation, + reduce: { + reducer: 'sum', + }, + replaceFields: true, + }, + }; + + await expect(transformDataFrame([cfg], [seriesA, seriesBC])).toEmitValuesWith((received) => { + const data = received[0]; + expect(data).toEqual([ + { + fields: [ + { + config: {}, + name: 'TheTime', + state: { + displayName: 'TheTime', + multipleFrames: false, + }, + type: 'time', + values: [1000, 2000], + }, + { + config: {}, + name: 'A + B', + type: 'number', + values: [3, 300], + }, + ], + length: 2, + refId: 'joinByField--', + }, + ]); + }); + }); + + it('transforms multiple queries + field + field in the old format (non existent right field)', async () => { + const cfg = { + id: DataTransformerID.calculateField, + options: { + binary: { + left: 'A', + operator: '+', + reducer: 'sum', + right: 'Z', + }, + mode: CalculateFieldMode.BinaryOperation, + reduce: { + reducer: 'sum', + }, + replaceFields: true, + }, + }; + + await expect(transformDataFrame([cfg], [seriesA, seriesBC])).toEmitValuesWith((received) => { + const data = received[0]; + expect(data).toEqual([]); + }); + }); + + it('transforms multiple queries + field + number in the old format and does not join', async () => { + const cfg = { + id: DataTransformerID.calculateField, + options: { + binary: { + left: 'A', + operator: '+', + reducer: 'sum', + right: '1336', + }, + mode: CalculateFieldMode.BinaryOperation, + reduce: { + reducer: 'sum', + }, + replaceFields: true, + }, + }; + + await expect(transformDataFrame([cfg], [seriesA, seriesBC])).toEmitValuesWith((received) => { + const data = received[0]; + expect(data).toEqual([ + { + fields: [ + { + config: {}, + name: 'TheTime', + state: { + displayName: 'TheTime', + multipleFrames: true, + }, + type: 'time', + values: [1000, 2000], + }, + { + config: {}, + name: 'A + 1336', + type: 'number', + values: [1337, 1436], + }, + ], + length: 2, + }, + ]); }); }); @@ -587,18 +677,16 @@ describe('calculateField transformer w/ timeseries', () => { const filtered = data[0]; const rows = new DataFrameView(filtered).toArray(); - expect(rows).toMatchInlineSnapshot(` - [ - { - "Test": 6, - "TheTime": 1000, - }, - { - "Test": 105, - "TheTime": 2000, - }, - ] - `); + expect(rows).toEqual([ + { + Test: 6, + TheTime: 1000, + }, + { + Test: 105, + TheTime: 2000, + }, + ]); }); it('calculates centered moving average on odd window size', async () => { diff --git a/packages/grafana-data/src/transformations/transformers/calculateField.ts b/packages/grafana-data/src/transformations/transformers/calculateField.ts index f7b8989c159..d6ef07c8f5c 100644 --- a/packages/grafana-data/src/transformations/transformers/calculateField.ts +++ b/packages/grafana-data/src/transformations/transformers/calculateField.ts @@ -131,7 +131,10 @@ export const calculateFieldTransformer: DataTransformerInfo Date: Sat, 1 Mar 2025 21:26:14 +0300 Subject: [PATCH 48/74] K8s/DualWriter: Use dualwriter package for all dual writers (#101393) --- pkg/apiserver/rest/dualwriter.go | 44 -- pkg/apiserver/rest/dualwriter_mode1.go | 346 --------------- pkg/apiserver/rest/dualwriter_mode2.go | 309 -------------- pkg/apiserver/rest/dualwriter_mode3.go | 327 -------------- pkg/apiserver/rest/metrics.go | 59 +-- pkg/apiserver/rest/storage_mocks_test.go | 21 +- pkg/services/apiserver/builder/helper.go | 2 +- pkg/storage/legacysql/dualwrite/dualwriter.go | 229 ++++++++++ .../dualwrite}/dualwriter_mode1_test.go | 404 ++---------------- .../dualwrite}/dualwriter_mode2_test.go | 46 +- .../dualwrite}/dualwriter_mode3_test.go | 100 ++--- pkg/storage/legacysql/dualwrite/runtime.go | 21 +- .../legacysql/dualwrite/runtime_test.go | 19 +- pkg/storage/legacysql/dualwrite/static.go | 46 +- .../legacysql/dualwrite/storage_mocks_test.go | 9 + 15 files changed, 392 insertions(+), 1590 deletions(-) delete mode 100644 pkg/apiserver/rest/dualwriter_mode1.go delete mode 100644 pkg/apiserver/rest/dualwriter_mode2.go delete mode 100644 pkg/apiserver/rest/dualwriter_mode3.go create mode 100644 pkg/storage/legacysql/dualwrite/dualwriter.go rename pkg/{apiserver/rest => storage/legacysql/dualwrite}/dualwriter_mode1_test.go (57%) rename pkg/{apiserver/rest => storage/legacysql/dualwrite}/dualwriter_mode2_test.go (94%) rename pkg/{apiserver/rest => storage/legacysql/dualwrite}/dualwriter_mode3_test.go (87%) diff --git a/pkg/apiserver/rest/dualwriter.go b/pkg/apiserver/rest/dualwriter.go index 31ca7e9c97e..6cd37cb8740 100644 --- a/pkg/apiserver/rest/dualwriter.go +++ b/pkg/apiserver/rest/dualwriter.go @@ -8,8 +8,6 @@ import ( "fmt" "time" - "github.com/prometheus/client_golang/prometheus" - "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apiserver/pkg/registry/rest" @@ -101,36 +99,6 @@ const ( Mode5 ) -// TODO: make this function private as there should only be one public way of setting the dual writing mode -// NewDualWriter returns a new DualWriter. -func NewDualWriter( - mode DualWriterMode, - legacy Storage, - unified Storage, - reg prometheus.Registerer, - resource string, -) Storage { - metrics := &dualWriterMetrics{} - metrics.init(reg) - switch mode { - case Mode0: - return legacy - case Mode1: - // read and write only from legacy storage - return newDualWriterMode1(legacy, unified, metrics, resource) - case Mode2: - // write to both, read from storage but use legacy as backup - return newDualWriterMode2(legacy, unified, metrics, resource) - case Mode3: - // write to both, read from storage only - return newDualWriterMode3(legacy, unified, metrics, resource) - case Mode4, Mode5: - return unified - default: - return newDualWriterMode1(legacy, unified, metrics, resource) - } -} - type NamespacedKVStore interface { Get(ctx context.Context, key string) (string, bool, error) Set(ctx context.Context, key, value string) error @@ -254,15 +222,3 @@ func extractSpec(obj runtime.Object) []byte { } return jsonObj } - -func getName(o runtime.Object) string { - if o == nil { - return "" - } - accessor, err := meta.Accessor(o) - if err != nil { - klog.Error("failed to get object name: ", err) - return "" - } - return accessor.GetName() -} diff --git a/pkg/apiserver/rest/dualwriter_mode1.go b/pkg/apiserver/rest/dualwriter_mode1.go deleted file mode 100644 index 7395fc5d13b..00000000000 --- a/pkg/apiserver/rest/dualwriter_mode1.go +++ /dev/null @@ -1,346 +0,0 @@ -package rest - -import ( - "context" - "errors" - "fmt" - "time" - - "k8s.io/apimachinery/pkg/api/meta" - metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apiserver/pkg/registry/rest" - "k8s.io/klog/v2" -) - -type DualWriterMode1 struct { - Legacy Storage - Storage Storage - *dualWriterMetrics - resource string - Log klog.Logger -} - -const mode1Str = "1" - -// NewDualWriterMode1 returns a new DualWriter in mode 1. -// Mode 1 represents writing to and reading from LegacyStorage. -func newDualWriterMode1(legacy Storage, storage Storage, dwm *dualWriterMetrics, resource string) *DualWriterMode1 { - return &DualWriterMode1{ - Legacy: legacy, - Storage: storage, - Log: klog.NewKlogr().WithName("DualWriterMode1").WithValues("mode", mode1Str, "resource", resource), - dualWriterMetrics: dwm, - resource: resource, - } -} - -// Mode returns the mode of the dual writer. -func (d *DualWriterMode1) Mode() DualWriterMode { - return Mode1 -} - -// Create overrides the behavior of the generic DualWriter and writes only to LegacyStorage. -func (d *DualWriterMode1) Create(ctx context.Context, in runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) { - var method = "create" - log := d.Log.WithValues("method", method) - ctx = klog.NewContext(ctx, log) - - accIn, err := meta.Accessor(in) - if err != nil { - return nil, err - } - - if accIn.GetUID() != "" { - return nil, fmt.Errorf("UID should not be present:: %v", accIn.GetUID()) - } - - startLegacy := time.Now() - created, err := d.Legacy.Create(ctx, in, createValidation, options) - d.recordLegacyDuration(err != nil, mode1Str, d.resource, method, startLegacy) - if err != nil { - log.Error(err, "unable to create object in legacy storage") - return created, err - } - - createdCopy := created.DeepCopyObject() - - //nolint:errcheck - go d.createOnUnifiedStorage(ctx, createValidation, createdCopy, options) - - return created, err -} - -func (d *DualWriterMode1) createOnUnifiedStorage(ctx context.Context, createValidation rest.ValidateObjectFunc, createdCopy runtime.Object, options *metav1.CreateOptions) error { - var method = "create" - log := d.Log.WithValues("method", method) - - // Ignores cancellation signals from parent context. Will automatically be canceled after 10 seconds. - ctx, cancel := context.WithTimeoutCause(context.WithoutCancel(ctx), time.Second*10, errors.New("storage create timeout")) - defer cancel() - - accCreated, err := meta.Accessor(createdCopy) - if err != nil { - return err - } - - accCreated.SetResourceVersion("") - - startStorage := time.Now() - storageObj, errObjectSt := d.Storage.Create(ctx, createdCopy, createValidation, options) - d.recordStorageDuration(errObjectSt != nil, mode1Str, d.resource, method, startStorage) - if errObjectSt != nil { - log.Error(errObjectSt, "unable to create object in storage") - cancel() - } - areEqual := Compare(storageObj, createdCopy) - d.recordOutcome(mode1Str, getName(createdCopy), areEqual, method) - if !areEqual { - log.Info("object from legacy and storage are not equal") - } - - return errObjectSt -} - -// Get overrides the behavior of the generic DualWriter and reads only from LegacyStorage. -func (d *DualWriterMode1) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { - var method = "get" - log := d.Log.WithValues("method", method, "name", name) - ctx = klog.NewContext(ctx, log) - - startLegacy := time.Now() - res, errLegacy := d.Legacy.Get(ctx, name, options) - if errLegacy != nil { - log.Error(errLegacy, "unable to get object in legacy storage") - } - d.recordLegacyDuration(errLegacy != nil, mode1Str, d.resource, method, startLegacy) - - //nolint:errcheck - go d.getFromUnifiedStorage(ctx, res, name, options) - - return res, errLegacy -} - -func (d *DualWriterMode1) getFromUnifiedStorage(ctx context.Context, objFromLegacy runtime.Object, name string, options *metav1.GetOptions) error { - var method = "get" - log := d.Log.WithValues("method", method, "name", name) - - startStorage := time.Now() - // Ignores cancellation signals from parent context. Will automatically be canceled after 10 seconds. - ctx, cancel := context.WithTimeoutCause(context.WithoutCancel(ctx), time.Second*10, errors.New("storage get timeout")) - defer cancel() - storageObj, err := d.Storage.Get(ctx, name, options) - d.recordStorageDuration(err != nil, mode1Str, d.resource, method, startStorage) - if err != nil { - log.Error(err, "unable to get object in storage") - cancel() - } - - areEqual := Compare(storageObj, objFromLegacy) - d.recordOutcome(mode1Str, name, areEqual, method) - if !areEqual { - log.WithValues("name", name).Info("object from legacy and storage are not equal") - } - - return err -} - -// List overrides the behavior of the generic DualWriter and reads only from LegacyStorage. -func (d *DualWriterMode1) List(ctx context.Context, options *metainternalversion.ListOptions) (runtime.Object, error) { - var method = "list" - log := d.Log.WithValues("resourceVersion", options.ResourceVersion, "method", method) - ctx = klog.NewContext(ctx, log) - - startLegacy := time.Now() - res, err := d.Legacy.List(ctx, options) - d.recordLegacyDuration(err != nil, mode1Str, d.resource, method, startLegacy) - if err != nil { - log.Error(err, "unable to list object in legacy storage") - } - - //nolint:errcheck - go d.listFromUnifiedStorage(ctx, options, res) - - return res, err -} - -func (d *DualWriterMode1) listFromUnifiedStorage(ctx context.Context, options *metainternalversion.ListOptions, objFromLegacy runtime.Object) error { - var method = "list" - log := d.Log.WithValues("resourceVersion", options.ResourceVersion, "method", method) - - startStorage := time.Now() - // Ignores cancellation signals from parent context. Will automatically be canceled after 10 seconds. - ctx, cancel := context.WithTimeoutCause(context.WithoutCancel(ctx), time.Second*10, errors.New("storage list timeout")) - defer cancel() - - storageObj, err := d.Storage.List(ctx, options) - d.recordStorageDuration(err != nil, mode1Str, d.resource, method, startStorage) - if err != nil { - log.Error(err, "unable to list objects from unified storage") - cancel() - } - areEqual := Compare(storageObj, objFromLegacy) - d.recordOutcome(mode1Str, getName(objFromLegacy), areEqual, method) - if !areEqual { - log.Info("object from legacy and storage are not equal") - } - - return err -} - -func (d *DualWriterMode1) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) { - var method = "delete" - log := d.Log.WithValues("name", name, "method", method, "name", name) - ctx = klog.NewContext(ctx, d.Log) - - startLegacy := time.Now() - res, async, err := d.Legacy.Delete(ctx, name, deleteValidation, options) - d.recordLegacyDuration(err != nil, mode1Str, name, method, startLegacy) - if err != nil { - log.Error(err, "unable to delete object in legacy storage") - return res, async, err - } - - //nolint:errcheck - go d.deleteFromUnifiedStorage(ctx, res, name, deleteValidation, options) - - return res, async, err -} - -func (d *DualWriterMode1) deleteFromUnifiedStorage(ctx context.Context, res runtime.Object, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) error { - var method = "delete" - log := d.Log.WithValues("name", name, "method", method, "name", name) - - startStorage := time.Now() - // Ignores cancellation signals from parent context. Will automatically be canceled after 10 seconds. - ctx, cancel := context.WithTimeoutCause(context.WithoutCancel(ctx), time.Second*10, errors.New("storage delete timeout")) - defer cancel() - storageObj, _, err := d.Storage.Delete(ctx, name, deleteValidation, options) - d.recordStorageDuration(err != nil, mode1Str, d.resource, method, startStorage) - if err != nil { - log.Error(err, "unable to delete object from unified storage") - cancel() - } - areEqual := Compare(storageObj, res) - d.recordOutcome(mode1Str, name, areEqual, method) - if !areEqual { - log.Info("object from legacy and storage are not equal") - } - - return err -} - -// DeleteCollection overrides the behavior of the generic DualWriter and deletes only from LegacyStorage. -func (d *DualWriterMode1) DeleteCollection(ctx context.Context, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions, listOptions *metainternalversion.ListOptions) (runtime.Object, error) { - var method = "delete-collection" - log := d.Log.WithValues("resourceVersion", listOptions.ResourceVersion, "method", method) - ctx = klog.NewContext(ctx, log) - - startLegacy := time.Now() - res, err := d.Legacy.DeleteCollection(ctx, deleteValidation, options, listOptions) - d.recordLegacyDuration(err != nil, mode1Str, d.resource, method, startLegacy) - if err != nil { - log.Error(err, "unable to delete collection in legacy storage") - return res, err - } - - //nolint:errcheck - go d.deleteCollectionFromUnifiedStorage(ctx, res, deleteValidation, options, listOptions) - - return res, err -} - -func (d *DualWriterMode1) deleteCollectionFromUnifiedStorage(ctx context.Context, res runtime.Object, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions, listOptions *metainternalversion.ListOptions) error { - var method = "delete-collection" - log := d.Log.WithValues("resourceVersion", listOptions.ResourceVersion, "method", method) - - startStorage := time.Now() - // Ignores cancellation signals from parent context. Will automatically be canceled after 10 seconds. - ctx, cancel := context.WithTimeoutCause(context.WithoutCancel(ctx), time.Second*10, errors.New("storage deletecollection timeout")) - defer cancel() - storageObj, err := d.Storage.DeleteCollection(ctx, deleteValidation, options, listOptions) - d.recordStorageDuration(err != nil, mode1Str, d.resource, method, startStorage) - if err != nil { - log.Error(err, "unable to delete collection object from unified storage") - cancel() - } - areEqual := Compare(storageObj, res) - d.recordOutcome(mode1Str, getName(res), areEqual, method) - if !areEqual { - log.Info("object from legacy and storage are not equal") - } - - return err -} - -func (d *DualWriterMode1) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) { - var method = "update" - log := d.Log.WithValues("name", name, "method", method, "name", name) - ctx = klog.NewContext(ctx, log) - - startLegacy := time.Now() - objLegacy, async, err := d.Legacy.Update(ctx, name, objInfo, createValidation, updateValidation, forceAllowCreate, options) - d.recordLegacyDuration(err != nil, mode1Str, d.resource, method, startLegacy) - if err != nil { - log.Error(err, "unable to update in legacy storage") - return objLegacy, async, err - } - - //nolint:errcheck - go d.updateOnUnifiedStorageMode1(ctx, objLegacy, name, objInfo, createValidation, updateValidation, forceAllowCreate, options) - - return objLegacy, async, err -} - -func (d *DualWriterMode1) updateOnUnifiedStorageMode1(ctx context.Context, objLegacy runtime.Object, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) error { - // The incoming RV is from legacy storage, so we can ignore it - ctx = context.WithValue(ctx, dualWriteContextKey{}, true) - - var method = "update" - log := d.Log.WithValues("name", name, "method", method, "name", name) - - // Ignores cancellation signals from parent context. Will automatically be canceled after 10 seconds. - ctx, cancel := context.WithTimeoutCause(context.WithoutCancel(ctx), time.Second*10, errors.New("storage update timeout")) - - startStorage := time.Now() - defer cancel() - storageObj, _, err := d.Storage.Update(ctx, name, objInfo, createValidation, updateValidation, forceAllowCreate, options) - d.recordStorageDuration(err != nil, mode1Str, d.resource, method, startStorage) - if err != nil { - log.Error(err, "unable to update object from unified storage") - cancel() - } - areEqual := Compare(storageObj, objLegacy) - d.recordOutcome(mode1Str, name, areEqual, method) - if !areEqual { - log.WithValues("name", name).Info("object from legacy and storage are not equal") - } - - return err -} - -func (d *DualWriterMode1) Destroy() { - d.Storage.Destroy() - d.Legacy.Destroy() -} - -func (d *DualWriterMode1) GetSingularName() string { - return d.Legacy.GetSingularName() -} - -func (d *DualWriterMode1) NamespaceScoped() bool { - return d.Legacy.NamespaceScoped() -} - -func (d *DualWriterMode1) New() runtime.Object { - return d.Legacy.New() -} - -func (d *DualWriterMode1) NewList() runtime.Object { - return d.Storage.NewList() -} - -func (d *DualWriterMode1) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) { - return d.Legacy.ConvertToTable(ctx, object, tableOptions) -} diff --git a/pkg/apiserver/rest/dualwriter_mode2.go b/pkg/apiserver/rest/dualwriter_mode2.go deleted file mode 100644 index 17aae84e2fb..00000000000 --- a/pkg/apiserver/rest/dualwriter_mode2.go +++ /dev/null @@ -1,309 +0,0 @@ -package rest - -import ( - "context" - "fmt" - "time" - - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" - metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apiserver/pkg/registry/rest" - "k8s.io/klog/v2" - - "github.com/grafana/grafana/pkg/apimachinery/utils" -) - -type DualWriterMode2 struct { - Storage Storage - Legacy Storage - *dualWriterMetrics - resource string - Log klog.Logger -} - -const mode2Str = "2" - -// newDualWriterMode2 returns a new DualWriter in mode 2. -// Mode 2 represents writing to LegacyStorage first, then to Storage. -// When reading, values from LegacyStorage will be returned. -func newDualWriterMode2(legacy Storage, storage Storage, dwm *dualWriterMetrics, resource string) *DualWriterMode2 { - return &DualWriterMode2{ - Legacy: legacy, - Storage: storage, - Log: klog.NewKlogr().WithName("DualWriterMode2").WithValues("mode", mode2Str, "resource", resource), - dualWriterMetrics: dwm, - resource: resource, - } -} - -// Mode returns the mode of the dual writer. -func (d *DualWriterMode2) Mode() DualWriterMode { - return Mode2 -} - -// Create overrides the behavior of the generic DualWriter and writes to LegacyStorage and Storage. -func (d *DualWriterMode2) Create(ctx context.Context, in runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) { - var method = "create" - log := d.Log.WithValues("method", method) - ctx = klog.NewContext(ctx, log) - - accIn, err := meta.Accessor(in) - if err != nil { - return nil, err - } - - if accIn.GetUID() != "" { - return nil, fmt.Errorf("UID should be empty: %v", accIn.GetUID()) - } - - startLegacy := time.Now() - createdFromLegacy, err := d.Legacy.Create(ctx, in, createValidation, options) - if err != nil { - log.Error(err, "unable to create object in legacy storage") - d.recordLegacyDuration(true, mode2Str, d.resource, method, startLegacy) - return nil, err - } - d.recordLegacyDuration(false, mode2Str, d.resource, method, startLegacy) - - createdCopy := createdFromLegacy.DeepCopyObject() - - accCreated, err := meta.Accessor(createdCopy) - if err != nil { - return nil, err - } - - accCreated.SetResourceVersion("") - - startStorage := time.Now() - createdFromStorage, err := d.Storage.Create(ctx, createdCopy, createValidation, options) - if err != nil { - log.WithValues("name").Error(err, "unable to create object in storage") - d.recordStorageDuration(true, mode2Str, d.resource, method, startStorage) - return createdFromStorage, err - } - d.recordStorageDuration(false, mode2Str, d.resource, method, startStorage) - - go func() { - areEqual := Compare(createdFromStorage, createdFromLegacy) - d.recordOutcome(mode2Str, getName(createdFromStorage), areEqual, method) - if !areEqual { - log.Info("object from legacy and storage are not equal") - } - }() - - return createdFromLegacy, err -} - -// Get retrieves an object from Storage if possible, and if not it falls back to LegacyStorage. -func (d *DualWriterMode2) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { - var method = "get" - log := d.Log.WithValues("name", name, "resourceVersion", options.ResourceVersion, "method", method) - ctx = klog.NewContext(ctx, log) - - startLegacy := time.Now() - objLegacy, err := d.Legacy.Get(ctx, name, options) - if err != nil { - log.Error(err, "unable to fetch object from legacy") - d.recordLegacyDuration(true, mode2Str, d.resource, method, startLegacy) - return nil, err - } - d.recordLegacyDuration(false, mode2Str, d.resource, method, startLegacy) - - startStorage := time.Now() - objStorage, err := d.Storage.Get(ctx, name, options) - d.recordStorageDuration(err != nil, mode2Str, d.resource, method, startStorage) - if err != nil { - if !apierrors.IsNotFound(err) { - log.Error(err, "unable to fetch object from storage") - return nil, err - } - log.Info("object not found in storage, dual write or migration didn't happen yet") - } - - go func() { - areEqual := Compare(objStorage, objLegacy) - d.recordOutcome(mode2Str, name, areEqual, method) - if !areEqual { - log.Info("object from legacy and storage are not equal") - } - }() - - return objLegacy, nil -} - -// List overrides the behavior of the generic DualWriter. -func (d *DualWriterMode2) List(ctx context.Context, options *metainternalversion.ListOptions) (runtime.Object, error) { - var method = "list" - log := d.Log.WithValues("resourceVersion", options.ResourceVersion, "method", method) - ctx = klog.NewContext(ctx, log) - - startLegacy := time.Now() - ll, err := d.Legacy.List(ctx, options) - if err != nil { - log.Error(err, "unable to list objects from legacy storage") - d.recordLegacyDuration(true, mode2Str, d.resource, method, startLegacy) - return ll, err - } - d.recordLegacyDuration(false, mode2Str, d.resource, method, startLegacy) - - // Even if we don't compare, we want to fetch from unified storage and check that it doesn't error. - startStorage := time.Now() - if _, err := d.Storage.List(ctx, options); err != nil { - log.Error(err, "unable to list objects from storage") - d.recordStorageDuration(true, mode2Str, d.resource, method, startStorage) - return nil, err - } - d.recordStorageDuration(false, mode2Str, d.resource, method, startStorage) - - return ll, nil -} - -// DeleteCollection overrides the behavior of the generic DualWriter and deletes from both LegacyStorage and Storage. -func (d *DualWriterMode2) DeleteCollection(ctx context.Context, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions, listOptions *metainternalversion.ListOptions) (runtime.Object, error) { - var method = "delete-collection" - log := d.Log.WithValues("resourceVersion", listOptions.ResourceVersion, "method", method) - ctx = klog.NewContext(ctx, log) - - startLegacy := time.Now() - deletedLegacy, err := d.Legacy.DeleteCollection(ctx, deleteValidation, options, listOptions) - if err != nil { - log.WithValues("deleted", deletedLegacy).Error(err, "failed to delete collection successfully from legacy storage") - d.recordLegacyDuration(true, mode2Str, d.resource, method, startLegacy) - return nil, err - } - d.recordLegacyDuration(false, mode2Str, d.resource, method, startLegacy) - - startStorage := time.Now() - deletedStorage, err := d.Storage.DeleteCollection(ctx, deleteValidation, options, listOptions) - if err != nil { - log.WithValues("deleted", deletedStorage).Error(err, "failed to delete collection successfully from Storage") - d.recordStorageDuration(true, mode2Str, d.resource, method, startStorage) - return nil, err - } - d.recordStorageDuration(false, mode2Str, d.resource, method, startStorage) - - go func() { - areEqual := Compare(deletedStorage, deletedLegacy) - d.recordOutcome(mode2Str, getName(deletedStorage), areEqual, method) - if !areEqual { - log.Info("object from legacy and storage are not equal") - } - }() - - return deletedLegacy, err -} - -func (d *DualWriterMode2) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) { - var method = "delete" - log := d.Log.WithValues("name", name, "method", method) - ctx = klog.NewContext(ctx, log) - - // We should delete from Unified storage first so we can retry if legacy fails. - startStorage := time.Now() - deletedS, _, err := d.Storage.Delete(ctx, name, deleteValidation, options) - d.recordStorageDuration(err != nil, mode2Str, d.resource, method, startStorage) - if err != nil { - if !apierrors.IsNotFound(err) { - log.WithValues("objectList", deletedS).Error(err, "could not delete from unified storage") - return nil, false, err - } - } - - startLegacy := time.Now() - deletedLS, async, err := d.Legacy.Delete(ctx, name, deleteValidation, options) - d.recordLegacyDuration(err != nil, mode2Str, d.resource, method, startLegacy) - // Deleting from legacy should always work in mode two, as legacy is still the primary database and - // needs to have all the data. - if err != nil { - return nil, false, err - } - - go func() { - areEqual := Compare(deletedS, deletedLS) - d.recordOutcome(mode2Str, name, areEqual, method) - if !areEqual { - log.WithValues("name", name).Info("object from legacy and storage are not equal") - } - }() - - return deletedLS, async, err -} - -// Update overrides the generic behavior of the Storage and writes first to the legacy storage and then to storage. -func (d *DualWriterMode2) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) { - var method = "update" - log := d.Log.WithValues("name", name, "method", method) - ctx = klog.NewContext(ctx, log) - - // The incoming RV is not stable -- it may be from legacy or storage! - // This sets a flag in the context and our apistore is more lenient when it exists - ctx = context.WithValue(ctx, dualWriteContextKey{}, true) - - startLegacy := time.Now() - objFromLegacy, created, err := d.Legacy.Update(ctx, name, objInfo, createValidation, updateValidation, forceAllowCreate, options) - if err != nil { - log.WithValues("object", objFromLegacy).Error(err, "could not update in legacy storage") - d.recordLegacyDuration(true, mode2Str, d.resource, "update", startLegacy) - return objFromLegacy, created, err - } - d.recordLegacyDuration(false, mode2Str, d.resource, "update", startLegacy) - - startStorage := time.Now() - objFromStorage, created, err := d.Storage.Update(ctx, name, objInfo, createValidation, updateValidation, forceAllowCreate, options) - if err != nil { - log.WithValues("object", objFromStorage).Error(err, "could not update in storage") - d.recordStorageDuration(true, mode2Str, d.resource, "update", startStorage) - return objFromStorage, created, err - } - - go func() { - areEqual := Compare(objFromStorage, objFromLegacy) - d.recordOutcome(mode2Str, name, areEqual, method) - if !areEqual { - log.WithValues("name", name).Info("object from legacy and storage are not equal") - } - }() - - return objFromLegacy, created, err -} - -func (d *DualWriterMode2) Destroy() { - d.Storage.Destroy() - d.Legacy.Destroy() -} - -func (d *DualWriterMode2) GetSingularName() string { - return d.Storage.GetSingularName() -} - -func (d *DualWriterMode2) NamespaceScoped() bool { - return d.Storage.NamespaceScoped() -} - -func (d *DualWriterMode2) New() runtime.Object { - return d.Storage.New() -} - -func (d *DualWriterMode2) NewList() runtime.Object { - return d.Storage.NewList() -} - -func (d *DualWriterMode2) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) { - return d.Storage.ConvertToTable(ctx, object, tableOptions) -} - -func parseList(legacyList []runtime.Object) (map[string]int, error) { - indexMap := map[string]int{} - - for i, obj := range legacyList { - accessor, err := utils.MetaAccessor(obj) - if err != nil { - return nil, err - } - indexMap[accessor.GetName()] = i - } - return indexMap, nil -} diff --git a/pkg/apiserver/rest/dualwriter_mode3.go b/pkg/apiserver/rest/dualwriter_mode3.go deleted file mode 100644 index db61f0ed7f7..00000000000 --- a/pkg/apiserver/rest/dualwriter_mode3.go +++ /dev/null @@ -1,327 +0,0 @@ -package rest - -import ( - "context" - "errors" - "fmt" - "time" - - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" - metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/watch" - "k8s.io/apiserver/pkg/registry/rest" - "k8s.io/klog/v2" -) - -type DualWriterMode3 struct { - Legacy Storage - Storage Storage - watchImp rest.Watcher // watch is only available in mode 3 and 4 - *dualWriterMetrics - resource string - Log klog.Logger -} - -// newDualWriterMode3 returns a new DualWriter in mode 3. -// Mode 3 represents writing to LegacyStorage and Storage and reading from Storage. -func newDualWriterMode3(legacy Storage, storage Storage, dwm *dualWriterMetrics, resource string) *DualWriterMode3 { - return &DualWriterMode3{ - Legacy: legacy, - Storage: storage, - Log: klog.NewKlogr().WithName("DualWriterMode3").WithValues("mode", mode3Str, "resource", resource), - dualWriterMetrics: dwm, - resource: resource, - } -} - -// Mode returns the mode of the dual writer. -func (d *DualWriterMode3) Mode() DualWriterMode { - return Mode3 -} - -const mode3Str = "3" - -// Create overrides the behavior of the generic DualWriter and writes to LegacyStorage and Storage. -func (d *DualWriterMode3) Create(ctx context.Context, in runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) { - var method = "create" - log := d.Log.WithValues("method", method) - - ctx = klog.NewContext(ctx, log) - - accIn, err := meta.Accessor(in) - if err != nil { - return nil, err - } - - if accIn.GetUID() != "" { - return nil, fmt.Errorf("UID should not be: %v", accIn.GetUID()) - } - - if accIn.GetName() == "" && accIn.GetGenerateName() == "" { - return nil, fmt.Errorf("name or generatename have to be set") - } - - // create in legacy first, and then unistore. if unistore fails, but legacy succeeds, - // will try to cleanup the object in legacy. - - startLegacy := time.Now() - createdFromLegacy, err := d.Legacy.Create(ctx, in, createValidation, options) - if err != nil { - log.Error(err, "unable to create object in legacy storage") - d.recordLegacyDuration(true, mode2Str, d.resource, method, startLegacy) - return createdFromLegacy, err - } - d.recordLegacyDuration(false, mode2Str, d.resource, method, startLegacy) - - createdCopy := createdFromLegacy.DeepCopyObject() - accCreated, err := meta.Accessor(createdCopy) - if err != nil { - return createdFromLegacy, err - } - accCreated.SetResourceVersion("") - - startStorage := time.Now() - storageObj, errObjectSt := d.Storage.Create(ctx, createdCopy, createValidation, options) - d.recordStorageDuration(errObjectSt != nil, mode3Str, d.resource, method, startStorage) - if errObjectSt != nil { - log.Error(err, "unable to create object in storage") - - // if we cannot create in unistore, attempt to clean up legacy - _, _, err = d.Legacy.Delete(ctx, accCreated.GetName(), nil, &metav1.DeleteOptions{}) - if err != nil { - log.Error(err, "unable to cleanup object in legacy storage") - } - - return storageObj, errObjectSt - } - - areEqual := Compare(createdFromLegacy, storageObj) - d.recordOutcome(mode3Str, getName(storageObj), areEqual, method) - if !areEqual { - log.Info("object from legacy and storage are not equal") - } - - return storageObj, errObjectSt -} - -// Get overrides the behavior of the generic DualWriter and retrieves an object from Storage. -func (d *DualWriterMode3) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { - var method = "get" - log := d.Log.WithValues("name", name, "method", method) - ctx = klog.NewContext(ctx, log) - - startStorage := time.Now() - storageObj, err := d.Storage.Get(ctx, name, options) - d.recordStorageDuration(err != nil, mode3Str, d.resource, method, startStorage) - if err != nil { - log.Error(err, "unable to get object in storage") - return nil, err - } - - //nolint:errcheck - go d.getFromLegacyStorage(ctx, storageObj, name, options) - - return storageObj, err -} - -func (d *DualWriterMode3) getFromLegacyStorage(ctx context.Context, storageObj runtime.Object, name string, options *metav1.GetOptions) error { - var method = "get" - log := d.Log.WithValues("method", method, "name", name) - - startLegacy := time.Now() - // Ignores cancellation signals from parent context. Will automatically be canceled after 10 seconds. - ctx, cancel := context.WithTimeoutCause(context.WithoutCancel(ctx), time.Second*10, errors.New("legacy get timeout")) - defer cancel() - - objFromLegacy, err := d.Legacy.Get(ctx, name, options) - d.recordLegacyDuration(err != nil, mode3Str, d.resource, method, startLegacy) - if err != nil { - log.Error(err, "unable to get object in legacy storage") - cancel() - } - - areEqual := Compare(storageObj, objFromLegacy) - d.recordOutcome(mode3Str, name, areEqual, method) - if !areEqual { - log.WithValues("name", name).Info("object from legacy and storage are not equal") - } - return err -} - -// List overrides the behavior of the generic DualWriter and reads only from Unified Store. -func (d *DualWriterMode3) List(ctx context.Context, options *metainternalversion.ListOptions) (runtime.Object, error) { - var method = "list" - log := d.Log.WithValues("resourceVersion", options.ResourceVersion, "method", method) - ctx = klog.NewContext(ctx, log) - - startStorage := time.Now() - objFromStorage, err := d.Storage.List(ctx, options) - d.recordStorageDuration(err != nil, mode3Str, d.resource, method, startStorage) - if err != nil { - log.Error(err, "unable to list object in storage") - } - return objFromStorage, err -} - -func (d *DualWriterMode3) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) { - var method = "delete" - log := d.Log.WithValues("name", name, "method", method) - ctx = klog.NewContext(ctx, d.Log) - - // delete from legacy first, and then unistore. Will return a failure if either fails, - // unless its a 404. - // - // we want to delete from legacy first, otherwise if the delete from unistore was successful, - // but legacy failed, the user would get a failure, but not be able to retry the delete - // as they would not be able to see the object in unistore anymore. - startLegacy := time.Now() - objFromLegacy, asyncLegacy, err := d.Legacy.Delete(ctx, name, deleteValidation, options) - d.recordLegacyDuration(err != nil && !apierrors.IsNotFound(err), mode3Str, d.resource, method, startLegacy) - if err != nil { - if !apierrors.IsNotFound(err) { - log.WithValues("object", objFromLegacy).Error(err, "could not delete from legacy store") - return objFromLegacy, asyncLegacy, err - } - } - - startStorage := time.Now() - objFromStorage, asyncStorage, err := d.Storage.Delete(ctx, name, deleteValidation, options) - d.recordStorageDuration(err != nil && !apierrors.IsNotFound(err), mode3Str, d.resource, method, startStorage) - if err != nil { - return nil, false, err - } - - areEqual := Compare(objFromStorage, objFromLegacy) - d.recordOutcome(mode3Str, name, areEqual, method) - if !areEqual { - log.WithValues("name", name).Info("object from legacy and storage are not equal") - } - - return objFromStorage, asyncStorage, err -} - -// Update overrides the behavior of the generic DualWriter and writes first to Storage and then to LegacyStorage. -func (d *DualWriterMode3) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) { - var method = "update" - log := d.Log.WithValues("name", name, "method", method) - ctx = klog.NewContext(ctx, log) - // The incoming RV is not stable -- it may be from legacy or storage! - // This sets a flag in the context and our apistore is more lenient when it exists - ctx = context.WithValue(ctx, dualWriteContextKey{}, true) - - // update in legacy first, and then unistore. Will return a failure if either fails. - // - // we want to update in legacy first, otherwise if the update from unistore was successful, - // but legacy failed, the user would get a failure, but see the update did apply to the source - // of truth, and be less likely to retry to save (and get the stores in sync again) - - startLegacy := time.Now() - objFromLegacy, createdLegacy, err := d.Legacy.Update(ctx, name, objInfo, createValidation, updateValidation, forceAllowCreate, options) - if err != nil { - log.WithValues("object", objFromLegacy).Error(err, "could not update in legacy storage") - d.recordLegacyDuration(true, mode2Str, d.resource, "update", startLegacy) - return objFromLegacy, createdLegacy, err - } - d.recordLegacyDuration(false, mode2Str, d.resource, "update", startLegacy) - - startStorage := time.Now() - objFromStorage, created, err := d.Storage.Update(ctx, name, objInfo, createValidation, updateValidation, forceAllowCreate, options) - if err != nil { - log.WithValues("object", objFromStorage).Error(err, "could not update in storage") - d.recordStorageDuration(true, mode2Str, d.resource, "update", startStorage) - return objFromStorage, created, err - } - - areEqual := Compare(objFromStorage, objFromLegacy) - d.recordOutcome(mode3Str, name, areEqual, method) - if !areEqual { - log.WithValues("name", name).Info("object from legacy and storage are not equal") - } - - return objFromStorage, created, err -} - -// DeleteCollection overrides the behavior of the generic DualWriter and deletes from both LegacyStorage and Storage. -func (d *DualWriterMode3) DeleteCollection(ctx context.Context, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions, listOptions *metainternalversion.ListOptions) (runtime.Object, error) { - var method = "delete-collection" - log := d.Log.WithValues("resourceVersion", listOptions.ResourceVersion, "method", method) - ctx = klog.NewContext(ctx, log) - - // delete from legacy first, and anything that is successful can be deleted in unistore too. - // - // we want to delete from legacy first, otherwise if the delete from unistore was successful, - // but legacy failed, the user would get a failure, but not be able to retry the delete - // as they would not be able to see the object in unistore anymore. - - startLegacy := time.Now() - deletedLegacy, err := d.Legacy.DeleteCollection(ctx, deleteValidation, options, listOptions) - if err != nil { - log.WithValues("deleted", deletedLegacy).Error(err, "failed to delete collection successfully from legacy storage") - d.recordLegacyDuration(true, mode3Str, d.resource, method, startLegacy) - return deletedLegacy, err - } - d.recordLegacyDuration(false, mode3Str, d.resource, method, startLegacy) - - legacyList, err := meta.ExtractList(deletedLegacy) - if err != nil { - log.Error(err, "unable to extract list from legacy storage") - return nil, err - } - - // Only the items deleted by the legacy DeleteCollection call are selected for deletion by Storage. - _, err = parseList(legacyList) - if err != nil { - return nil, err - } - - startStorage := time.Now() - deletedStorage, err := d.Storage.DeleteCollection(ctx, deleteValidation, options, listOptions) - if err != nil { - log.WithValues("deleted", deletedStorage).Error(err, "failed to delete collection successfully from Storage") - d.recordStorageDuration(true, mode3Str, d.resource, method, startStorage) - return deletedStorage, err - } - d.recordStorageDuration(false, mode3Str, d.resource, method, startStorage) - - areEqual := Compare(deletedStorage, deletedLegacy) - d.recordOutcome(mode3Str, getName(deletedLegacy), areEqual, method) - if !areEqual { - log.Info("object from legacy and storage are not equal") - } - - return deletedStorage, err -} - -func (d *DualWriterMode3) Watch(ctx context.Context, options *metainternalversion.ListOptions) (watch.Interface, error) { - var method = "watch" - d.Log.WithValues("method", method, "mode", mode3Str).Info("starting to watch") - return d.watchImp.Watch(ctx, options) -} - -func (d *DualWriterMode3) Destroy() { - d.Storage.Destroy() - d.Legacy.Destroy() -} - -func (d *DualWriterMode3) GetSingularName() string { - return d.Storage.GetSingularName() -} - -func (d *DualWriterMode3) NamespaceScoped() bool { - return d.Storage.NamespaceScoped() -} - -func (d *DualWriterMode3) New() runtime.Object { - return d.Storage.New() -} - -func (d *DualWriterMode3) NewList() runtime.Object { - return d.Storage.NewList() -} - -func (d *DualWriterMode3) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) { - return d.Storage.ConvertToTable(ctx, object, tableOptions) -} diff --git a/pkg/apiserver/rest/metrics.go b/pkg/apiserver/rest/metrics.go index 0b15a7a4ff5..9380e948f75 100644 --- a/pkg/apiserver/rest/metrics.go +++ b/pkg/apiserver/rest/metrics.go @@ -10,43 +10,10 @@ import ( ) type dualWriterMetrics struct { - legacy *prometheus.HistogramVec - storage *prometheus.HistogramVec - outcome *prometheus.HistogramVec syncer *prometheus.HistogramVec syncerOutcome *prometheus.HistogramVec } -// DualWriterStorageDuration is a metric summary for dual writer storage duration per mode -var DualWriterStorageDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{ - Name: "dual_writer_storage_duration_seconds", - Help: "Histogram for the runtime of dual writer storage duration per mode", - Namespace: "grafana", - NativeHistogramBucketFactor: 1.1, -}, []string{"is_error", "mode", "resource", "method"}) - -// DualWriterLegacyDuration is a metric summary for dual writer legacy duration per mode -var DualWriterLegacyDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{ - Name: "dual_writer_legacy_duration_seconds", - Help: "Histogram for the runtime of dual writer legacy duration per mode", - Namespace: "grafana", - NativeHistogramBucketFactor: 1.1, -}, []string{"is_error", "mode", "resource", "method"}) - -// DualWriterOutcome is a metric summary for dual writer outcome comparison between the 2 stores per mode -var DualWriterOutcome = prometheus.NewHistogramVec(prometheus.HistogramOpts{ - Name: "dual_writer_outcome", - Help: "Histogram for the runtime of dual writer outcome comparison between the 2 stores per mode", - Namespace: "grafana", - NativeHistogramBucketFactor: 1.1, -}, []string{"mode", "name", "method"}) - -var DualWriterReadLegacyCounts = prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "dual_writer_read_legacy_count", - Help: "Histogram for the runtime of dual writer reads from legacy", - Namespace: "grafana", -}, []string{"resource", "method"}) - // DualWriterSyncerDuration is a metric summary for dual writer sync duration per mode var DualWriterSyncerDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{ Name: "dual_writer_data_syncer_duration_seconds", @@ -65,39 +32,15 @@ var DualWriterDataSyncerOutcome = prometheus.NewHistogramVec(prometheus.Histogra func (m *dualWriterMetrics) init(reg prometheus.Registerer) { log := klog.NewKlogr() - m.legacy = DualWriterLegacyDuration - m.storage = DualWriterStorageDuration - m.outcome = DualWriterOutcome m.syncer = DualWriterSyncerDuration m.syncerOutcome = DualWriterDataSyncerOutcome - errLegacy := reg.Register(m.legacy) - errStorage := reg.Register(m.storage) - errOutcome := reg.Register(m.outcome) errSyncer := reg.Register(m.syncer) errSyncerOutcome := reg.Register(m.syncerOutcome) - if errLegacy != nil || errStorage != nil || errOutcome != nil || errSyncer != nil || errSyncerOutcome != nil { + if errSyncer != nil || errSyncerOutcome != nil { log.Info("cloud migration metrics already registered") } } -func (m *dualWriterMetrics) recordLegacyDuration(isError bool, mode string, resource string, method string, startFrom time.Time) { - duration := time.Since(startFrom).Seconds() - m.legacy.WithLabelValues(strconv.FormatBool(isError), mode, resource, method).Observe(duration) -} - -func (m *dualWriterMetrics) recordStorageDuration(isError bool, mode string, resource string, method string, startFrom time.Time) { - duration := time.Since(startFrom).Seconds() - m.storage.WithLabelValues(strconv.FormatBool(isError), mode, resource, method).Observe(duration) -} - -func (m *dualWriterMetrics) recordOutcome(mode string, name string, areEqual bool, method string) { - var observeValue float64 - if !areEqual { - observeValue = 1 - } - m.outcome.WithLabelValues(mode, name, method).Observe(observeValue) -} - func (m *dualWriterMetrics) recordDataSyncerDuration(isError bool, mode DualWriterMode, resource string, startFrom time.Time) { duration := time.Since(startFrom).Seconds() m.syncer.WithLabelValues(strconv.FormatBool(isError), fmt.Sprintf("%d", mode), resource).Observe(duration) diff --git a/pkg/apiserver/rest/storage_mocks_test.go b/pkg/apiserver/rest/storage_mocks_test.go index 3baaa14c526..a85a372c5e1 100644 --- a/pkg/apiserver/rest/storage_mocks_test.go +++ b/pkg/apiserver/rest/storage_mocks_test.go @@ -3,14 +3,26 @@ package rest import ( "context" "errors" + "time" + "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/mock" metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/apis/example" "k8s.io/apiserver/pkg/registry/rest" ) +var now = time.Now() + +var exampleObj = &example.Pod{TypeMeta: metav1.TypeMeta{Kind: "foo"}, ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1", CreationTimestamp: metav1.Time{}, GenerateName: "foo"}, Spec: example.PodSpec{}, Status: example.PodStatus{StartTime: &metav1.Time{Time: now}}} +var anotherObj = &example.Pod{TypeMeta: metav1.TypeMeta{Kind: "foo"}, ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "2", GenerateName: "foo"}, Spec: example.PodSpec{}, Status: example.PodStatus{StartTime: &metav1.Time{Time: now}}} +var exampleList = &example.PodList{TypeMeta: metav1.TypeMeta{Kind: "foo"}, ListMeta: metav1.ListMeta{}, Items: []example.Pod{*exampleObj}} +var anotherList = &example.PodList{Items: []example.Pod{*anotherObj}} + +var p = prometheus.NewRegistry() + type storageMock struct { *mock.Mock Storage @@ -104,12 +116,3 @@ func (m storageMock) DeleteCollection(ctx context.Context, deleteValidation rest } return args.Get(0).(runtime.Object), args.Error(1) } - -type updatedObjInfoObj struct{} - -func (u updatedObjInfoObj) UpdatedObject(ctx context.Context, oldObj runtime.Object) (newObj runtime.Object, err error) { // nolint:staticcheck - // nolint:staticcheck - oldObj = exampleObj - return oldObj, nil -} -func (u updatedObjInfoObj) Preconditions() *metav1.Preconditions { return &metav1.Preconditions{} } diff --git a/pkg/services/apiserver/builder/helper.go b/pkg/services/apiserver/builder/helper.go index 5fdf11c51a8..cb6d2626061 100644 --- a/pkg/services/apiserver/builder/helper.go +++ b/pkg/services/apiserver/builder/helper.go @@ -372,7 +372,7 @@ func InstallAPIs( if currentMode != mode { klog.Warningf("Requested DualWrite mode: %d, but using %d for %+v", mode, currentMode, gr) } - return grafanarest.NewDualWriter(currentMode, legacy, storage, reg, key), nil + return dualwrite.NewDualWriter(gr, currentMode, legacy, storage) } } diff --git a/pkg/storage/legacysql/dualwrite/dualwriter.go b/pkg/storage/legacysql/dualwrite/dualwriter.go new file mode 100644 index 00000000000..242b401b856 --- /dev/null +++ b/pkg/storage/legacysql/dualwrite/dualwriter.go @@ -0,0 +1,229 @@ +package dualwrite + +import ( + "context" + "fmt" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" + metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/registry/rest" + + "github.com/grafana/grafana-app-sdk/logging" + grafanarest "github.com/grafana/grafana/pkg/apiserver/rest" +) + +var ( + _ grafanarest.Storage = (*dualWriter)(nil) +) + +// dualWriter will write first to legacy, then to unified keeping the same internal ID +type dualWriter struct { + legacy grafanarest.Storage + unified grafanarest.Storage + readUnified bool + errorIsOK bool // in "mode1" we try writing both -- but don't block on unified write errors + log logging.Logger +} + +func (d *dualWriter) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { + // Call get (send read traffic in cloud) + unifiedGet, unifiedErr := d.unified.Get(ctx, name, options) + if d.readUnified { + return unifiedGet, unifiedErr + } + + legacyGet, err := d.legacy.Get(ctx, name, options) + if err != nil { + return nil, err + } + + if unifiedErr != nil && !apierrors.IsNotFound(unifiedErr) && !d.errorIsOK { + return nil, unifiedErr // the unified error + } + return legacyGet, nil +} + +func (d *dualWriter) List(ctx context.Context, options *metainternalversion.ListOptions) (runtime.Object, error) { + // Call list (send read traffic in cloud) + unifiedList, err := d.unified.List(ctx, options) + if d.readUnified { + return unifiedList, err + } + + if err != nil && !d.errorIsOK { + return nil, err + } + + return d.legacy.List(ctx, options) +} + +// Create overrides the behavior of the generic DualWriter and writes to LegacyStorage and Storage. +func (d *dualWriter) Create(ctx context.Context, in runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) { + log := d.log.With("method", "Create").WithContext(ctx) + + accIn, err := meta.Accessor(in) + if err != nil { + return nil, err + } + + if accIn.GetUID() != "" { + return nil, fmt.Errorf("UID should not be: %v", accIn.GetUID()) + } + + if accIn.GetName() == "" && accIn.GetGenerateName() == "" { + return nil, fmt.Errorf("name or generatename have to be set") + } + + // create in legacy first, and then unistore. if unistore fails, but legacy succeeds, + // will try to cleanup the object in legacy. + createdFromLegacy, err := d.legacy.Create(ctx, in, createValidation, options) + if err != nil { + log.Error("unable to create object in legacy storage", "err", err) + return createdFromLegacy, err + } + + createdCopy := createdFromLegacy.DeepCopyObject() + accCreated, err := meta.Accessor(createdCopy) + if err != nil { + return createdFromLegacy, err + } + accCreated.SetResourceVersion("") + accCreated.SetUID("") + + storageObj, errObjectSt := d.unified.Create(ctx, createdCopy, createValidation, options) + if errObjectSt != nil { + log.Error("unable to create object in unified storage", "err", err) + if d.errorIsOK { + return createdFromLegacy, nil + } + + // if we cannot create in unistore, attempt to clean up legacy + _, _, err = d.legacy.Delete(ctx, accCreated.GetName(), nil, &metav1.DeleteOptions{}) + if err != nil { + log.Error("unable to cleanup object in legacy storage", "err", err) + } + } + + if d.readUnified { + return storageObj, errObjectSt + } + return createdFromLegacy, errObjectSt +} + +func (d *dualWriter) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) { + // delete from legacy first, and then unistore. Will return a failure if either fails, + // unless its a 404. + // + // we want to delete from legacy first, otherwise if the delete from unistore was successful, + // but legacy failed, the user would get a failure, but not be able to retry the delete + // as they would not be able to see the object in unistore anymore. + objFromLegacy, asyncLegacy, err := d.legacy.Delete(ctx, name, deleteValidation, options) + if err != nil && !d.readUnified { + return objFromLegacy, asyncLegacy, err + } + + objFromStorage, asyncStorage, err := d.unified.Delete(ctx, name, deleteValidation, options) + if err != nil && apierrors.IsNotFound(err) || d.errorIsOK { + err = nil // clear the error + } + + if d.readUnified { + return objFromStorage, asyncStorage, err + } + + return objFromLegacy, asyncLegacy, err +} + +// Update overrides the behavior of the generic DualWriter and writes first to Storage and then to LegacyStorage. +func (d *dualWriter) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) { + log := d.log.With("method", "Update").WithContext(ctx) + + // The incoming RV is not stable -- it may be from legacy or storage! + // This sets a flag in the context and our apistore is more lenient when it exists + ctx = grafanarest.WithDualWriteUpdate(ctx) + + // update in legacy first, and then unistore. Will return a failure if either fails. + // + // we want to update in legacy first, otherwise if the update from unistore was successful, + // but legacy failed, the user would get a failure, but see the update did apply to the source + // of truth, and be less likely to retry to save (and get the stores in sync again) + + objFromLegacy, createdLegacy, err := d.legacy.Update(ctx, name, objInfo, createValidation, updateValidation, forceAllowCreate, options) + if err != nil { + log.With("object", objFromLegacy).Error("could not update in legacy storage", "err", err) + return objFromLegacy, createdLegacy, err + } + + objFromStorage, created, err := d.unified.Update(ctx, name, objInfo, createValidation, updateValidation, forceAllowCreate, options) + if err != nil { + log.With("object", objFromStorage).Error("could not update in storage", "err", err) + if d.errorIsOK { + return objFromLegacy, createdLegacy, nil + } + } + + if d.readUnified { + return objFromStorage, created, err + } + + return objFromLegacy, createdLegacy, err +} + +// DeleteCollection overrides the behavior of the generic DualWriter and deletes from both LegacyStorage and Storage. +func (d *dualWriter) DeleteCollection(ctx context.Context, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions, listOptions *metainternalversion.ListOptions) (runtime.Object, error) { + log := d.log.With("method", "DeleteCollection", "resourceVersion", listOptions.ResourceVersion).WithContext(ctx) + + // delete from legacy first, and anything that is successful can be deleted in unistore too. + // + // we want to delete from legacy first, otherwise if the delete from unistore was successful, + // but legacy failed, the user would get a failure, but not be able to retry the delete + // as they would not be able to see the object in unistore anymore. + + deletedLegacy, err := d.legacy.DeleteCollection(ctx, deleteValidation, options, listOptions) + if err != nil { + log.With("deleted", deletedLegacy).Error("failed to delete collection successfully from legacy storage", "err", err) + return deletedLegacy, err + } + + deletedStorage, err := d.unified.DeleteCollection(ctx, deleteValidation, options, listOptions) + if err != nil { + log.With("deleted", deletedStorage).Error("failed to delete collection successfully from Storage", "err", err) + if d.errorIsOK { + return deletedLegacy, nil + } + } + + if d.readUnified { + return deletedStorage, err + } + + return deletedLegacy, err +} + +func (d *dualWriter) Destroy() { + d.legacy.Destroy() + d.unified.Destroy() +} + +func (d *dualWriter) GetSingularName() string { + return d.unified.GetSingularName() +} + +func (d *dualWriter) NamespaceScoped() bool { + return d.unified.NamespaceScoped() +} + +func (d *dualWriter) New() runtime.Object { + return d.unified.New() +} + +func (d *dualWriter) NewList() runtime.Object { + return d.unified.NewList() +} + +func (d *dualWriter) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) { + return d.unified.ConvertToTable(ctx, object, tableOptions) +} diff --git a/pkg/apiserver/rest/dualwriter_mode1_test.go b/pkg/storage/legacysql/dualwrite/dualwriter_mode1_test.go similarity index 57% rename from pkg/apiserver/rest/dualwriter_mode1_test.go rename to pkg/storage/legacysql/dualwrite/dualwriter_mode1_test.go index 398b25a3acc..74a73a573c2 100644 --- a/pkg/apiserver/rest/dualwriter_mode1_test.go +++ b/pkg/storage/legacysql/dualwrite/dualwriter_mode1_test.go @@ -1,4 +1,4 @@ -package rest +package dualwrite import ( "context" @@ -14,6 +14,8 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apiserver/pkg/apis/example" + + "github.com/grafana/grafana/pkg/apiserver/rest" ) var now = time.Now() @@ -26,7 +28,6 @@ var exampleList = &example.PodList{TypeMeta: metav1.TypeMeta{Kind: "foo"}, ListM var anotherList = &example.PodList{Items: []example.Pod{*anotherObj}} var p = prometheus.NewRegistry() -var kind = "foo" func TestMode1_Create(t *testing.T) { type testCase struct { @@ -60,8 +61,8 @@ func TestMode1_Create(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - l := (Storage)(nil) - s := (Storage)(nil) + l := (rest.Storage)(nil) + s := (rest.Storage)(nil) ls := storageMock{&mock.Mock{}, l} us := storageMock{&mock.Mock{}, s} @@ -73,7 +74,8 @@ func TestMode1_Create(t *testing.T) { tt.setupStorageFn(us.Mock) } - dw := NewDualWriter(Mode1, ls, us, p, kind) + dw, err := NewDualWriter(kind, rest.Mode1, ls, us) + require.NoError(t, err) obj, err := dw.Create(context.Background(), tt.input, func(context.Context, runtime.Object) error { return nil }, &metav1.CreateOptions{}) @@ -90,63 +92,6 @@ func TestMode1_Create(t *testing.T) { } } -func TestMode1_CreateOnUnifiedStorage(t *testing.T) { - ctxCanceled, cancel := context.WithCancel(context.TODO()) - cancel() - - type testCase struct { - name string - input runtime.Object - ctx *context.Context - setupLegacyFn func(m *mock.Mock) - setupStorageFn func(m *mock.Mock) - } - tests := - []testCase{ - { - name: "Create on unified storage", - input: exampleObj, - setupStorageFn: func(m *mock.Mock) { - m.On("Create", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(exampleObjNoRV, nil) - }, - }, - { - name: "Create on unified storage works even if parent context is canceled", - input: exampleObj, - ctx: &ctxCanceled, - setupStorageFn: func(m *mock.Mock) { - m.On("Create", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(exampleObjNoRV, nil) - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - l := (Storage)(nil) - s := (Storage)(nil) - - ls := storageMock{&mock.Mock{}, l} - us := storageMock{&mock.Mock{}, s} - - if tt.setupLegacyFn != nil { - tt.setupLegacyFn(ls.Mock) - } - if tt.setupStorageFn != nil { - tt.setupStorageFn(us.Mock) - } - - ctx := context.TODO() - if tt.ctx != nil { - ctx = *tt.ctx - } - - dw := NewDualWriter(Mode1, ls, us, p, kind) - err := dw.(*DualWriterMode1).createOnUnifiedStorage(ctx, func(context.Context, runtime.Object) error { return nil }, tt.input, &metav1.CreateOptions{}) - require.NoError(t, err) - }) - } -} - func TestMode1_Get(t *testing.T) { type testCase struct { setupLegacyFn func(m *mock.Mock, name string) @@ -190,8 +135,8 @@ func TestMode1_Get(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - l := (Storage)(nil) - s := (Storage)(nil) + l := (rest.Storage)(nil) + s := (rest.Storage)(nil) ls := storageMock{&mock.Mock{}, l} us := storageMock{&mock.Mock{}, s} @@ -203,7 +148,8 @@ func TestMode1_Get(t *testing.T) { tt.setupStorageFn(us.Mock, name) } - dw := NewDualWriter(Mode1, ls, us, p, kind) + dw, err := NewDualWriter(kind, rest.Mode1, ls, us) + require.NoError(t, err) obj, err := dw.Get(context.Background(), name, &metav1.GetOptions{}) @@ -220,62 +166,6 @@ func TestMode1_Get(t *testing.T) { } } -func TestMode1_GetFromUnifiedStorage(t *testing.T) { - ctxCanceled, cancel := context.WithCancel(context.TODO()) - cancel() - - type testCase struct { - setupLegacyFn func(m *mock.Mock, name string) - setupStorageFn func(m *mock.Mock, name string) - ctx *context.Context - name string - } - tests := - []testCase{ - { - name: "should succeed when getting an object from UnifiedStorage", - setupStorageFn: func(m *mock.Mock, name string) { - m.On("Get", mock.Anything, name, mock.Anything).Return(exampleObj, nil) - }, - }, - { - name: "should succeed when getting an object from UnifiedStorage even if parent context is canceled", - ctx: &ctxCanceled, - setupStorageFn: func(m *mock.Mock, name string) { - m.On("Get", mock.Anything, name, mock.Anything).Return(exampleObj, nil) - }, - }, - } - - name := "foo" - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - l := (Storage)(nil) - s := (Storage)(nil) - - ls := storageMock{&mock.Mock{}, l} - us := storageMock{&mock.Mock{}, s} - - if tt.setupLegacyFn != nil { - tt.setupLegacyFn(ls.Mock, name) - } - if tt.setupStorageFn != nil { - tt.setupStorageFn(us.Mock, name) - } - - ctx := context.TODO() - if tt.ctx != nil { - ctx = *tt.ctx - } - - dw := NewDualWriter(Mode1, ls, us, p, kind) - err := dw.(*DualWriterMode1).getFromUnifiedStorage(ctx, exampleObj, name, &metav1.GetOptions{}) - require.NoError(t, err) - }) - } -} - func TestMode1_List(t *testing.T) { type testCase struct { setupLegacyFn func(m *mock.Mock) @@ -308,8 +198,8 @@ func TestMode1_List(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - l := (Storage)(nil) - s := (Storage)(nil) + l := (rest.Storage)(nil) + s := (rest.Storage)(nil) ls := storageMock{&mock.Mock{}, l} us := storageMock{&mock.Mock{}, s} @@ -321,9 +211,10 @@ func TestMode1_List(t *testing.T) { tt.setupStorageFn(us.Mock) } - dw := NewDualWriter(Mode1, ls, us, p, kind) + dw, err := NewDualWriter(kind, rest.Mode1, ls, us) + require.NoError(t, err) - _, err := dw.List(context.Background(), &metainternalversion.ListOptions{}) + _, err = dw.List(context.Background(), &metainternalversion.ListOptions{}) if tt.wantErr { require.Error(t, err) @@ -333,64 +224,6 @@ func TestMode1_List(t *testing.T) { } } -func TestMode1_ListFromUnifiedStorage(t *testing.T) { - ctxCanceled, cancel := context.WithCancel(context.TODO()) - cancel() - - type testCase struct { - ctx *context.Context - name string - setupLegacyFn func(m *mock.Mock) - setupStorageFn func(m *mock.Mock) - } - tests := - []testCase{ - { - name: "should succeed when listing from UnifiedStorage", - setupStorageFn: func(m *mock.Mock) { - m.On("List", mock.Anything, mock.Anything).Return(anotherList, nil) - }, - setupLegacyFn: func(m *mock.Mock) { - m.On("List", mock.Anything, mock.Anything).Return(anotherList, nil) - }, - }, - { - name: "should succeed when listing from UnifiedStorage even if parent context is canceled", - ctx: &ctxCanceled, - setupStorageFn: func(m *mock.Mock) { - m.On("List", mock.Anything, mock.Anything).Return(anotherList, nil) - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - l := (Storage)(nil) - s := (Storage)(nil) - - ls := storageMock{&mock.Mock{}, l} - us := storageMock{&mock.Mock{}, s} - - if tt.setupLegacyFn != nil { - tt.setupLegacyFn(ls.Mock) - } - if tt.setupStorageFn != nil { - tt.setupStorageFn(us.Mock) - } - - ctx := context.TODO() - if tt.ctx != nil { - ctx = *tt.ctx - } - - dw := NewDualWriter(Mode1, ls, us, p, kind) - - err := dw.(*DualWriterMode1).listFromUnifiedStorage(ctx, &metainternalversion.ListOptions{}, anotherList) - require.NoError(t, err) - }) - } -} - func TestMode1_Delete(t *testing.T) { type testCase struct { setupLegacyFn func(m *mock.Mock, name string) @@ -434,8 +267,8 @@ func TestMode1_Delete(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - l := (Storage)(nil) - s := (Storage)(nil) + l := (rest.Storage)(nil) + s := (rest.Storage)(nil) ls := storageMock{&mock.Mock{}, l} us := storageMock{&mock.Mock{}, s} @@ -447,7 +280,8 @@ func TestMode1_Delete(t *testing.T) { tt.setupStorageFn(us.Mock, name) } - dw := NewDualWriter(Mode1, ls, us, p, kind) + dw, err := NewDualWriter(kind, rest.Mode1, ls, us) + require.NoError(t, err) obj, _, err := dw.Delete(context.Background(), name, func(ctx context.Context, obj runtime.Object) error { return nil }, &metav1.DeleteOptions{}) @@ -463,63 +297,6 @@ func TestMode1_Delete(t *testing.T) { } } -func TestMode1_DeleteFromUnifiedStorage(t *testing.T) { - ctxCanceled, cancel := context.WithCancel(context.TODO()) - cancel() - - type testCase struct { - ctx *context.Context - setupLegacyFn func(m *mock.Mock, name string) - setupStorageFn func(m *mock.Mock, name string) - name string - } - tests := - []testCase{ - { - name: "should succeed when deleting an object from UnifiedStorage", - setupStorageFn: func(m *mock.Mock, name string) { - m.On("Delete", mock.Anything, name, mock.Anything, mock.Anything).Return(exampleObj, false, nil) - }, - }, - { - name: "should succeed when deleting an object from UnifiedStorage even if parent context is canceled", - ctx: &ctxCanceled, - setupStorageFn: func(m *mock.Mock, name string) { - m.On("Delete", mock.Anything, name, mock.Anything, mock.Anything).Return(exampleObj, false, nil) - }, - }, - } - - name := "foo" - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - l := (Storage)(nil) - s := (Storage)(nil) - - ls := storageMock{&mock.Mock{}, l} - us := storageMock{&mock.Mock{}, s} - - if tt.setupLegacyFn != nil { - tt.setupLegacyFn(ls.Mock, name) - } - if tt.setupStorageFn != nil { - tt.setupStorageFn(us.Mock, name) - } - - ctx := context.TODO() - if tt.ctx != nil { - ctx = *tt.ctx - } - - dw := NewDualWriter(Mode1, ls, us, p, kind) - - err := dw.(*DualWriterMode1).deleteFromUnifiedStorage(ctx, exampleObj, name, func(ctx context.Context, obj runtime.Object) error { return nil }, &metav1.DeleteOptions{}) - require.NoError(t, err) - }) - } -} - func TestMode1_DeleteCollection(t *testing.T) { type testCase struct { input *metav1.DeleteOptions @@ -565,8 +342,8 @@ func TestMode1_DeleteCollection(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - l := (Storage)(nil) - s := (Storage)(nil) + l := (rest.Storage)(nil) + s := (rest.Storage)(nil) ls := storageMock{&mock.Mock{}, l} us := storageMock{&mock.Mock{}, s} @@ -578,7 +355,8 @@ func TestMode1_DeleteCollection(t *testing.T) { tt.setupStorageFn(us.Mock, tt.input) } - dw := NewDualWriter(Mode1, ls, us, p, kind) + dw, err := NewDualWriter(kind, rest.Mode1, ls, us) + require.NoError(t, err) obj, err := dw.DeleteCollection(context.Background(), func(ctx context.Context, obj runtime.Object) error { return nil }, tt.input, &metainternalversion.ListOptions{}) @@ -594,64 +372,6 @@ func TestMode1_DeleteCollection(t *testing.T) { } } -func TestMode1_DeleteCollectionFromUnifiedStorage(t *testing.T) { - ctxCanceled, cancel := context.WithCancel(context.TODO()) - cancel() - - type testCase struct { - ctx *context.Context - setupLegacyFn func(m *mock.Mock) - setupStorageFn func(m *mock.Mock) - name string - input *metav1.DeleteOptions - } - tests := - []testCase{ - { - name: "should succeed when deleting a collection from UnifiedStorage", - input: &metav1.DeleteOptions{TypeMeta: metav1.TypeMeta{Kind: "foo"}}, - setupStorageFn: func(m *mock.Mock) { - m.On("DeleteCollection", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(exampleObj, nil) - }, - }, - { - name: "should succeed when deleting a collection from UnifiedStorage even if parent context is canceled", - input: &metav1.DeleteOptions{TypeMeta: metav1.TypeMeta{Kind: "foo"}}, - ctx: &ctxCanceled, - setupStorageFn: func(m *mock.Mock) { - m.On("DeleteCollection", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(exampleObj, nil) - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - l := (Storage)(nil) - s := (Storage)(nil) - - ls := storageMock{&mock.Mock{}, l} - us := storageMock{&mock.Mock{}, s} - - if tt.setupLegacyFn != nil { - tt.setupLegacyFn(ls.Mock) - } - if tt.setupStorageFn != nil { - tt.setupStorageFn(us.Mock) - } - - ctx := context.TODO() - if tt.ctx != nil { - ctx = *tt.ctx - } - - dw := NewDualWriter(Mode1, ls, us, p, kind) - - err := dw.(*DualWriterMode1).deleteCollectionFromUnifiedStorage(ctx, exampleObj, func(ctx context.Context, obj runtime.Object) error { return nil }, tt.input, &metainternalversion.ListOptions{}) - require.NoError(t, err) - }) - } -} - func TestMode1_Update(t *testing.T) { type testCase struct { setupLegacyFn func(m *mock.Mock, input string) @@ -695,8 +415,8 @@ func TestMode1_Update(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - l := (Storage)(nil) - s := (Storage)(nil) + l := (rest.Storage)(nil) + s := (rest.Storage)(nil) ls := storageMock{&mock.Mock{}, l} us := storageMock{&mock.Mock{}, s} @@ -708,7 +428,8 @@ func TestMode1_Update(t *testing.T) { tt.setupStorageFn(us.Mock, name) } - dw := NewDualWriter(Mode1, ls, us, p, kind) + dw, err := NewDualWriter(kind, rest.Mode1, ls, us) + require.NoError(t, err) obj, _, err := dw.Update(context.Background(), name, updatedObjInfoObj{}, func(ctx context.Context, obj runtime.Object) error { return nil }, func(ctx context.Context, obj, old runtime.Object) error { return nil }, false, &metav1.UpdateOptions{}) @@ -722,72 +443,3 @@ func TestMode1_Update(t *testing.T) { }) } } - -func TestMode1_UpdateOnUnifiedStorage(t *testing.T) { - ctxCanceled, cancel := context.WithCancel(context.TODO()) - cancel() - - type testCase struct { - ctx *context.Context - setupLegacyFn func(m *mock.Mock, input string) - setupStorageFn func(m *mock.Mock, input string) - setupGetFn func(m *mock.Mock, input string) - name string - } - tests := - []testCase{ - { - name: "should succeed when updating an object on UnifiedStorage", - setupStorageFn: func(m *mock.Mock, input string) { - m.On("Update", mock.Anything, input, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(anotherObj, false, nil) - }, - setupGetFn: func(m *mock.Mock, input string) { - m.On("Get", mock.Anything, input, mock.Anything).Return(exampleObj, nil) - }, - }, - { - name: "should succeed when updating an object on UnifiedStorage even if parent context is canceled", - ctx: &ctxCanceled, - setupStorageFn: func(m *mock.Mock, input string) { - m.On("Update", mock.Anything, input, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(anotherObj, false, nil) - }, - setupGetFn: func(m *mock.Mock, input string) { - m.On("Get", mock.Anything, input, mock.Anything).Return(exampleObj, nil) - }, - }, - } - - name := "foo" - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - l := (Storage)(nil) - s := (Storage)(nil) - - ls := storageMock{&mock.Mock{}, l} - us := storageMock{&mock.Mock{}, s} - - if tt.setupLegacyFn != nil { - tt.setupLegacyFn(ls.Mock, name) - } - if tt.setupStorageFn != nil { - tt.setupStorageFn(us.Mock, name) - } - - if tt.setupGetFn != nil { - tt.setupGetFn(ls.Mock, name) - tt.setupGetFn(us.Mock, name) - } - - ctx := context.TODO() - if tt.ctx != nil { - ctx = *tt.ctx - } - - dw := NewDualWriter(Mode1, ls, us, p, kind) - - err := dw.(*DualWriterMode1).updateOnUnifiedStorageMode1(ctx, exampleObj, name, updatedObjInfoObj{}, func(ctx context.Context, obj runtime.Object) error { return nil }, func(ctx context.Context, obj, old runtime.Object) error { return nil }, false, &metav1.UpdateOptions{}) - require.NoError(t, err) - }) - } -} diff --git a/pkg/apiserver/rest/dualwriter_mode2_test.go b/pkg/storage/legacysql/dualwrite/dualwriter_mode2_test.go similarity index 94% rename from pkg/apiserver/rest/dualwriter_mode2_test.go rename to pkg/storage/legacysql/dualwrite/dualwriter_mode2_test.go index b0d653053df..cd1e87b0b9a 100644 --- a/pkg/apiserver/rest/dualwriter_mode2_test.go +++ b/pkg/storage/legacysql/dualwrite/dualwriter_mode2_test.go @@ -1,4 +1,4 @@ -package rest +package dualwrite import ( "context" @@ -12,6 +12,8 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + + "github.com/grafana/grafana/pkg/apiserver/rest" ) var createFn = func(context.Context, runtime.Object) error { return nil } @@ -54,8 +56,8 @@ func TestMode2_Create(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - l := (Storage)(nil) - s := (Storage)(nil) + l := (rest.Storage)(nil) + s := (rest.Storage)(nil) ls := storageMock{&mock.Mock{}, l} us := storageMock{&mock.Mock{}, s} @@ -67,7 +69,8 @@ func TestMode2_Create(t *testing.T) { tt.setupStorageFn(us.Mock, tt.input) } - dw := NewDualWriter(Mode2, ls, us, p, kind) + dw, err := NewDualWriter(kind, rest.Mode2, ls, us) + require.NoError(t, err) obj, err := dw.Create(context.Background(), tt.input, createFn, &metav1.CreateOptions{}) @@ -138,8 +141,8 @@ func TestMode2_Get(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - l := (Storage)(nil) - s := (Storage)(nil) + l := (rest.Storage)(nil) + s := (rest.Storage)(nil) ls := storageMock{&mock.Mock{}, l} us := storageMock{&mock.Mock{}, s} @@ -151,7 +154,8 @@ func TestMode2_Get(t *testing.T) { tt.setupStorageFn(us.Mock, tt.input) } - dw := NewDualWriter(Mode2, ls, us, p, kind) + dw, err := NewDualWriter(kind, rest.Mode2, ls, us) + require.NoError(t, err) obj, err := dw.Get(context.Background(), tt.input, &metav1.GetOptions{}) @@ -212,8 +216,8 @@ func TestMode2_List(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - l := (Storage)(nil) - s := (Storage)(nil) + l := (rest.Storage)(nil) + s := (rest.Storage)(nil) ls := storageMock{&mock.Mock{}, l} us := storageMock{&mock.Mock{}, s} @@ -225,7 +229,8 @@ func TestMode2_List(t *testing.T) { tt.setupStorageFn(us.Mock) } - dw := NewDualWriter(Mode2, ls, us, p, kind) + dw, err := NewDualWriter(kind, rest.Mode2, ls, us) + require.NoError(t, err) obj, err := dw.List(context.Background(), &metainternalversion.ListOptions{}) @@ -313,8 +318,8 @@ func TestMode2_Delete(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - l := (Storage)(nil) - s := (Storage)(nil) + l := (rest.Storage)(nil) + s := (rest.Storage)(nil) ls := storageMock{&mock.Mock{}, l} us := storageMock{&mock.Mock{}, s} @@ -326,7 +331,8 @@ func TestMode2_Delete(t *testing.T) { tt.setupStorageFn(us.Mock, name) } - dw := NewDualWriter(Mode2, ls, us, p, kind) + dw, err := NewDualWriter(kind, rest.Mode2, ls, us) + require.NoError(t, err) obj, _, err := dw.Delete(context.Background(), name, func(context.Context, runtime.Object) error { return nil }, &metav1.DeleteOptions{}) @@ -382,8 +388,8 @@ func TestMode2_DeleteCollection(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - l := (Storage)(nil) - s := (Storage)(nil) + l := (rest.Storage)(nil) + s := (rest.Storage)(nil) ls := storageMock{&mock.Mock{}, l} us := storageMock{&mock.Mock{}, s} @@ -395,7 +401,8 @@ func TestMode2_DeleteCollection(t *testing.T) { tt.setupStorageFn(us.Mock) } - dw := NewDualWriter(Mode2, ls, us, p, kind) + dw, err := NewDualWriter(kind, rest.Mode2, ls, us) + require.NoError(t, err) obj, err := dw.DeleteCollection(context.Background(), func(ctx context.Context, obj runtime.Object) error { return nil }, &metav1.DeleteOptions{TypeMeta: metav1.TypeMeta{Kind: name}}, &metainternalversion.ListOptions{}) @@ -451,8 +458,8 @@ func TestMode2_Update(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - l := (Storage)(nil) - s := (Storage)(nil) + l := (rest.Storage)(nil) + s := (rest.Storage)(nil) ls := storageMock{&mock.Mock{}, l} us := storageMock{&mock.Mock{}, s} @@ -464,7 +471,8 @@ func TestMode2_Update(t *testing.T) { tt.setupStorageFn(us.Mock, name) } - dw := NewDualWriter(Mode2, ls, us, p, kind) + dw, err := NewDualWriter(kind, rest.Mode2, ls, us) + require.NoError(t, err) obj, _, err := dw.Update(context.Background(), name, updatedObjInfoObj{}, func(ctx context.Context, obj runtime.Object) error { return nil }, func(ctx context.Context, obj, old runtime.Object) error { return nil }, false, &metav1.UpdateOptions{}) diff --git a/pkg/apiserver/rest/dualwriter_mode3_test.go b/pkg/storage/legacysql/dualwrite/dualwriter_mode3_test.go similarity index 87% rename from pkg/apiserver/rest/dualwriter_mode3_test.go rename to pkg/storage/legacysql/dualwrite/dualwriter_mode3_test.go index 832c8957aeb..c53be55b64c 100644 --- a/pkg/apiserver/rest/dualwriter_mode3_test.go +++ b/pkg/storage/legacysql/dualwrite/dualwriter_mode3_test.go @@ -1,11 +1,10 @@ -package rest +package dualwrite import ( "context" "errors" "testing" - "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -13,6 +12,8 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + + "github.com/grafana/grafana/pkg/apiserver/rest" ) func TestMode3_Create(t *testing.T) { @@ -61,8 +62,8 @@ func TestMode3_Create(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - l := (Storage)(nil) - s := (Storage)(nil) + l := (rest.Storage)(nil) + s := (rest.Storage)(nil) ls := storageMock{&mock.Mock{}, l} us := storageMock{&mock.Mock{}, s} @@ -74,7 +75,8 @@ func TestMode3_Create(t *testing.T) { tt.setupStorageFn(us.Mock, tt.input) } - dw := NewDualWriter(Mode3, ls, us, p, kind) + dw, err := NewDualWriter(kind, rest.Mode3, ls, us) + require.NoError(t, err) obj, err := dw.Create(context.Background(), tt.input, createFn, &metav1.CreateOptions{}) @@ -128,8 +130,8 @@ func TestMode3_Get(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - l := (Storage)(nil) - s := (Storage)(nil) + l := (rest.Storage)(nil) + s := (rest.Storage)(nil) ls := storageMock{&mock.Mock{}, l} us := storageMock{&mock.Mock{}, s} @@ -141,8 +143,8 @@ func TestMode3_Get(t *testing.T) { tt.setupStorageFn(us.Mock, name) } - p := prometheus.NewRegistry() - dw := NewDualWriter(Mode3, ls, us, p, kind) + dw, err := NewDualWriter(kind, rest.Mode3, ls, us) + require.NoError(t, err) obj, err := dw.Get(context.Background(), name, &metav1.GetOptions{}) @@ -157,58 +159,6 @@ func TestMode3_Get(t *testing.T) { } } -func TestMode1_GetFromLegacyStorage(t *testing.T) { - ctxCanceled, cancel := context.WithCancel(context.TODO()) - cancel() - - type testCase struct { - setupLegacyFn func(m *mock.Mock, name string) - ctx *context.Context - name string - } - tests := - []testCase{ - { - name: "should succeed when getting an object from the LegacyStorage", - setupLegacyFn: func(m *mock.Mock, name string) { - m.On("Get", mock.Anything, name, mock.Anything).Return(exampleObj, nil) - }, - }, - { - name: "should succeed when getting an object from the LegacyStorage even if parent context is canceled", - ctx: &ctxCanceled, - setupLegacyFn: func(m *mock.Mock, name string) { - m.On("Get", mock.Anything, name, mock.Anything).Return(exampleObj, nil) - }, - }, - } - - name := "foo" - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - l := (Storage)(nil) - s := (Storage)(nil) - - ls := storageMock{&mock.Mock{}, l} - us := storageMock{&mock.Mock{}, s} - - if tt.setupLegacyFn != nil { - tt.setupLegacyFn(ls.Mock, name) - } - - ctx := context.TODO() - if tt.ctx != nil { - ctx = *tt.ctx - } - - dw := NewDualWriter(Mode3, ls, us, p, kind) - err := dw.(*DualWriterMode3).getFromLegacyStorage(ctx, exampleObj, name, &metav1.GetOptions{}) - require.NoError(t, err) - }) - } -} - func TestMode3_List(t *testing.T) { type testCase struct { setupStorageFn func(m *mock.Mock, options *metainternalversion.ListOptions) @@ -234,8 +184,8 @@ func TestMode3_List(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - l := (Storage)(nil) - s := (Storage)(nil) + l := (rest.Storage)(nil) + s := (rest.Storage)(nil) ls := storageMock{&mock.Mock{}, l} us := storageMock{&mock.Mock{}, s} @@ -244,7 +194,8 @@ func TestMode3_List(t *testing.T) { tt.setupStorageFn(us.Mock, &metainternalversion.ListOptions{TypeMeta: metav1.TypeMeta{Kind: "foo"}}) } - dw := NewDualWriter(Mode3, ls, us, p, kind) + dw, err := NewDualWriter(kind, rest.Mode3, ls, us) + require.NoError(t, err) res, err := dw.List(context.Background(), &metainternalversion.ListOptions{TypeMeta: metav1.TypeMeta{Kind: "foo"}}) @@ -311,8 +262,8 @@ func TestMode3_Delete(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - l := (Storage)(nil) - s := (Storage)(nil) + l := (rest.Storage)(nil) + s := (rest.Storage)(nil) ls := storageMock{&mock.Mock{}, l} us := storageMock{&mock.Mock{}, s} @@ -324,7 +275,8 @@ func TestMode3_Delete(t *testing.T) { tt.setupStorageFn(us.Mock, name) } - dw := NewDualWriter(Mode3, ls, us, p, kind) + dw, err := NewDualWriter(kind, rest.Mode3, ls, us) + require.NoError(t, err) obj, _, err := dw.Delete(context.Background(), name, func(context.Context, runtime.Object) error { return nil }, &metav1.DeleteOptions{}) @@ -380,8 +332,8 @@ func TestMode3_DeleteCollection(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - l := (Storage)(nil) - s := (Storage)(nil) + l := (rest.Storage)(nil) + s := (rest.Storage)(nil) ls := storageMock{&mock.Mock{}, l} us := storageMock{&mock.Mock{}, s} @@ -393,7 +345,8 @@ func TestMode3_DeleteCollection(t *testing.T) { tt.setupStorageFn(us.Mock) } - dw := NewDualWriter(Mode3, ls, us, p, kind) + dw, err := NewDualWriter(kind, rest.Mode3, ls, us) + require.NoError(t, err) obj, err := dw.DeleteCollection(context.Background(), func(ctx context.Context, obj runtime.Object) error { return nil }, &metav1.DeleteOptions{TypeMeta: metav1.TypeMeta{Kind: name}}, &metainternalversion.ListOptions{}) @@ -449,8 +402,8 @@ func TestMode3_Update(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - l := (Storage)(nil) - s := (Storage)(nil) + l := (rest.Storage)(nil) + s := (rest.Storage)(nil) ls := storageMock{&mock.Mock{}, l} us := storageMock{&mock.Mock{}, s} @@ -462,7 +415,8 @@ func TestMode3_Update(t *testing.T) { tt.setupStorageFn(us.Mock, name) } - dw := NewDualWriter(Mode3, ls, us, p, kind) + dw, err := NewDualWriter(kind, rest.Mode3, ls, us) + require.NoError(t, err) obj, _, err := dw.Update(context.Background(), name, updatedObjInfoObj{}, func(ctx context.Context, obj runtime.Object) error { return nil }, func(ctx context.Context, obj, old runtime.Object) error { return nil }, false, &metav1.UpdateOptions{}) diff --git a/pkg/storage/legacysql/dualwrite/runtime.go b/pkg/storage/legacysql/dualwrite/runtime.go index 33896e669e2..8d9d5eb872d 100644 --- a/pkg/storage/legacysql/dualwrite/runtime.go +++ b/pkg/storage/legacysql/dualwrite/runtime.go @@ -11,25 +11,26 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apiserver/pkg/registry/rest" + "github.com/grafana/grafana-app-sdk/logging" + grafanarest "github.com/grafana/grafana/pkg/apiserver/rest" ) -func (m *service) NewStorage(gr schema.GroupResource, - legacy grafanarest.Storage, - storage grafanarest.Storage, -) (grafanarest.Storage, error) { +func (m *service) NewStorage(gr schema.GroupResource, legacy grafanarest.Storage, unified grafanarest.Storage) (grafanarest.Storage, error) { status, err := m.Status(context.Background(), gr) if err != nil { return nil, err } + log := logging.DefaultLogger.With("gr", gr.String()) + if m.enabled && status.Runtime { // Dynamic storage behavior return &runtimeDualWriter{ service: m, legacy: legacy, - unified: storage, - dualwrite: grafanarest.NewDualWriter(grafanarest.Mode3, legacy, storage, m.reg, gr.String()), + unified: unified, + dualwrite: &dualWriter{legacy: legacy, unified: unified, log: log}, // not used for read gr: gr, }, nil } @@ -37,13 +38,13 @@ func (m *service) NewStorage(gr schema.GroupResource, if status.ReadUnified { if status.WriteLegacy { // Write both, read unified - return grafanarest.NewDualWriter(grafanarest.Mode3, legacy, storage, m.reg, gr.String()), nil + return &dualWriter{legacy: legacy, unified: unified, log: log, readUnified: true}, nil } - return storage, nil + return unified, nil } if status.WriteUnified { // Write both, read legacy - return grafanarest.NewDualWriter(grafanarest.Mode2, legacy, storage, m.reg, gr.String()), nil + return &dualWriter{legacy: legacy, unified: unified, log: log}, nil } return legacy, nil } @@ -55,7 +56,7 @@ type runtimeDualWriter struct { service Service legacy grafanarest.Storage unified grafanarest.Storage - dualwrite grafanarest.Storage + dualwrite *dualWriter gr schema.GroupResource } diff --git a/pkg/storage/legacysql/dualwrite/runtime_test.go b/pkg/storage/legacysql/dualwrite/runtime_test.go index 9c148eaf07f..a4b5af5223c 100644 --- a/pkg/storage/legacysql/dualwrite/runtime_test.go +++ b/pkg/storage/legacysql/dualwrite/runtime_test.go @@ -4,33 +4,20 @@ import ( "context" "errors" "testing" - "time" - "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/mock" "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" "github.com/grafana/grafana/pkg/apiserver/rest" "github.com/grafana/grafana/pkg/services/featuremgmt" ) -var now = time.Now() - -var createFn = func(context.Context, runtime.Object) error { return nil } - -var exampleObj = &example.Pod{TypeMeta: metav1.TypeMeta{Kind: "foo"}, ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1", CreationTimestamp: metav1.Time{}, GenerateName: "foo"}, Spec: example.PodSpec{}, Status: example.PodStatus{StartTime: &metav1.Time{Time: now}}} -var exampleObjNoRV = &example.Pod{TypeMeta: metav1.TypeMeta{Kind: "foo"}, ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "", CreationTimestamp: metav1.Time{}, GenerateName: "foo"}, Spec: example.PodSpec{}, Status: example.PodStatus{StartTime: &metav1.Time{Time: now}}} -var anotherObj = &example.Pod{TypeMeta: metav1.TypeMeta{Kind: "foo"}, ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "2", GenerateName: "foo"}, Spec: example.PodSpec{}, Status: example.PodStatus{StartTime: &metav1.Time{Time: now}}} -var failingObj = &example.Pod{TypeMeta: metav1.TypeMeta{Kind: "foo"}, ObjectMeta: metav1.ObjectMeta{Name: "object-fail", ResourceVersion: "2", GenerateName: "object-fail"}, Spec: example.PodSpec{}, Status: example.PodStatus{}} - -var p = prometheus.NewRegistry() var kind = schema.GroupResource{Group: "g", Resource: "r"} -func TestManagedMode3_Create(t *testing.T) { +func TestRuntime_Create(t *testing.T) { type testCase struct { input runtime.Object setupLegacyFn func(m *mock.Mock, input runtime.Object) @@ -105,7 +92,7 @@ func TestManagedMode3_Create(t *testing.T) { } } -func TestManagedMode3_Get(t *testing.T) { +func TestRuntime_Get(t *testing.T) { type testCase struct { setupLegacyFn func(m *mock.Mock, name string) setupStorageFn func(m *mock.Mock, name string) @@ -184,7 +171,7 @@ func TestManagedMode3_Get(t *testing.T) { } } -func TestManagedMode3_CreateWhileMigrating(t *testing.T) { +func TestRuntime_CreateWhileMigrating(t *testing.T) { type testCase struct { input runtime.Object setupLegacyFn func(m *mock.Mock, input runtime.Object) diff --git a/pkg/storage/legacysql/dualwrite/static.go b/pkg/storage/legacysql/dualwrite/static.go index d74e2a5b914..db71d338377 100644 --- a/pkg/storage/legacysql/dualwrite/static.go +++ b/pkg/storage/legacysql/dualwrite/static.go @@ -6,16 +6,58 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" + "github.com/grafana/grafana-app-sdk/logging" "github.com/grafana/grafana/pkg/apiserver/rest" "github.com/grafana/grafana/pkg/setting" ) +// NewDualWriter -- temporary shim +func NewDualWriter( + gr schema.GroupResource, + mode rest.DualWriterMode, + legacy rest.Storage, + unified rest.Storage, +) (rest.Storage, error) { + m := &staticService{} + m.SetMode(gr, mode) + return m.NewStorage(gr, legacy, unified) +} + type staticService struct { cfg *setting.Cfg } -func (m *staticService) NewStorage(gr schema.GroupResource, legacy rest.Storage, storage rest.Storage) (rest.Storage, error) { - return nil, fmt.Errorf("not implemented") +// Used in tests +func (m *staticService) SetMode(gr schema.GroupResource, mode rest.DualWriterMode) { + if m.cfg == nil { + m.cfg = &setting.Cfg{} + } + if m.cfg.UnifiedStorage == nil { + m.cfg.UnifiedStorage = make(map[string]setting.UnifiedStorageConfig) + } + m.cfg.UnifiedStorage[gr.String()] = setting.UnifiedStorageConfig{ + DualWriterMode: mode, + } +} + +func (m *staticService) NewStorage(gr schema.GroupResource, legacy rest.Storage, unified rest.Storage) (rest.Storage, error) { + log := logging.DefaultLogger.With("dualwrite", gr.String()) + + config := m.cfg.UnifiedStorage[gr.String()] + switch config.DualWriterMode { + case rest.Mode1: + return &dualWriter{log: log, legacy: legacy, unified: unified, errorIsOK: true}, nil + case rest.Mode2: + return &dualWriter{log: log, legacy: legacy, unified: unified}, nil + case rest.Mode3: + return &dualWriter{log: log, legacy: legacy, unified: unified, readUnified: true}, nil + case rest.Mode4, rest.Mode5: + return unified, nil // use unified directly + case rest.Mode0: + fallthrough + default: + return legacy, nil + } } // ReadFromUnified implements Service. diff --git a/pkg/storage/legacysql/dualwrite/storage_mocks_test.go b/pkg/storage/legacysql/dualwrite/storage_mocks_test.go index b3905d1c3d3..409980f59c1 100644 --- a/pkg/storage/legacysql/dualwrite/storage_mocks_test.go +++ b/pkg/storage/legacysql/dualwrite/storage_mocks_test.go @@ -106,3 +106,12 @@ func (m storageMock) DeleteCollection(ctx context.Context, deleteValidation rest } return args.Get(0).(runtime.Object), args.Error(1) } + +type updatedObjInfoObj struct{} + +func (u updatedObjInfoObj) UpdatedObject(ctx context.Context, oldObj runtime.Object) (newObj runtime.Object, err error) { // nolint:staticcheck + // nolint:staticcheck + oldObj = exampleObj + return oldObj, nil +} +func (u updatedObjInfoObj) Preconditions() *metav1.Preconditions { return &metav1.Preconditions{} } From ed8bd902dfeea13c84eb321e554c66ca68066c4f Mon Sep 17 00:00:00 2001 From: "grafana-pr-automation[bot]" <140550294+grafana-pr-automation[bot]@users.noreply.github.com> Date: Sun, 2 Mar 2025 02:31:55 +0200 Subject: [PATCH 49/74] I18n: Download translations from Crowdin (#101486) New Crowdin translations by GitHub Action Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- public/locales/de-DE/grafana.json | 54 +++++++++++++++++++++++++++-- public/locales/es-ES/grafana.json | 54 +++++++++++++++++++++++++++-- public/locales/fr-FR/grafana.json | 54 +++++++++++++++++++++++++++-- public/locales/pt-BR/grafana.json | 54 +++++++++++++++++++++++++++-- public/locales/zh-Hans/grafana.json | 54 +++++++++++++++++++++++++++-- 5 files changed, 255 insertions(+), 15 deletions(-) diff --git a/public/locales/de-DE/grafana.json b/public/locales/de-DE/grafana.json index 355610c995d..950616d290a 100644 --- a/public/locales/de-DE/grafana.json +++ b/public/locales/de-DE/grafana.json @@ -209,6 +209,8 @@ "alerting": "", "alerting-change-description": "", "annotations": "", + "compare": "", + "compare-with-latest": "", "compareVersions": "", "comparing-versions": "", "condition": "", @@ -228,17 +230,22 @@ "provisioning": "", "provisioning-change-description": "", "queryAndAlertCondition": "", - "reset": "", "restore": "", + "restore-manually": "", "restore-modal": { "body": "", + "confirm": "", + "error": "", "summary": "", "title": "" }, + "restore-version": "", "rule_group": "", "unknown": "", "unknown-change-description": "", - "user-id": "" + "user-id": "", + "warning-restore-manually": "", + "warning-restore-manually-title": "" }, "annotations": { "description": "", @@ -315,6 +322,10 @@ "empty-state": { "title": "" }, + "key-value-map": { + "add": "", + "confirm-add": "" + }, "last-delivery-attempt": "", "last-delivery-failed": "", "no-contact-points-found": "", @@ -1043,10 +1054,24 @@ }, "modal": { "title": "" - } + }, + "repeat": { + "title": "", + "variable": { + "title": "" + } + }, + "title": "" } }, "edit-pane": { + "elements": { + "dashboard": "", + "objects": "", + "panels": "", + "rows": "", + "tabs": "" + }, "objects": { "multi-select": { "selection-number": "" @@ -1151,6 +1176,15 @@ "title": "", "title-option": "" }, + "outline": { + "tree": { + "item": { + "collapse": "", + "empty": "", + "expand": "" + } + } + }, "panel-edit": { "alerting-tab": { "dashboard-not-saved": "", @@ -1161,6 +1195,12 @@ "description": "", "item-options": { "hide-no-data": "", + "repeat": { + "variable": { + "description": "", + "title": "" + } + }, "title": "" }, "name": "", @@ -2224,6 +2264,14 @@ "log-line": "", "no-details": "" }, + "log-line-menu": { + "copy-link": "", + "copy-log": "", + "icon-label": "", + "pin-to-outline": "", + "show-context": "", + "unpin-from-outline": "" + }, "log-row-message": { "ellipsis": "", "more": "", diff --git a/public/locales/es-ES/grafana.json b/public/locales/es-ES/grafana.json index 1fa664da890..cddcac1dbb6 100644 --- a/public/locales/es-ES/grafana.json +++ b/public/locales/es-ES/grafana.json @@ -209,6 +209,8 @@ "alerting": "", "alerting-change-description": "", "annotations": "", + "compare": "", + "compare-with-latest": "", "compareVersions": "", "comparing-versions": "", "condition": "", @@ -228,17 +230,22 @@ "provisioning": "", "provisioning-change-description": "", "queryAndAlertCondition": "", - "reset": "", "restore": "", + "restore-manually": "", "restore-modal": { "body": "", + "confirm": "", + "error": "", "summary": "", "title": "" }, + "restore-version": "", "rule_group": "", "unknown": "", "unknown-change-description": "", - "user-id": "" + "user-id": "", + "warning-restore-manually": "", + "warning-restore-manually-title": "" }, "annotations": { "description": "", @@ -315,6 +322,10 @@ "empty-state": { "title": "" }, + "key-value-map": { + "add": "", + "confirm-add": "" + }, "last-delivery-attempt": "", "last-delivery-failed": "", "no-contact-points-found": "", @@ -1043,10 +1054,24 @@ }, "modal": { "title": "" - } + }, + "repeat": { + "title": "", + "variable": { + "title": "" + } + }, + "title": "" } }, "edit-pane": { + "elements": { + "dashboard": "", + "objects": "", + "panels": "", + "rows": "", + "tabs": "" + }, "objects": { "multi-select": { "selection-number": "" @@ -1151,6 +1176,15 @@ "title": "", "title-option": "" }, + "outline": { + "tree": { + "item": { + "collapse": "", + "empty": "", + "expand": "" + } + } + }, "panel-edit": { "alerting-tab": { "dashboard-not-saved": "", @@ -1161,6 +1195,12 @@ "description": "", "item-options": { "hide-no-data": "", + "repeat": { + "variable": { + "description": "", + "title": "" + } + }, "title": "" }, "name": "", @@ -2224,6 +2264,14 @@ "log-line": "", "no-details": "" }, + "log-line-menu": { + "copy-link": "", + "copy-log": "", + "icon-label": "", + "pin-to-outline": "", + "show-context": "", + "unpin-from-outline": "" + }, "log-row-message": { "ellipsis": "", "more": "", diff --git a/public/locales/fr-FR/grafana.json b/public/locales/fr-FR/grafana.json index 4def0fc0e73..10cebf9fa25 100644 --- a/public/locales/fr-FR/grafana.json +++ b/public/locales/fr-FR/grafana.json @@ -209,6 +209,8 @@ "alerting": "", "alerting-change-description": "", "annotations": "", + "compare": "", + "compare-with-latest": "", "compareVersions": "", "comparing-versions": "", "condition": "", @@ -228,17 +230,22 @@ "provisioning": "", "provisioning-change-description": "", "queryAndAlertCondition": "", - "reset": "", "restore": "", + "restore-manually": "", "restore-modal": { "body": "", + "confirm": "", + "error": "", "summary": "", "title": "" }, + "restore-version": "", "rule_group": "", "unknown": "", "unknown-change-description": "", - "user-id": "" + "user-id": "", + "warning-restore-manually": "", + "warning-restore-manually-title": "" }, "annotations": { "description": "", @@ -315,6 +322,10 @@ "empty-state": { "title": "" }, + "key-value-map": { + "add": "", + "confirm-add": "" + }, "last-delivery-attempt": "", "last-delivery-failed": "", "no-contact-points-found": "", @@ -1043,10 +1054,24 @@ }, "modal": { "title": "" - } + }, + "repeat": { + "title": "", + "variable": { + "title": "" + } + }, + "title": "" } }, "edit-pane": { + "elements": { + "dashboard": "", + "objects": "", + "panels": "", + "rows": "", + "tabs": "" + }, "objects": { "multi-select": { "selection-number": "" @@ -1151,6 +1176,15 @@ "title": "", "title-option": "" }, + "outline": { + "tree": { + "item": { + "collapse": "", + "empty": "", + "expand": "" + } + } + }, "panel-edit": { "alerting-tab": { "dashboard-not-saved": "", @@ -1161,6 +1195,12 @@ "description": "", "item-options": { "hide-no-data": "", + "repeat": { + "variable": { + "description": "", + "title": "" + } + }, "title": "" }, "name": "", @@ -2224,6 +2264,14 @@ "log-line": "", "no-details": "" }, + "log-line-menu": { + "copy-link": "", + "copy-log": "", + "icon-label": "", + "pin-to-outline": "", + "show-context": "", + "unpin-from-outline": "" + }, "log-row-message": { "ellipsis": "", "more": "", diff --git a/public/locales/pt-BR/grafana.json b/public/locales/pt-BR/grafana.json index 6e0f3ba0687..7e0f679777b 100644 --- a/public/locales/pt-BR/grafana.json +++ b/public/locales/pt-BR/grafana.json @@ -209,6 +209,8 @@ "alerting": "", "alerting-change-description": "", "annotations": "", + "compare": "", + "compare-with-latest": "", "compareVersions": "", "comparing-versions": "", "condition": "", @@ -228,17 +230,22 @@ "provisioning": "", "provisioning-change-description": "", "queryAndAlertCondition": "", - "reset": "", "restore": "", + "restore-manually": "", "restore-modal": { "body": "", + "confirm": "", + "error": "", "summary": "", "title": "" }, + "restore-version": "", "rule_group": "", "unknown": "", "unknown-change-description": "", - "user-id": "" + "user-id": "", + "warning-restore-manually": "", + "warning-restore-manually-title": "" }, "annotations": { "description": "", @@ -315,6 +322,10 @@ "empty-state": { "title": "" }, + "key-value-map": { + "add": "", + "confirm-add": "" + }, "last-delivery-attempt": "", "last-delivery-failed": "", "no-contact-points-found": "", @@ -1043,10 +1054,24 @@ }, "modal": { "title": "" - } + }, + "repeat": { + "title": "", + "variable": { + "title": "" + } + }, + "title": "" } }, "edit-pane": { + "elements": { + "dashboard": "", + "objects": "", + "panels": "", + "rows": "", + "tabs": "" + }, "objects": { "multi-select": { "selection-number": "" @@ -1151,6 +1176,15 @@ "title": "", "title-option": "" }, + "outline": { + "tree": { + "item": { + "collapse": "", + "empty": "", + "expand": "" + } + } + }, "panel-edit": { "alerting-tab": { "dashboard-not-saved": "", @@ -1161,6 +1195,12 @@ "description": "", "item-options": { "hide-no-data": "", + "repeat": { + "variable": { + "description": "", + "title": "" + } + }, "title": "" }, "name": "", @@ -2224,6 +2264,14 @@ "log-line": "", "no-details": "" }, + "log-line-menu": { + "copy-link": "", + "copy-log": "", + "icon-label": "", + "pin-to-outline": "", + "show-context": "", + "unpin-from-outline": "" + }, "log-row-message": { "ellipsis": "", "more": "", diff --git a/public/locales/zh-Hans/grafana.json b/public/locales/zh-Hans/grafana.json index d1f6b954db5..74386956d29 100644 --- a/public/locales/zh-Hans/grafana.json +++ b/public/locales/zh-Hans/grafana.json @@ -209,6 +209,8 @@ "alerting": "", "alerting-change-description": "", "annotations": "", + "compare": "", + "compare-with-latest": "", "compareVersions": "", "comparing-versions": "", "condition": "", @@ -228,17 +230,22 @@ "provisioning": "", "provisioning-change-description": "", "queryAndAlertCondition": "", - "reset": "", "restore": "", + "restore-manually": "", "restore-modal": { "body": "", + "confirm": "", + "error": "", "summary": "", "title": "" }, + "restore-version": "", "rule_group": "", "unknown": "", "unknown-change-description": "", - "user-id": "" + "user-id": "", + "warning-restore-manually": "", + "warning-restore-manually-title": "" }, "annotations": { "description": "", @@ -315,6 +322,10 @@ "empty-state": { "title": "" }, + "key-value-map": { + "add": "", + "confirm-add": "" + }, "last-delivery-attempt": "", "last-delivery-failed": "", "no-contact-points-found": "", @@ -1034,10 +1045,24 @@ }, "modal": { "title": "" - } + }, + "repeat": { + "title": "", + "variable": { + "title": "" + } + }, + "title": "" } }, "edit-pane": { + "elements": { + "dashboard": "", + "objects": "", + "panels": "", + "rows": "", + "tabs": "" + }, "objects": { "multi-select": { "selection-number": "" @@ -1142,6 +1167,15 @@ "title": "", "title-option": "" }, + "outline": { + "tree": { + "item": { + "collapse": "", + "empty": "", + "expand": "" + } + } + }, "panel-edit": { "alerting-tab": { "dashboard-not-saved": "", @@ -1152,6 +1186,12 @@ "description": "", "item-options": { "hide-no-data": "", + "repeat": { + "variable": { + "description": "", + "title": "" + } + }, "title": "" }, "name": "", @@ -2214,6 +2254,14 @@ "log-line": "", "no-details": "" }, + "log-line-menu": { + "copy-link": "", + "copy-log": "", + "icon-label": "", + "pin-to-outline": "", + "show-context": "", + "unpin-from-outline": "" + }, "log-row-message": { "ellipsis": "", "more": "", From 2e7c28ccbc37ee1d718982761620ef056b81ac87 Mon Sep 17 00:00:00 2001 From: Stephanie Hingtgen Date: Sun, 2 Mar 2025 21:45:24 -0700 Subject: [PATCH 50/74] Dashboard history: rename rudderstack variable (#101182) --- .../settings/version-history/VersionHistoryTable.test.tsx | 2 +- .../settings/version-history/VersionHistoryTable.tsx | 2 +- public/app/features/dashboard-scene/utils/interactions.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/public/app/features/dashboard-scene/settings/version-history/VersionHistoryTable.test.tsx b/public/app/features/dashboard-scene/settings/version-history/VersionHistoryTable.test.tsx index 0a15aff1dd5..8b2a8891892 100644 --- a/public/app/features/dashboard-scene/settings/version-history/VersionHistoryTable.test.tsx +++ b/public/app/features/dashboard-scene/settings/version-history/VersionHistoryTable.test.tsx @@ -52,7 +52,7 @@ describe('VersionHistoryTable', () => { version: mockVersions[1].version, index: 1, confirm: false, - timestamp: mockVersions[1].created, + version_date: mockVersions[1].created, }); }); }); diff --git a/public/app/features/dashboard-scene/settings/version-history/VersionHistoryTable.tsx b/public/app/features/dashboard-scene/settings/version-history/VersionHistoryTable.tsx index 48fc15963b8..d98577c2a75 100644 --- a/public/app/features/dashboard-scene/settings/version-history/VersionHistoryTable.tsx +++ b/public/app/features/dashboard-scene/settings/version-history/VersionHistoryTable.tsx @@ -70,7 +70,7 @@ export const VersionHistoryTable = ({ versions, canCompare, onCheck, onRestore } version: version.version, index: idx, confirm: false, - timestamp: version.created, + version_date: version.created, }); }} > diff --git a/public/app/features/dashboard-scene/utils/interactions.ts b/public/app/features/dashboard-scene/utils/interactions.ts index b52c09e190f..c7a0791e513 100644 --- a/public/app/features/dashboard-scene/utils/interactions.ts +++ b/public/app/features/dashboard-scene/utils/interactions.ts @@ -118,7 +118,7 @@ export const DashboardInteractions = { }, // Dashboards versions interactions - versionRestoreClicked: (properties: { version: number; index?: number; confirm: boolean; timestamp?: Date }) => { + versionRestoreClicked: (properties: { version: number; index?: number; confirm: boolean; version_date?: Date }) => { reportDashboardInteraction('version_restore_clicked', properties); }, showMoreVersionsClicked: () => { From 561156c4da99701bd95914c807a74af427e83ade Mon Sep 17 00:00:00 2001 From: "Filip \"Ret2Me\" Poplewski" <37419029+Ret2Me@users.noreply.github.com> Date: Mon, 3 Mar 2025 10:18:14 +0100 Subject: [PATCH 51/74] Auth: Add support for the TlsSkipVerify parameter to JWT Auth (#91514) * feat(auth/JWTAuth): add support for the TlsSkipVerify parameter * feat(auth/JWTAuth): add param to default.ini and sample.ini --------- Co-authored-by: Mihaly Gyongyosi --- conf/defaults.ini | 1 + conf/sample.ini | 1 + pkg/services/auth/jwt/key_sets.go | 3 ++- pkg/setting/setting_jwt.go | 2 ++ 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/conf/defaults.ini b/conf/defaults.ini index bf0bf994b56..492151a87f2 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -937,6 +937,7 @@ auto_sign_up = false url_login = false allow_assign_grafana_admin = false skip_org_role_sync = false +tls_skip_verify_insecure = false #################################### Auth LDAP ########################### [auth.ldap] diff --git a/conf/sample.ini b/conf/sample.ini index da688f03078..f695824f04f 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -907,6 +907,7 @@ ;allow_assign_grafana_admin = false ;skip_org_role_sync = false ;signout_redirect_url = +;tls_skip_verify_insecure = false #################################### Auth LDAP ########################## [auth.ldap] diff --git a/pkg/services/auth/jwt/key_sets.go b/pkg/services/auth/jwt/key_sets.go index 5361f3b3fbb..2e5d6b22001 100644 --- a/pkg/services/auth/jwt/key_sets.go +++ b/pkg/services/auth/jwt/key_sets.go @@ -161,7 +161,8 @@ func (s *AuthService) initKeySet() error { client: &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{ - Renegotiation: tls.RenegotiateFreelyAsClient, + Renegotiation: tls.RenegotiateFreelyAsClient, + InsecureSkipVerify: s.Cfg.JWTAuth.TlsSkipVerify, }, Proxy: http.ProxyFromEnvironment, DialContext: (&net.Dialer{ diff --git a/pkg/setting/setting_jwt.go b/pkg/setting/setting_jwt.go index 42b8009de4b..2a559a145b7 100644 --- a/pkg/setting/setting_jwt.go +++ b/pkg/setting/setting_jwt.go @@ -27,6 +27,7 @@ type AuthJWTSettings struct { GroupsAttributePath string EmailAttributePath string UsernameAttributePath string + TlsSkipVerify bool } type ExtJWTSettings struct { @@ -69,6 +70,7 @@ func (cfg *Cfg) readAuthJWTSettings() { jwtSettings.GroupsAttributePath = valueAsString(authJWT, "groups_attribute_path", "") jwtSettings.EmailAttributePath = valueAsString(authJWT, "email_attribute_path", "") jwtSettings.UsernameAttributePath = valueAsString(authJWT, "username_attribute_path", "") + jwtSettings.TlsSkipVerify = authJWT.Key("tls_skip_verify_insecure").MustBool(false) cfg.JWTAuth = jwtSettings } From 28a28a686df1deeb21c037298063371cedf71f67 Mon Sep 17 00:00:00 2001 From: Gilles De Mey Date: Mon, 3 Mar 2025 10:19:01 +0100 Subject: [PATCH 52/74] Alerting: Fix crash when invalid matcher is used in silence query params (#101500) --- .../alerting/unified/utils/matchers.test.ts | 8 ++++++++ .../features/alerting/unified/utils/matchers.ts | 17 +++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/public/app/features/alerting/unified/utils/matchers.test.ts b/public/app/features/alerting/unified/utils/matchers.test.ts index f89e3fa8230..fdf9511c7fa 100644 --- a/public/app/features/alerting/unified/utils/matchers.test.ts +++ b/public/app/features/alerting/unified/utils/matchers.test.ts @@ -49,6 +49,14 @@ describe('Unified Alerting matchers', () => { expect(matchers[0].name).toBe('alertname'); expect(matchers[0].value).toBe('TestData 1'); }); + + it('should not crash when matcher is not valid', () => { + expect(() => { + parseQueryParamMatchers(['alertname']); + }).not.toThrow(); + + expect(parseQueryParamMatchers(['alertname'])).toHaveLength(0); + }); }); describe('normalizeMatchers', () => { diff --git a/public/app/features/alerting/unified/utils/matchers.ts b/public/app/features/alerting/unified/utils/matchers.ts index f5f5476e208..32e0f08555a 100644 --- a/public/app/features/alerting/unified/utils/matchers.ts +++ b/public/app/features/alerting/unified/utils/matchers.ts @@ -5,7 +5,7 @@ * Please keep the references to other files here to a minimum, if we reference a file that uses GrafanaBootData from `window` the worker will fail to load. */ -import { compact, uniqBy } from 'lodash'; +import { chain, compact } from 'lodash'; import { parseFlags } from '@grafana/data'; import { Matcher, MatcherOperator, ObjectMatcher, Route } from 'app/plugins/datasource/alertmanager/types'; @@ -110,11 +110,16 @@ export function parsePromQLStyleMatcherLooseSafe(matcher: string): Matcher[] { // Parses a list of entries like like "['foo=bar', 'baz=~bad*']" into SilenceMatcher[] export function parseQueryParamMatchers(matcherPairs: string[]): Matcher[] { - const parsedMatchers = matcherPairs.filter((x) => !!x.trim()).map((x) => parseMatcher(x)); - - // Due to migration, old alert rules might have a duplicated alertname label - // To handle that case want to filter out duplicates and make sure there are only unique labels - return uniqBy(parsedMatchers, (matcher) => matcher.name); + return ( + chain(matcherPairs) + .map((m) => m.trim()) // trim spaces + .compact() // remove empty strings + .flatMap(parsePromQLStyleMatcherLooseSafe) + // Due to migration, old alert rules might have a duplicated alertname label + // To handle that case want to filter out duplicates and make sure there are only unique labels + .uniqBy('name') + .value() + ); } export const getMatcherQueryParams = (labels: Labels) => { From 070d4b2ee466274a3cd145e107ab7690b0661eba Mon Sep 17 00:00:00 2001 From: Oscar Kilhed Date: Mon, 3 Mar 2025 11:19:17 +0100 Subject: [PATCH 53/74] SchemaV2: Accept rows with no panel property (#101503) accept rows with no panel property --- .../dashboard/api/ResponseTransformers.test.ts | 14 +++++++++++++- .../features/dashboard/api/ResponseTransformers.ts | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/public/app/features/dashboard/api/ResponseTransformers.test.ts b/public/app/features/dashboard/api/ResponseTransformers.test.ts index 4a7a29cf711..41064867a87 100644 --- a/public/app/features/dashboard/api/ResponseTransformers.test.ts +++ b/public/app/features/dashboard/api/ResponseTransformers.test.ts @@ -406,6 +406,13 @@ describe('ResponseTransformers', () => { ], collapsed: true, }, + { + id: 6, + type: 'row', + title: 'Row with no panel property', + gridPos: { x: 0, y: 25, w: 12, h: 1 }, + collapsed: true, + }, ], }; @@ -483,7 +490,7 @@ describe('ResponseTransformers', () => { // Panel expect(spec.layout.kind).toBe('GridLayout'); const layout = spec.layout as GridLayoutKind; - expect(layout.spec.items).toHaveLength(4); + expect(layout.spec.items).toHaveLength(5); expect(layout.spec.items[0].spec).toEqual({ element: { kind: 'ElementReference', @@ -606,6 +613,11 @@ describe('ResponseTransformers', () => { height: 8, }); + const rowWithNoPanelProperty = layout.spec.items[4].spec as GridLayoutRowSpec; + expect(rowWithNoPanelProperty.collapsed).toBe(true); + expect(rowWithNoPanelProperty.title).toBe('Row with no panel property'); + expect(rowWithNoPanelProperty.elements).toHaveLength(0); + // Variables validateVariablesV1ToV2(spec.variables[0], dashboardV1.templating?.list?.[0]); validateVariablesV1ToV2(spec.variables[1], dashboardV1.templating?.list?.[1]); diff --git a/public/app/features/dashboard/api/ResponseTransformers.ts b/public/app/features/dashboard/api/ResponseTransformers.ts index 5ad1d7836d6..4dc01f06a99 100644 --- a/public/app/features/dashboard/api/ResponseTransformers.ts +++ b/public/app/features/dashboard/api/ResponseTransformers.ts @@ -298,7 +298,7 @@ function getElementsFromPanels( const rowElements = []; - for (const panel of p.panels) { + for (const panel of p.panels || []) { const [element, name] = buildElement(panel); elements[name] = element; rowElements.push(buildGridItemKind(panel, name, yOffsetInRows(panel, p.gridPos!.y))); From d3b550c230ccf9118880865e97b5d640c20afbf1 Mon Sep 17 00:00:00 2001 From: Sergej-Vlasov <37613182+Sergej-Vlasov@users.noreply.github.com> Date: Mon, 3 Mar 2025 10:49:32 +0000 Subject: [PATCH 54/74] Dashboards: Redesign edit pane of dashboard and viz panels (#101437) * adjust options pane category component and shared logic * redesign dashboard edit pane * clean up * redesign viz panel edit panes * address comments * updated i18n * clean up * address comments --- .../edit-pane/DashboardEditableElement.tsx | 24 ++-- .../edit-pane/EditPaneHeader.tsx | 57 ++++++++ .../edit-pane/ElementEditPane.tsx | 2 + .../MultiSelectedVizPanelsEditableElement.tsx | 40 +++--- .../edit-pane/VizPanelEditableElement.tsx | 136 +++++++++++------- .../DashboardLayoutSelector.tsx | 7 +- .../scene/types/EditableDashboardElement.ts | 10 ++ .../MultiSelectedEditableDashboardElement.ts | 10 ++ .../PanelEditor/OptionsPaneCategory.tsx | 42 ++++-- .../OptionsPaneCategoryDescriptor.tsx | 1 + public/locales/en-US/grafana.json | 19 ++- public/locales/pseudo-LOCALE/grafana.json | 19 ++- 12 files changed, 252 insertions(+), 115 deletions(-) create mode 100644 public/app/features/dashboard-scene/edit-pane/EditPaneHeader.tsx diff --git a/public/app/features/dashboard-scene/edit-pane/DashboardEditableElement.tsx b/public/app/features/dashboard-scene/edit-pane/DashboardEditableElement.tsx index 77255075393..ae3085bc055 100644 --- a/public/app/features/dashboard-scene/edit-pane/DashboardEditableElement.tsx +++ b/public/app/features/dashboard-scene/edit-pane/DashboardEditableElement.tsx @@ -6,7 +6,7 @@ import { OptionsPaneCategoryDescriptor } from 'app/features/dashboard/components import { OptionsPaneItemDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor'; import { DashboardScene } from '../scene/DashboardScene'; -import { useLayoutCategory } from '../scene/layouts-shared/DashboardLayoutSelector'; +import { DashboardLayoutSelector } from '../scene/layouts-shared/DashboardLayoutSelector'; import { EditableDashboardElement, EditableDashboardElementInfo } from '../scene/types/EditableDashboardElement'; export class DashboardEditableElement implements EditableDashboardElement { @@ -28,29 +28,29 @@ export class DashboardEditableElement implements EditableDashboardElement { return new OptionsPaneCategoryDescriptor({ title: t('dashboard.options.title', 'Dashboard options'), id: 'dashboard-options', - isOpenDefault: true, + isOpenable: false, }) .addItem( new OptionsPaneItemDescriptor({ title: t('dashboard.options.title-option', 'Title'), - render: function renderTitle() { - return ; - }, + render: () => , }) ) .addItem( new OptionsPaneItemDescriptor({ title: t('dashboard.options.description', 'Description'), - render: function renderTitle() { - return ; - }, + render: () => , + }) + ) + .addItem( + new OptionsPaneItemDescriptor({ + title: t('dashboard.layout.common.layout', 'Layout'), + render: () => , }) ); - }, [dashboard]); + }, [body, dashboard]); - const layoutCategory = useLayoutCategory(body); - - return [dashboardOptions, layoutCategory]; + return [dashboardOptions]; } } diff --git a/public/app/features/dashboard-scene/edit-pane/EditPaneHeader.tsx b/public/app/features/dashboard-scene/edit-pane/EditPaneHeader.tsx new file mode 100644 index 00000000000..653daf384f2 --- /dev/null +++ b/public/app/features/dashboard-scene/edit-pane/EditPaneHeader.tsx @@ -0,0 +1,57 @@ +import { Dropdown, Button, IconButton, Menu, Stack, Icon } from '@grafana/ui'; +import { t } from 'app/core/internationalization'; + +interface EditPaneHeaderProps { + title: string; + onDelete?: () => void; + onCopy?: () => void; + onDuplicate?: () => void; +} + +export const EditPaneHeader = ({ title, onDelete, onCopy, onDuplicate }: EditPaneHeaderProps) => { + const addCopyOrDuplicate = onCopy || onDuplicate; + return ( + + {title} + + {addCopyOrDuplicate ? ( + }> + + + ) : null} + + + + + ); +}; + +type MenuItemsProps = { + onCopy?: () => void; + onDuplicate?: () => void; +}; + +const MenuItems = ({ onCopy, onDuplicate }: MenuItemsProps) => { + return ( + + {onCopy ? : null} + {onDuplicate ? ( + + ) : null} + + ); +}; diff --git a/public/app/features/dashboard-scene/edit-pane/ElementEditPane.tsx b/public/app/features/dashboard-scene/edit-pane/ElementEditPane.tsx index 47cd84ade4b..01b9a3f2398 100644 --- a/public/app/features/dashboard-scene/edit-pane/ElementEditPane.tsx +++ b/public/app/features/dashboard-scene/edit-pane/ElementEditPane.tsx @@ -24,6 +24,8 @@ export function ElementEditPane({ element }: Props) { title={elementInfo.name} isOpenDefault={true} className={styles.noBorderTop} + renderTitle={element.renderTitle} + isOpenable={element.isOpenable} >
{element.renderActions()}
diff --git a/public/app/features/dashboard-scene/edit-pane/MultiSelectedVizPanelsEditableElement.tsx b/public/app/features/dashboard-scene/edit-pane/MultiSelectedVizPanelsEditableElement.tsx index afa29772adc..3e6a7fa98ae 100644 --- a/public/app/features/dashboard-scene/edit-pane/MultiSelectedVizPanelsEditableElement.tsx +++ b/public/app/features/dashboard-scene/edit-pane/MultiSelectedVizPanelsEditableElement.tsx @@ -1,14 +1,15 @@ -import { ReactNode } from 'react'; import { v4 as uuidv4 } from 'uuid'; import { VizPanel } from '@grafana/scenes'; -import { Button, Stack, Text } from '@grafana/ui'; -import { t, Trans } from 'app/core/internationalization'; +import { t } from 'app/core/internationalization'; +import { OptionsPaneCategoryDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor'; import { EditableDashboardElementInfo } from '../scene/types/EditableDashboardElement'; import { MultiSelectedEditableDashboardElement } from '../scene/types/MultiSelectedEditableDashboardElement'; import { dashboardSceneGraph } from '../utils/dashboardSceneGraph'; +import { EditPaneHeader } from './EditPaneHeader'; + export class MultiSelectedVizPanelsEditableElement implements MultiSelectedEditableDashboardElement { public readonly isMultiSelectedEditableDashboardElement = true; public readonly key: string; @@ -21,23 +22,22 @@ export class MultiSelectedVizPanelsEditableElement implements MultiSelectedEdita return { name: t('dashboard.edit-pane.elements.panels', 'Panels'), typeId: 'panels', icon: 'folder' }; } - renderActions(): ReactNode { - return ( - - - - No. of panels selected: {{ length }} - - - - -
{isExpanded && (
@@ -161,15 +169,19 @@ const getStyles = (theme: GrafanaTheme2) => ({ fontSize: '1rem', fontWeight: theme.typography.fontWeightMedium, margin: 0, + height: theme.spacing(4), + display: 'flex', + alignItems: 'center', }), header: css({ display: 'flex', - cursor: 'pointer', alignItems: 'center', padding: theme.spacing(0.5, 1.5), color: theme.colors.text.primary, fontWeight: theme.typography.fontWeightMedium, - + }), + headerHover: css({ + cursor: 'pointer', '&:hover': { background: theme.colors.emphasize(theme.colors.background.primary, 0.03), }, diff --git a/public/app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor.tsx b/public/app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor.tsx index 9106be64a5d..bb1c76969d1 100644 --- a/public/app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor.tsx +++ b/public/app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor.tsx @@ -16,6 +16,7 @@ export interface OptionsPaneCategoryDescriptorProps { itemsCount?: number; customRender?: () => React.ReactNode; sandboxId?: string; + isOpenable?: boolean; } /** diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index 2447f89a826..3dd18f11efa 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -1078,11 +1078,6 @@ } }, "open": "Open options pane", - "panels": { - "multi-select": { - "selection-number": "No. of panels selected: {{length}}" - } - }, "row": { "header": { "hide": "Hide", @@ -1171,6 +1166,16 @@ "rows": "Total number rows", "table-title": "Stats" }, + "layout": { + "common": { + "copy": "Copy", + "copy-or-duplicate": "Copy or Duplicate", + "delete": "Delete", + "duplicate": "Duplicate", + "layout": "Layout", + "panels-title": "{{length}} Panels Selected" + } + }, "options": { "description": "Description", "title": "Dashboard options", @@ -1325,7 +1330,9 @@ "viz-panel": { "options": { "description": "Description", - "title": "Panel options", + "open-edit": "Open Panel Edit", + "plugin-type-image": "Image of plugin type", + "title": "Panel", "title-option": "Title", "transparent-background": "Transparent background" } diff --git a/public/locales/pseudo-LOCALE/grafana.json b/public/locales/pseudo-LOCALE/grafana.json index 9bd26c9e45a..4d2e90d0c70 100644 --- a/public/locales/pseudo-LOCALE/grafana.json +++ b/public/locales/pseudo-LOCALE/grafana.json @@ -1078,11 +1078,6 @@ } }, "open": "Øpęʼn őpŧįőʼnş päʼnę", - "panels": { - "multi-select": { - "selection-number": "Ńő. őƒ päʼnęľş şęľęčŧęđ: {{length}}" - } - }, "row": { "header": { "hide": "Ħįđę", @@ -1171,6 +1166,16 @@ "rows": "Ŧőŧäľ ʼnūmþęř řőŵş", "table-title": "Ŝŧäŧş" }, + "layout": { + "common": { + "copy": "Cőpy", + "copy-or-duplicate": "Cőpy őř Đūpľįčäŧę", + "delete": "Đęľęŧę", + "duplicate": "Đūpľįčäŧę", + "layout": "Ŀäyőūŧ", + "panels-title": "{{length}} Päʼnęľş Ŝęľęčŧęđ" + } + }, "options": { "description": "Đęşčřįpŧįőʼn", "title": "Đäşĥþőäřđ őpŧįőʼnş", @@ -1325,7 +1330,9 @@ "viz-panel": { "options": { "description": "Đęşčřįpŧįőʼn", - "title": "Päʼnęľ őpŧįőʼnş", + "open-edit": "Øpęʼn Päʼnęľ Ēđįŧ", + "plugin-type-image": "Ĩmäģę őƒ pľūģįʼn ŧypę", + "title": "Päʼnęľ", "title-option": "Ŧįŧľę", "transparent-background": "Ŧřäʼnşpäřęʼnŧ þäčĸģřőūʼnđ" } From d1b20c652d4affc8a9413b592f9ae2cd42c8336f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Mar 2025 12:11:08 +0100 Subject: [PATCH 55/74] Bump github.com/go-jose/go-jose/v3 from 3.0.3 to 3.0.4 (#101385) * Bump github.com/go-jose/go-jose/v3 from 3.0.3 to 3.0.4 Bumps [github.com/go-jose/go-jose/v3](https://github.com/go-jose/go-jose) from 3.0.3 to 3.0.4. - [Release notes](https://github.com/go-jose/go-jose/releases) - [Changelog](https://github.com/go-jose/go-jose/blob/main/CHANGELOG.md) - [Commits](https://github.com/go-jose/go-jose/compare/v3.0.3...v3.0.4) --- updated-dependencies: - dependency-name: github.com/go-jose/go-jose/v3 dependency-type: direct:production ... Signed-off-by: dependabot[bot] * update workspace --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- pkg/apimachinery/go.mod | 2 +- pkg/apimachinery/go.sum | 4 ++-- pkg/storage/unified/apistore/go.mod | 2 +- pkg/storage/unified/apistore/go.sum | 4 ++-- pkg/storage/unified/resource/go.mod | 2 +- pkg/storage/unified/resource/go.sum | 4 ++-- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 1ddd0152b12..5c909f4d188 100644 --- a/go.mod +++ b/go.mod @@ -48,7 +48,7 @@ require ( github.com/fullstorydev/grpchan v1.1.1 // @grafana/grafana-backend-group github.com/gchaincl/sqlhooks v1.3.0 // @grafana/grafana-search-and-storage github.com/getkin/kin-openapi v0.129.0 // @grafana/grafana-app-platform-squad - github.com/go-jose/go-jose/v3 v3.0.3 // @grafana/identity-access-team + github.com/go-jose/go-jose/v3 v3.0.4 // @grafana/identity-access-team github.com/go-kit/log v0.2.1 // @grafana/grafana-backend-group github.com/go-ldap/ldap/v3 v3.4.4 // @grafana/identity-access-team github.com/go-openapi/loads v0.22.0 // @grafana/alerting-backend diff --git a/go.sum b/go.sum index 21c166a08d9..627ce54fc2d 100644 --- a/go.sum +++ b/go.sum @@ -1175,8 +1175,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= -github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= -github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= +github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY= +github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= diff --git a/pkg/apimachinery/go.mod b/pkg/apimachinery/go.mod index a3f8b199c92..c702c33a2ca 100644 --- a/pkg/apimachinery/go.mod +++ b/pkg/apimachinery/go.mod @@ -15,7 +15,7 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/go-jose/go-jose/v3 v3.0.3 // indirect + github.com/go-jose/go-jose/v3 v3.0.4 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect diff --git a/pkg/apimachinery/go.sum b/pkg/apimachinery/go.sum index a2532bad3ff..4982a368eb5 100644 --- a/pkg/apimachinery/go.sum +++ b/pkg/apimachinery/go.sum @@ -6,8 +6,8 @@ github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxER github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= -github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= +github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY= +github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= diff --git a/pkg/storage/unified/apistore/go.mod b/pkg/storage/unified/apistore/go.mod index bc3820efab7..30a247fd9ed 100644 --- a/pkg/storage/unified/apistore/go.mod +++ b/pkg/storage/unified/apistore/go.mod @@ -146,7 +146,7 @@ require ( github.com/gchaincl/sqlhooks v1.3.0 // indirect github.com/getkin/kin-openapi v0.129.0 // indirect github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect - github.com/go-jose/go-jose/v3 v3.0.3 // indirect + github.com/go-jose/go-jose/v3 v3.0.4 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-ldap/ldap/v3 v3.4.4 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect diff --git a/pkg/storage/unified/apistore/go.sum b/pkg/storage/unified/apistore/go.sum index a3a38f639b9..6a18c347c14 100644 --- a/pkg/storage/unified/apistore/go.sum +++ b/pkg/storage/unified/apistore/go.sum @@ -373,8 +373,8 @@ github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkPro github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= -github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= +github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY= +github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= diff --git a/pkg/storage/unified/resource/go.mod b/pkg/storage/unified/resource/go.mod index a6802a0d5b2..5fe39d78291 100644 --- a/pkg/storage/unified/resource/go.mod +++ b/pkg/storage/unified/resource/go.mod @@ -88,7 +88,7 @@ require ( github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/getkin/kin-openapi v0.129.0 // indirect - github.com/go-jose/go-jose/v3 v3.0.3 // indirect + github.com/go-jose/go-jose/v3 v3.0.4 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.4.2 // indirect diff --git a/pkg/storage/unified/resource/go.sum b/pkg/storage/unified/resource/go.sum index 49c224e0ad3..656e395e5b9 100644 --- a/pkg/storage/unified/resource/go.sum +++ b/pkg/storage/unified/resource/go.sum @@ -244,8 +244,8 @@ github.com/getkin/kin-openapi v0.129.0 h1:QGYTNcmyP5X0AtFQ2Dkou9DGBJsUETeLH9rFrJ github.com/getkin/kin-openapi v0.129.0/go.mod h1:gmWI+b/J45xqpyK5wJmRRZse5wefA5H0RDMK46kLUtI= github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= -github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= -github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= +github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY= +github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= From b110754c9a834396137d2f6f2d5c4578c27d330e Mon Sep 17 00:00:00 2001 From: Matheus Macabu Date: Mon, 3 Mar 2025 13:12:13 +0100 Subject: [PATCH 56/74] Hackaton: Add more unit tests, take 2 (#101473) * login/social/socialimpl: add assertions for usage stats, support bundle and oauthinfo methods * accesscontrol/acimpl: add tests for GetRoleByName * anonymous/sortopts: add tests for Sorter * cloudmigration/gmsclient: add basic test cases for all methods * shorturls/shorturlimpl: add more edge test cases * tag/tagimpl: add test to cover duplicate tag kv and nil pairs * updatechecker: add test cases for module --- pkg/login/social/socialimpl/service_test.go | 39 +- .../accesscontrol/acimpl/service_test.go | 35 ++ .../anonymous/sortopts/sortopts_test.go | 147 ++++++ .../cloudmigration/gmsclient/gms_client.go | 2 +- .../gmsclient/gms_client_test.go | 478 ++++++++++++++++++ .../shorturls/shorturlimpl/shorturl_test.go | 44 ++ .../supportbundles/supportbundlestest/fake.go | 5 +- pkg/services/tag/model_test.go | 6 + pkg/services/tag/tagimpl/store_test.go | 4 +- pkg/services/updatechecker/grafana_test.go | 132 +++++ 10 files changed, 887 insertions(+), 5 deletions(-) create mode 100644 pkg/services/anonymous/sortopts/sortopts_test.go create mode 100644 pkg/services/updatechecker/grafana_test.go diff --git a/pkg/login/social/socialimpl/service_test.go b/pkg/login/social/socialimpl/service_test.go index ad9617bc15b..776fc077d8a 100644 --- a/pkg/login/social/socialimpl/service_test.go +++ b/pkg/login/social/socialimpl/service_test.go @@ -1,6 +1,7 @@ package socialimpl import ( + "context" "testing" "github.com/stretchr/testify/require" @@ -85,6 +86,8 @@ func TestSocialService_ProvideService(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { + ctx := context.Background() + env := &testEnv{ features: featuremgmt.WithFeatures(), } @@ -92,13 +95,45 @@ func TestSocialService_ProvideService(t *testing.T) { tc.setup(t, env) } - socialService := ProvideService(cfg, env.features, &usagestats.UsageStatsMock{}, supportbundlestest.NewFakeBundleService(), remotecache.NewFakeStore(t), nil, ssoSettingsSvc) - require.Equal(t, tc.expectedSocialMapLength, len(socialService.socialMap)) + usageInsights := &usagestats.UsageStatsMock{} + supportBundle := supportbundlestest.NewFakeBundleService() + + socialService := ProvideService(cfg, env.features, usageInsights, supportBundle, remotecache.NewFakeStore(t), nil, ssoSettingsSvc) + require.Equal(t, tc.expectedSocialMapLength, len(socialService.GetOAuthProviders())) genericOAuthInfo := socialService.GetOAuthInfoProvider("generic_oauth") if genericOAuthInfo != nil { require.Equal(t, tc.expectedGenericOAuthSkipOrgRoleSync, genericOAuthInfo.SkipOrgRoleSync) } + + for name, enabled := range socialService.GetOAuthProviders() { + client, err := socialService.GetOAuthHttpClient(name) + if !enabled { + require.Error(t, err) + require.Nil(t, client) + } else { + require.NoError(t, err) + require.NotNil(t, client) + } + } + + report, err := usageInsights.GetUsageReport(ctx) + require.NoError(t, err) + require.NotNil(t, report) + require.Len(t, report.Metrics, tc.expectedSocialMapLength) + + require.Len(t, supportBundle.Collectors, tc.expectedSocialMapLength) + + createdBundles := make(map[string]struct{}, 0) + for _, collector := range supportBundle.Collectors { + supportItem, err := collector.Fn(ctx) + require.NoError(t, err) + require.NotNil(t, supportItem) + + createdBundles[supportItem.Filename] = struct{}{} + } + + require.Len(t, createdBundles, tc.expectedSocialMapLength) }) } } diff --git a/pkg/services/accesscontrol/acimpl/service_test.go b/pkg/services/accesscontrol/acimpl/service_test.go index 2d991d98ab6..d1f3e45c1d0 100644 --- a/pkg/services/accesscontrol/acimpl/service_test.go +++ b/pkg/services/accesscontrol/acimpl/service_test.go @@ -970,3 +970,38 @@ func TestService_DeleteExternalServiceRole(t *testing.T) { }) } } + +func TestService_GetRoleByName(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + t.Run("when the role does not exists, it returns an error", func(t *testing.T) { + t.Parallel() + + ac := setupTestEnv(t) + ac.registrations = accesscontrol.RegistrationList{} + + role, err := ac.GetRoleByName(ctx, 0, "not-found-role") + require.ErrorIs(t, err, accesscontrol.ErrRoleNotFound) + require.Nil(t, role) + }) + + t.Run("when the role exists, it is returned", func(t *testing.T) { + t.Parallel() + + roleName := "fixed:test:test" + + ac := setupTestEnv(t) + ac.registrations = accesscontrol.RegistrationList{} + ac.registrations.Append(accesscontrol.RoleRegistration{ + Role: accesscontrol.RoleDTO{Name: roleName}, + Grants: []string{"Admin"}, + }) + + role, err := ac.GetRoleByName(ctx, 0, roleName) + require.NoError(t, err) + require.NotNil(t, role) + require.Equal(t, roleName, role.Name) + }) +} diff --git a/pkg/services/anonymous/sortopts/sortopts_test.go b/pkg/services/anonymous/sortopts/sortopts_test.go new file mode 100644 index 00000000000..38e0ead7985 --- /dev/null +++ b/pkg/services/anonymous/sortopts/sortopts_test.go @@ -0,0 +1,147 @@ +package sortopts + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestSorter(t *testing.T) { + tests := []struct { + name string + query string + expectedSQL []string + expectedErr bool + }{ + { + name: "empty query", + query: "", + }, + { + name: "single field ascending", + query: "userAgent-asc", + expectedSQL: []string{"user_agent ASC"}, + }, + { + name: "single field descending", + query: "userAgent-desc", + expectedSQL: []string{"user_agent DESC"}, + }, + { + name: "multiple fields", + query: "userAgent-asc,updatedAt-desc", + expectedSQL: []string{"user_agent ASC", "updated_at DESC"}, + }, + { + name: "unknown option", + query: "uzer_agent", + expectedErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + sortOptions, err := ParseSortQueryParam(tt.query) + if tt.expectedErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + + if len(tt.expectedSQL) > 0 { + orderBy := make([]string, 0) + for _, opt := range sortOptions { + require.Len(t, opt.Filter, 1) + + orderBy = append(orderBy, opt.Filter[0].OrderBy()) + } + + assert.EqualValues(t, tt.expectedSQL, orderBy) + } + }) + } +} + +func TestSorter_OrderBy(t *testing.T) { + tests := []struct { + name string + sorter Sorter + expectedSQL string + }{ + { + name: "with table name ascending", + sorter: Sorter{ + Field: "user_agent", + WithTableName: true, + }, + expectedSQL: "anon_device.user_agent ASC", + }, + { + name: "with table name descending", + sorter: Sorter{ + Field: "user_agent", + WithTableName: true, + Descending: true, + }, + expectedSQL: "anon_device.user_agent DESC", + }, + { + name: "without table name ascending", + sorter: Sorter{ + Field: "user_agent", + }, + expectedSQL: "user_agent ASC", + }, + { + name: "without table name descending", + sorter: Sorter{ + Field: "user_agent", + Descending: true, + }, + expectedSQL: "user_agent DESC", + }, + { + name: "with table name lowercase ascending", + sorter: Sorter{ + Field: "user_agent", + WithTableName: true, + LowerCase: true, + }, + expectedSQL: "LOWER(anon_device.user_agent) ASC", + }, + { + name: "with table name lowercase descending", + sorter: Sorter{ + Field: "user_agent", + WithTableName: true, + LowerCase: true, + Descending: true, + }, + expectedSQL: "LOWER(anon_device.user_agent) DESC", + }, + { + name: "without table name lowercase ascending", + sorter: Sorter{ + Field: "user_agent", + LowerCase: true, + }, + expectedSQL: "LOWER(user_agent) ASC", + }, + { + name: "without table name lowercase descending", + sorter: Sorter{ + Field: "user_agent", + LowerCase: true, + Descending: true, + }, + expectedSQL: "LOWER(user_agent) DESC", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.expectedSQL, tt.sorter.OrderBy()) + }) + } +} diff --git a/pkg/services/cloudmigration/gmsclient/gms_client.go b/pkg/services/cloudmigration/gmsclient/gms_client.go index 18f4c0539a7..e74b232f918 100644 --- a/pkg/services/cloudmigration/gmsclient/gms_client.go +++ b/pkg/services/cloudmigration/gmsclient/gms_client.go @@ -32,7 +32,7 @@ func NewGMSClient(cfg *setting.Cfg, httpClient *http.Client) (Client, error) { type gmsClientImpl struct { cfg *setting.Cfg - log *log.ConcreteLogger + log log.Logger httpClient *http.Client getStatusMux sync.Mutex diff --git a/pkg/services/cloudmigration/gmsclient/gms_client_test.go b/pkg/services/cloudmigration/gmsclient/gms_client_test.go index 449c64decf7..d8acbd0af10 100644 --- a/pkg/services/cloudmigration/gmsclient/gms_client_test.go +++ b/pkg/services/cloudmigration/gmsclient/gms_client_test.go @@ -1,13 +1,20 @@ package gmsclient import ( + "context" + "fmt" "net/http" + "net/http/httptest" + "runtime" "testing" + "time" + "github.com/grafana/grafana/pkg/infra/log/logtest" "github.com/grafana/grafana/pkg/services/cloudmigration" "github.com/grafana/grafana/pkg/setting" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "golang.org/x/sync/errgroup" ) func Test_buildURL(t *testing.T) { @@ -129,3 +136,474 @@ func Test_handleGMSErrors(t *testing.T) { require.ErrorIs(t, resError, tc.expectedError) } } + +func Test_ValidateKey(t *testing.T) { + t.Parallel() + + t.Run("when the key is valid, it returns no error", func(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + session := cloudmigration.CloudMigrationSession{ + StackID: 1234, + AuthToken: "auth-tok", + ClusterSlug: "cluster-slug", + } + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, http.MethodPost, r.Method) + + auth := r.Header.Get("Authorization") + require.Equal(t, fmt.Sprintf("Bearer %d:%s", session.StackID, session.AuthToken), auth) + + w.WriteHeader(http.StatusOK) + })) + t.Cleanup(server.Close) + + cfg := &setting.Cfg{ + CloudMigration: setting.CloudMigrationSettings{ + GMSDomain: server.URL, + GMSValidateKeyTimeout: time.Hour, // arbitrary, it just can't be 0. + }, + } + logger := &logtest.Fake{} + client := gmsClientImpl{cfg: cfg, log: logger, httpClient: http.DefaultClient} + + err := client.ValidateKey(ctx, session) + require.NoError(t, err) + }) + + t.Run("when the key invalidated for any reason, it returns a token validation failure", func(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + session := cloudmigration.CloudMigrationSession{ + StackID: 1234, + AuthToken: "auth-tok", + ClusterSlug: "cluster-slug", + } + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, http.MethodPost, r.Method) + + auth := r.Header.Get("Authorization") + require.Equal(t, fmt.Sprintf("Bearer %d:%s", session.StackID, session.AuthToken), auth) + + w.WriteHeader(http.StatusBadRequest) + _, _ = w.Write([]byte(`{"message": "instance is unreachable"}`)) // could be any other error that is unmapped. + })) + t.Cleanup(server.Close) + + cfg := &setting.Cfg{ + CloudMigration: setting.CloudMigrationSettings{ + GMSDomain: server.URL, + GMSValidateKeyTimeout: time.Hour, // arbitrary, it just can't be 0. + }, + } + logger := &logtest.Fake{} + client := gmsClientImpl{cfg: cfg, log: logger, httpClient: http.DefaultClient} + + err := client.ValidateKey(ctx, session) + require.Error(t, err) + }) +} + +func Test_StartSnapshot(t *testing.T) { + t.Parallel() + + t.Run("when the session is valid, a snapshot result is returned", func(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + session := cloudmigration.CloudMigrationSession{ + StackID: 1234, + AuthToken: "auth-tok", + ClusterSlug: "cluster-slug", + } + + expectedSnapshot := &cloudmigration.StartSnapshotResponse{ + SnapshotID: "uuid", + MaxItemsPerPartition: 1024, + Algo: "nacl", + EncryptionKey: []uint8{0x66, 0x6f, 0x6f, 0xa}, // foo + Metadata: []uint8{0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xa}, // metadata + } + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, http.MethodPost, r.Method) + + auth := r.Header.Get("Authorization") + require.Equal(t, fmt.Sprintf("Bearer %d:%s", session.StackID, session.AuthToken), auth) + + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(`{ + "snapshotID": "uuid", + "maxItemsPerPartition": 1024, + "algo": "nacl", + "encryptionKey": "Zm9vCg==", + "metadata": "bWV0YWRhdGEK" + }`)) + })) + t.Cleanup(server.Close) + + cfg := &setting.Cfg{ + CloudMigration: setting.CloudMigrationSettings{ + GMSDomain: server.URL, + GMSStartSnapshotTimeout: time.Hour, // arbitrary, it just can't be 0. + }, + } + logger := &logtest.Fake{} + client := gmsClientImpl{cfg: cfg, log: logger, httpClient: http.DefaultClient} + + resp, err := client.StartSnapshot(ctx, session) + require.NoError(t, err) + require.NotNil(t, resp) + require.EqualValues(t, expectedSnapshot, resp) + }) + + t.Run("when there is an error in the upstream, it logs and returns the error", func(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + session := cloudmigration.CloudMigrationSession{ + StackID: 1234, + AuthToken: "auth-tok", + ClusterSlug: "cluster-slug", + } + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, http.MethodPost, r.Method) + + auth := r.Header.Get("Authorization") + require.Equal(t, fmt.Sprintf("Bearer %d:%s", session.StackID, session.AuthToken), auth) + + w.WriteHeader(http.StatusInternalServerError) + _, _ = w.Write([]byte(`{"message": "internal server error"}`)) + })) + t.Cleanup(server.Close) + + cfg := &setting.Cfg{ + CloudMigration: setting.CloudMigrationSettings{ + GMSDomain: server.URL, + GMSStartSnapshotTimeout: time.Hour, // arbitrary, it just can't be 0. + }, + } + logger := &logtest.Fake{} + client := gmsClientImpl{cfg: cfg, log: logger, httpClient: http.DefaultClient} + + resp, err := client.StartSnapshot(ctx, session) + require.Error(t, err) + require.Nil(t, resp) + + require.Equal(t, 1, logger.ErrorLogs.Calls) + }) +} + +func Test_GetSnapshotStatus(t *testing.T) { + t.Parallel() + + t.Run("it queries the snapshot status and returns it", func(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + session := cloudmigration.CloudMigrationSession{ + StackID: 1234, + AuthToken: "auth-tok", + ClusterSlug: "cluster-slug", + } + + snapshot := cloudmigration.CloudMigrationSnapshot{ + UID: "snapshot-uuid", + } + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, http.MethodGet, r.Method) + + auth := r.Header.Get("Authorization") + require.Equal(t, fmt.Sprintf("Bearer %d:%s", session.StackID, session.AuthToken), auth) + + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(`{ + "state": "PROCESSING", + "results": [] + }`)) + })) + t.Cleanup(server.Close) + + cfg := &setting.Cfg{ + CloudMigration: setting.CloudMigrationSettings{ + GMSDomain: server.URL, + GMSGetSnapshotStatusTimeout: time.Hour, // arbitrary, it just can't be 0. + }, + } + logger := &logtest.Fake{} + client := gmsClientImpl{cfg: cfg, log: logger, httpClient: http.DefaultClient} + + g, gctx := errgroup.WithContext(ctx) + for range runtime.NumCPU() * 2 { // run a couple of concurrent requests to check for race condition. + g.Go(func() error { + resp, err := client.GetSnapshotStatus(gctx, session, snapshot, 0) + require.NotNil(t, resp) + + return err + }) + } + require.NoError(t, g.Wait()) + + require.NotEmpty(t, client.getStatusLastQueried) + }) + + t.Run("when there is an error in the upstream, it logs and returns the error", func(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + session := cloudmigration.CloudMigrationSession{ + StackID: 1234, + AuthToken: "auth-tok", + ClusterSlug: "cluster-slug", + } + + snapshot := cloudmigration.CloudMigrationSnapshot{ + UID: "snapshot-uuid", + } + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, http.MethodGet, r.Method) + + auth := r.Header.Get("Authorization") + require.Equal(t, fmt.Sprintf("Bearer %d:%s", session.StackID, session.AuthToken), auth) + + w.WriteHeader(http.StatusInternalServerError) + _, _ = w.Write([]byte(`{"message": "internal server error"}`)) + })) + t.Cleanup(server.Close) + + cfg := &setting.Cfg{ + CloudMigration: setting.CloudMigrationSettings{ + GMSDomain: server.URL, + GMSGetSnapshotStatusTimeout: time.Hour, // arbitrary, it just can't be 0. + }, + } + logger := &logtest.Fake{} + client := gmsClientImpl{cfg: cfg, log: logger, httpClient: http.DefaultClient} + + resp, err := client.GetSnapshotStatus(ctx, session, snapshot, 0) + require.Error(t, err) + require.Nil(t, resp) + + require.Equal(t, 1, logger.ErrorLogs.Calls) + }) +} + +func Test_CreatePresignedUploadUrl(t *testing.T) { + t.Parallel() + + t.Run("when the snapshot and session are valid, it returns a presigned url string", func(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + session := cloudmigration.CloudMigrationSession{ + StackID: 1234, + AuthToken: "auth-tok", + ClusterSlug: "cluster-slug", + } + + snapshot := cloudmigration.CloudMigrationSnapshot{ + UID: "snapshot-uuid", + } + + expectedURL := "http://example.com" + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, http.MethodPost, r.Method) + + auth := r.Header.Get("Authorization") + require.Equal(t, fmt.Sprintf("Bearer %d:%s", session.StackID, session.AuthToken), auth) + + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(`{"uploadUrl": "` + expectedURL + `"}`)) + })) + t.Cleanup(server.Close) + + cfg := &setting.Cfg{ + CloudMigration: setting.CloudMigrationSettings{ + GMSDomain: server.URL, + GMSCreateUploadUrlTimeout: time.Hour, // arbitrary, it just can't be 0. + }, + } + logger := &logtest.Fake{} + client := gmsClientImpl{cfg: cfg, log: logger, httpClient: http.DefaultClient} + + url, err := client.CreatePresignedUploadUrl(ctx, session, snapshot) + require.NoError(t, err) + require.Equal(t, expectedURL, url) + }) + + t.Run("when there is an error in the upstream, it logs and returns the error", func(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + session := cloudmigration.CloudMigrationSession{ + StackID: 1234, + AuthToken: "auth-tok", + ClusterSlug: "cluster-slug", + } + + snapshot := cloudmigration.CloudMigrationSnapshot{ + UID: "snapshot-uuid", + } + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, http.MethodPost, r.Method) + + auth := r.Header.Get("Authorization") + require.Equal(t, fmt.Sprintf("Bearer %d:%s", session.StackID, session.AuthToken), auth) + + w.WriteHeader(http.StatusInternalServerError) + _, _ = w.Write([]byte(`{"message": "internal server error"}`)) + })) + t.Cleanup(server.Close) + + cfg := &setting.Cfg{ + CloudMigration: setting.CloudMigrationSettings{ + GMSDomain: server.URL, + GMSCreateUploadUrlTimeout: time.Hour, // arbitrary, it just can't be 0. + }, + } + logger := &logtest.Fake{} + client := gmsClientImpl{cfg: cfg, log: logger, httpClient: http.DefaultClient} + + url, err := client.CreatePresignedUploadUrl(ctx, session, snapshot) + require.Error(t, err) + require.Empty(t, url) + + require.Equal(t, 1, logger.ErrorLogs.Calls) + }) +} + +func Test_ReportEvent(t *testing.T) { + t.Parallel() + + t.Run("when the session data is valid, it does not log an error", func(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + session := cloudmigration.CloudMigrationSession{ + StackID: 1234, + AuthToken: "auth-tok", + ClusterSlug: "cluster-slug", + } + + event := EventRequestDTO{ + LocalID: "local-id", + Event: EventDoneUploadingSnapshot, + } + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, http.MethodPost, r.Method) + + auth := r.Header.Get("Authorization") + require.Equal(t, fmt.Sprintf("Bearer %d:%s", session.StackID, session.AuthToken), auth) + + w.WriteHeader(http.StatusNoContent) + })) + t.Cleanup(server.Close) + + cfg := &setting.Cfg{ + CloudMigration: setting.CloudMigrationSettings{ + GMSDomain: server.URL, + GMSReportEventTimeout: time.Hour, // arbitrary, it just can't be 0. + }, + } + logger := &logtest.Fake{} + client := gmsClientImpl{cfg: cfg, log: logger, httpClient: http.DefaultClient} + + client.ReportEvent(ctx, session, event) + + require.Zero(t, logger.DebugLogs.Calls) + require.Zero(t, logger.WarnLogs.Calls) + require.Zero(t, logger.InfoLogs.Calls) + require.Zero(t, logger.ErrorLogs.Calls) + }) + + t.Run("when the session is missing required data, it returns without doing anything", func(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + event := EventRequestDTO{ + Event: EventDoneUploadingSnapshot, + } + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.True(t, false) // This will never be called, but if it does, it will cause the test to fail. + })) + t.Cleanup(server.Close) + + cfg := &setting.Cfg{ + CloudMigration: setting.CloudMigrationSettings{ + GMSDomain: server.URL, + GMSReportEventTimeout: 0, // this won't be called. + }, + } + logger := &logtest.Fake{} + client := gmsClientImpl{cfg: cfg, log: logger, httpClient: http.DefaultClient} + + client.ReportEvent(ctx, cloudmigration.CloudMigrationSession{}, event) + + require.Zero(t, logger.DebugLogs.Calls) + require.Zero(t, logger.WarnLogs.Calls) + require.Zero(t, logger.InfoLogs.Calls) + require.Zero(t, logger.ErrorLogs.Calls) + }) + + t.Run("when the upstream server is down, it logs the error", func(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + session := cloudmigration.CloudMigrationSession{ + StackID: 1234, + AuthToken: "auth-tok", + ClusterSlug: "cluster-slug", + } + + event := EventRequestDTO{ + LocalID: "local-id", + Event: EventDoneUploadingSnapshot, + } + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, http.MethodPost, r.Method) + + w.WriteHeader(http.StatusInternalServerError) + _, _ = w.Write([]byte(`{"message": "internal server error"}`)) + })) + t.Cleanup(server.Close) + + cfg := &setting.Cfg{ + CloudMigration: setting.CloudMigrationSettings{ + GMSDomain: server.URL, + GMSReportEventTimeout: time.Hour, // arbitrary, it just can't be 0. + }, + } + logger := &logtest.Fake{} + client := gmsClientImpl{cfg: cfg, log: logger, httpClient: http.DefaultClient} + + client.ReportEvent(ctx, session, event) + + require.Zero(t, logger.DebugLogs.Calls) + require.Zero(t, logger.WarnLogs.Calls) + require.Zero(t, logger.InfoLogs.Calls) + require.Equal(t, 2, logger.ErrorLogs.Calls) + }) +} diff --git a/pkg/services/shorturls/shorturlimpl/shorturl_test.go b/pkg/services/shorturls/shorturlimpl/shorturl_test.go index e55804bfcea..e192fed067a 100644 --- a/pkg/services/shorturls/shorturlimpl/shorturl_test.go +++ b/pkg/services/shorturls/shorturlimpl/shorturl_test.go @@ -75,6 +75,8 @@ func TestShortURLService(t *testing.T) { t.Run("and no action when no stale short urls exist", func(t *testing.T) { cmd := shorturls.DeleteShortUrlCommand{OlderThan: time.Unix(existingShortURL.CreatedAt, 0)} + + err = service.DeleteStaleShortURLs(context.Background(), &cmd) require.NoError(t, err) require.Equal(t, int64(0), cmd.NumDeleted) }) @@ -89,4 +91,46 @@ func TestShortURLService(t *testing.T) { require.True(t, shorturls.ErrShortURLNotFound.Is(err)) require.Nil(t, shortURL) }) + + t.Run("User cannot create short URLs from invalid paths", func(t *testing.T) { + service := ShortURLService{SQLStore: &sqlStore{db: store}} + + ctx := context.Background() + + absolutePath := "/path?test=true" + newShortURL, err := service.CreateShortURL(ctx, user, absolutePath) + require.ErrorIs(t, err, shorturls.ErrShortURLAbsolutePath) + require.Nil(t, newShortURL) + + relativePath := "path/../test?test=true" + newShortURL, err = service.CreateShortURL(ctx, user, relativePath) + require.ErrorIs(t, err, shorturls.ErrShortURLInvalidPath) + require.Nil(t, newShortURL) + + relativePath = "../path/test?test=true" + newShortURL, err = service.CreateShortURL(ctx, user, relativePath) + require.ErrorIs(t, err, shorturls.ErrShortURLInvalidPath) + require.Nil(t, newShortURL) + }) + + t.Run("The same URL will generate different entries", func(t *testing.T) { + service := ShortURLService{SQLStore: &sqlStore{db: store}} + + ctx := context.Background() + + const refPath = "mock/path?test=true" + + newShortURL1, err := service.CreateShortURL(ctx, user, refPath) + require.NoError(t, err) + require.NotNil(t, newShortURL1) + require.NotEmpty(t, newShortURL1.Uid) + + newShortURL2, err := service.CreateShortURL(ctx, user, refPath) + require.NoError(t, err) + require.NotNil(t, newShortURL2) + require.NotEmpty(t, newShortURL2.Uid) + + require.NotEqual(t, newShortURL1.Uid, newShortURL2.Uid) + require.Equal(t, newShortURL1.Path, newShortURL2.Path) + }) } diff --git a/pkg/services/supportbundles/supportbundlestest/fake.go b/pkg/services/supportbundles/supportbundlestest/fake.go index 8634834f4b4..c9852b38910 100644 --- a/pkg/services/supportbundles/supportbundlestest/fake.go +++ b/pkg/services/supportbundles/supportbundlestest/fake.go @@ -3,10 +3,13 @@ package supportbundlestest import "github.com/grafana/grafana/pkg/services/supportbundles" type FakeBundleService struct { + Collectors []supportbundles.Collector } func NewFakeBundleService() *FakeBundleService { return &FakeBundleService{} } -func (s *FakeBundleService) RegisterSupportItemCollector(collector supportbundles.Collector) {} +func (s *FakeBundleService) RegisterSupportItemCollector(collector supportbundles.Collector) { + s.Collectors = append(s.Collectors, collector) +} diff --git a/pkg/services/tag/model_test.go b/pkg/services/tag/model_test.go index aaf530ffa94..bb7d5aaef99 100644 --- a/pkg/services/tag/model_test.go +++ b/pkg/services/tag/model_test.go @@ -78,6 +78,12 @@ func TestParseTagPairs(t *testing.T) { assert.Equal(t, "key", tags[2].Key) assert.Equal(t, "val2", tags[2].Value) }) + + t.Run("Nil tag returns an allocated but empty pair", func(t *testing.T) { + tags := ParseTagPairs(nil) + require.NotNil(t, tags) + require.Empty(t, tags) + }) } func TestJoinTagPairs(t *testing.T) { diff --git a/pkg/services/tag/tagimpl/store_test.go b/pkg/services/tag/tagimpl/store_test.go index a3bf9c2783e..beba583727e 100644 --- a/pkg/services/tag/tagimpl/store_test.go +++ b/pkg/services/tag/tagimpl/store_test.go @@ -26,10 +26,12 @@ func testIntegrationSavingTags(t *testing.T, fn getStore) { {Key: "outage"}, {Key: "type", Value: "outage"}, {Key: "server", Value: "server-1"}, + {Key: "server", Value: "server-1"}, // duplicates will generate a new ID. {Key: "error"}, + {Key: "error"}, // duplicates will generate a new ID. } tags, err := store.EnsureTagsExist(context.Background(), tagPairs) require.Nil(t, err) - require.Equal(t, 4, len(tags)) + require.Equal(t, len(tagPairs), len(tags)) } diff --git a/pkg/services/updatechecker/grafana_test.go b/pkg/services/updatechecker/grafana_test.go new file mode 100644 index 00000000000..2f0b14293f7 --- /dev/null +++ b/pkg/services/updatechecker/grafana_test.go @@ -0,0 +1,132 @@ +package updatechecker + +import ( + "context" + "testing" + "time" + + "github.com/grafana/grafana/pkg/infra/log" + "github.com/grafana/grafana/pkg/infra/tracing" + "github.com/stretchr/testify/require" +) + +func TestGrafanaService(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + t.Run("when the Grafana version is stable", func(t *testing.T) { + t.Parallel() + + t.Run("and the latest version is newer than the current one", func(t *testing.T) { + t.Parallel() + + grafanaVersion := "99.0.0" + latestVersion := "99.0.1" + + httpClient := &fakeHTTPClient{ + fakeResp: `{"version": "` + latestVersion + `"}`, + } + + service := &GrafanaService{ + enabled: true, + grafanaVersion: grafanaVersion, + httpClient: httpClient, + log: log.NewNopLogger(), + tracer: tracing.NewNoopTracerService(), + } + + err := service.checkForUpdates(ctx) + require.NoError(t, err) + + require.True(t, service.UpdateAvailable()) + require.Equal(t, latestVersion, service.LatestVersion()) + require.False(t, service.IsDisabled()) + }) + + t.Run("and the latest version is the same as the current one", func(t *testing.T) { + t.Parallel() + + grafanaVersion := "99.0.0" + latestVersion := grafanaVersion + + httpClient := &fakeHTTPClient{ + fakeResp: `{"version": "` + latestVersion + `"}`, + } + + service := &GrafanaService{ + enabled: true, + grafanaVersion: grafanaVersion, + httpClient: httpClient, + log: log.NewNopLogger(), + tracer: tracing.NewNoopTracerService(), + } + + err := service.checkForUpdates(ctx) + require.NoError(t, err) + + require.False(t, service.UpdateAvailable()) + require.Equal(t, grafanaVersion, service.LatestVersion()) + require.False(t, service.IsDisabled()) + }) + }) + + t.Run("when the Grafana version is a development build", func(t *testing.T) { + t.Parallel() + + grafanaVersion := "99.0.0-222555" + lastestVersion := "99.0.1" + + httpClient := &fakeHTTPClient{ + fakeResp: `{"version": "` + lastestVersion + `"}`, + } + + service := &GrafanaService{ + enabled: true, + grafanaVersion: grafanaVersion, + httpClient: httpClient, + log: log.NewNopLogger(), + tracer: tracing.NewNoopTracerService(), + } + + err := service.checkForUpdates(ctx) + require.NoError(t, err) + + require.False(t, service.UpdateAvailable()) + require.Empty(t, service.LatestVersion()) + require.False(t, service.IsDisabled()) + }) +} + +func TestGrafanaService_Run(t *testing.T) { + latestVersion := "99.0.1" + + service := &GrafanaService{ + enabled: true, + grafanaVersion: "99.0.0", + httpClient: &fakeHTTPClient{ + fakeResp: `{"version": "` + latestVersion + `"}`, + }, + log: log.NewNopLogger(), + tracer: tracing.NewNoopTracerService(), + } + + ctx, cancel := context.WithCancel(context.Background()) + + // Initially there won't be any data. + require.False(t, service.UpdateAvailable()) + require.Empty(t, service.LatestVersion()) + + // Run in the background so we can cancel it after the first run. + errChan := make(chan error, 1) + go func() { + errChan <- service.Run(ctx) + }() + + // It will run once immediately then schedule it for 24 hours later. This will be true because latest > current. + require.Eventually(t, func() bool { return service.UpdateAvailable() }, 5*time.Second, 20*time.Millisecond) + + cancel() + + require.ErrorIs(t, <-errChan, context.Canceled) +} From 41ab914da270a4556c1cb497a7fcc0df7bb956e1 Mon Sep 17 00:00:00 2001 From: Haris Rozajac <58232930+harisrozajac@users.noreply.github.com> Date: Mon, 3 Mar 2025 08:07:02 -0700 Subject: [PATCH 57/74] Dashboard: Fix the unintentional time range and variables updates on saving (#101475) pass the changedModel --- .../features/dashboard-scene/saving/SaveDashboardAsForm.tsx | 1 + .../app/features/dashboard-scene/saving/SaveDashboardForm.tsx | 4 ++-- .../app/features/dashboard-scene/saving/useSaveDashboard.ts | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/public/app/features/dashboard-scene/saving/SaveDashboardAsForm.tsx b/public/app/features/dashboard-scene/saving/SaveDashboardAsForm.tsx index e21fbeb4e8f..96e52c2346a 100644 --- a/public/app/features/dashboard-scene/saving/SaveDashboardAsForm.tsx +++ b/public/app/features/dashboard-scene/saving/SaveDashboardAsForm.tsx @@ -54,6 +54,7 @@ export function SaveDashboardAsForm({ dashboard, changeInfo }: Props) { const result = await onSaveDashboard(dashboard, { overwrite, folderUid: data.folder.uid, + rawDashboardJSON: changedSaveModel, // save as config saveAsCopy: true, diff --git a/public/app/features/dashboard-scene/saving/SaveDashboardForm.tsx b/public/app/features/dashboard-scene/saving/SaveDashboardForm.tsx index ac621a91baf..7f77aac7f1b 100644 --- a/public/app/features/dashboard-scene/saving/SaveDashboardForm.tsx +++ b/public/app/features/dashboard-scene/saving/SaveDashboardForm.tsx @@ -25,7 +25,7 @@ export interface Props { } export function SaveDashboardForm({ dashboard, drawer, changeInfo }: Props) { - const { hasChanges } = changeInfo; + const { hasChanges, changedSaveModel } = changeInfo; const { state, onSaveDashboard } = useSaveDashboard(false); const [options, setOptions] = useState({ @@ -38,7 +38,7 @@ export function SaveDashboardForm({ dashboard, drawer, changeInfo }: Props) { }); const onSave = async (overwrite: boolean) => { - const result = await onSaveDashboard(dashboard, { ...options, overwrite }); + const result = await onSaveDashboard(dashboard, { ...options, rawDashboardJSON: changedSaveModel, overwrite }); if (result.status === 'success') { dashboard.closeModal(); drawer.state.onSaveSuccess?.(); diff --git a/public/app/features/dashboard-scene/saving/useSaveDashboard.ts b/public/app/features/dashboard-scene/saving/useSaveDashboard.ts index a5d8352683e..93056eb6f8f 100644 --- a/public/app/features/dashboard-scene/saving/useSaveDashboard.ts +++ b/public/app/features/dashboard-scene/saving/useSaveDashboard.ts @@ -3,6 +3,7 @@ import { useAsyncFn } from 'react-use'; import { locationUtil } from '@grafana/data'; import { locationService, reportInteraction } from '@grafana/runtime'; import { Dashboard } from '@grafana/schema'; +import { DashboardV2Spec } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0'; import appEvents from 'app/core/app_events'; import { useAppNotification } from 'app/core/copy/appNotification'; import { updateDashboardName } from 'app/core/reducers/navBarTree'; @@ -25,7 +26,7 @@ export function useSaveDashboard(isCopy = false) { options: SaveDashboardOptions & SaveDashboardAsOptions & { // When provided, will take precedence over the scene's save model - rawDashboardJSON?: Dashboard; + rawDashboardJSON?: Dashboard | DashboardV2Spec; } ) => { { From 2430e21ffaab4ee1d39e97bf3397dda2572ced04 Mon Sep 17 00:00:00 2001 From: Gilles De Mey Date: Mon, 3 Mar 2025 16:14:34 +0100 Subject: [PATCH 58/74] Alerting: Fix no search results loop for new list UI (#101513) --- .../alerting/unified/rule-list/FilterView.tsx | 10 ++++++++-- .../rule-list/hooks/useFilteredRulesIterator.ts | 13 +++++++++---- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/public/app/features/alerting/unified/rule-list/FilterView.tsx b/public/app/features/alerting/unified/rule-list/FilterView.tsx index 25358a57390..ea6b3ceec49 100644 --- a/public/app/features/alerting/unified/rule-list/FilterView.tsx +++ b/public/app/features/alerting/unified/rule-list/FilterView.tsx @@ -1,4 +1,5 @@ -import { take, tap, withAbort } from 'ix/asynciterable/operators'; +import { empty } from 'ix/asynciterable'; +import { catchError, take, tap, withAbort } from 'ix/asynciterable/operators'; import { useEffect, useRef, useState, useTransition } from 'react'; import { Card, EmptyState, Stack, Text } from '@grafana/ui'; @@ -75,7 +76,12 @@ function FilterViewResults({ filterState }: FilterViewProps) { /* This function will fetch a page of results from the iterable */ const [{ execute: loadResultPage }, state] = useAsync(async () => { - for await (const rule of rulesIterator.current.pipe(take(FRONTENT_PAGE_SIZE))) { + for await (const rule of rulesIterator.current.pipe( + // grab from the rules iterable + take(FRONTENT_PAGE_SIZE), + // if an error occurs trying to fetch a page, return an empty iterable so the front-end isn't caught in an infinite loop + catchError(() => empty()) + )) { startTransition(() => { // Rule key could be computed on the fly, but we do it here to avoid recalculating it with each render // It's a not trivial computation because it involves hashing the rule diff --git a/public/app/features/alerting/unified/rule-list/hooks/useFilteredRulesIterator.ts b/public/app/features/alerting/unified/rule-list/hooks/useFilteredRulesIterator.ts index ddbfea8e216..6512ddcea18 100644 --- a/public/app/features/alerting/unified/rule-list/hooks/useFilteredRulesIterator.ts +++ b/public/app/features/alerting/unified/rule-list/hooks/useFilteredRulesIterator.ts @@ -1,4 +1,4 @@ -import { AsyncIterableX, from } from 'ix/asynciterable/index'; +import { AsyncIterableX, empty, from } from 'ix/asynciterable'; import { merge } from 'ix/asynciterable/merge'; import { filter, flatMap, map } from 'ix/asynciterable/operators'; import { compact } from 'lodash'; @@ -68,11 +68,16 @@ export function useFilteredRulesIteratorProvider() { map(([group, rule]) => mapGrafanaRuleToRuleWithOrigin(group, rule)) ); - const [source, ...iterables] = ruleSourcesToFetchFrom.map((ds) => { - return from(prometheusGroupsGenerator(ds, groupLimit)).pipe(map((group) => [ds, group] as const)); + const sourceIterables = ruleSourcesToFetchFrom.map((ds) => { + const generator = prometheusGroupsGenerator(ds, groupLimit); + return from(generator).pipe(map((group) => [ds, group] as const)); }); - const dataSourcesIterator = merge(source, ...iterables).pipe( + // if we have no prometheus data sources, use an empty async iterable + const source = sourceIterables.at(0) ?? empty(); + const otherIterables = sourceIterables.slice(1); + + const dataSourcesIterator = merge(source, ...otherIterables).pipe( filter(([_, group]) => groupFilter(group, normalizedFilterState)), flatMap(([rulesSource, group]) => group.rules.map((rule) => [rulesSource, group, rule] as const)), filter(([_, __, rule]) => ruleFilter(rule, filterState)), From 4bab25054f21239cfb328f0022625a2ee08c8f34 Mon Sep 17 00:00:00 2001 From: Tobias Skarhed <1438972+tskarhed@users.noreply.github.com> Date: Mon, 3 Mar 2025 16:17:57 +0100 Subject: [PATCH 59/74] FrontendMonitoring: Track web vitals attribution (#101520) --- .../grafana-javascript-agent/GrafanaJavascriptAgentBackend.ts | 1 + 1 file changed, 1 insertion(+) 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 3af977436d0..6bee3a7080f 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 @@ -102,6 +102,7 @@ export class GrafanaJavascriptAgentBackend ? instrumentations : [...getWebInstrumentations(), new TracingInstrumentation()], consoleInstrumentation: consoleInstrumentationOptions, + trackWebVitalsAttribution: options.webVitalsInstrumentalizationEnabled || options.allInstrumentationsEnabled, transports, ignoreErrors: [ 'ResizeObserver loop limit exceeded', From 165bca6417ec6c124ee29f680a0341c36cc19888 Mon Sep 17 00:00:00 2001 From: Serge Zaitsev Date: Mon, 3 Mar 2025 17:02:10 +0100 Subject: [PATCH 60/74] Chore: Add initial/experimental xorm spanner driver (#101398) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * make it build and start * run some migrations * add build tags, remove log * remove unused code * revert go.mod changes * move initialisation into dialect file * update workspace * update workspace once again * clean up dependencies * further cleanup * Address some review feedback. * Fix go.sum. --------- Co-authored-by: Peter Štibraný --- apps/alerting/notifications/go.mod | 4 +- apps/alerting/notifications/go.sum | 12 +- apps/investigations/go.mod | 4 +- apps/investigations/go.sum | 9 +- apps/playlist/go.mod | 4 +- apps/playlist/go.sum | 9 +- go.mod | 40 +- go.sum | 85 +- go.work.sum | 322 ++++ pkg/aggregator/go.mod | 6 +- pkg/aggregator/go.sum | 15 +- pkg/apimachinery/go.mod | 2 +- pkg/apimachinery/go.sum | 5 +- pkg/apiserver/go.mod | 6 +- pkg/apiserver/go.sum | 12 +- pkg/build/go.mod | 34 +- pkg/build/go.sum | 90 +- pkg/promlib/go.mod | 6 +- pkg/promlib/go.sum | 30 +- pkg/services/sqlstore/database_config.go | 2 + pkg/services/sqlstore/migrator/migrations.go | 4 + pkg/services/sqlstore/migrator/migrator.go | 5 + .../sqlstore/migrator/spanner_dialect.go | 84 + pkg/services/sqlstore/migrator/types.go | 1 + pkg/storage/unified/apistore/go.mod | 31 +- pkg/storage/unified/apistore/go.sum | 1146 +++++++++++- pkg/storage/unified/resource/go.mod | 34 +- pkg/storage/unified/resource/go.sum | 1395 +++++++++++++- pkg/util/xorm/dialect_spanner.go | 284 +++ pkg/util/xorm/go.mod | 56 +- pkg/util/xorm/go.sum | 1615 +++++++++++++++++ pkg/util/xorm/session_insert.go | 16 + 32 files changed, 5144 insertions(+), 224 deletions(-) create mode 100644 pkg/services/sqlstore/migrator/spanner_dialect.go create mode 100644 pkg/util/xorm/dialect_spanner.go diff --git a/apps/alerting/notifications/go.mod b/apps/alerting/notifications/go.mod index cf49c4e862d..dfcdc5a722a 100644 --- a/apps/alerting/notifications/go.mod +++ b/apps/alerting/notifications/go.mod @@ -80,8 +80,8 @@ require ( golang.org/x/term v0.29.0 // indirect golang.org/x/text v0.22.0 // indirect golang.org/x/time v0.9.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 // indirect google.golang.org/grpc v1.70.0 // indirect google.golang.org/protobuf v1.36.5 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect diff --git a/apps/alerting/notifications/go.sum b/apps/alerting/notifications/go.sum index 3b3312aebf7..d871841faf1 100644 --- a/apps/alerting/notifications/go.sum +++ b/apps/alerting/notifications/go.sum @@ -260,12 +260,12 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU= -google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4= -google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f h1:gap6+3Gk41EItBuyi4XX/bp4oqJ3UwuIMl25yGinuAA= -google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:Ic02D47M+zbarjYYUlK57y316f2MoN0gjAwI3f2S95o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= +google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4 h1:Pw6WnI9W/LIdRxqK7T6XGugGbHIRl5Q7q3BssH6xk4s= +google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4/go.mod h1:qbZzneIOXSq+KFAFut9krLfRLZiFLzZL5u2t8SV83EE= +google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 h1:5iw9XJTD4thFidQmFVvx0wi4g5yOHk76rNRUxz1ZG5g= +google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47/go.mod h1:AfA77qWLcidQWywD0YgqfpJzf50w2VjzBml3TybHeJU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 h1:2duwAxN2+k0xLNpjnHTXoMUgnv6VPSp5fiqTuwSxjmI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk= google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= diff --git a/apps/investigations/go.mod b/apps/investigations/go.mod index 7e9c06424d0..a57bc190e02 100644 --- a/apps/investigations/go.mod +++ b/apps/investigations/go.mod @@ -70,8 +70,8 @@ require ( golang.org/x/text v0.22.0 // indirect golang.org/x/time v0.9.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 // indirect google.golang.org/grpc v1.70.0 // indirect google.golang.org/protobuf v1.36.5 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/apps/investigations/go.sum b/apps/investigations/go.sum index bc0a2332d93..f21718f2a17 100644 --- a/apps/investigations/go.sum +++ b/apps/investigations/go.sum @@ -189,10 +189,11 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f h1:gap6+3Gk41EItBuyi4XX/bp4oqJ3UwuIMl25yGinuAA= -google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:Ic02D47M+zbarjYYUlK57y316f2MoN0gjAwI3f2S95o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= +google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 h1:5iw9XJTD4thFidQmFVvx0wi4g5yOHk76rNRUxz1ZG5g= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 h1:2duwAxN2+k0xLNpjnHTXoMUgnv6VPSp5fiqTuwSxjmI= +google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47/go.mod h1:AfA77qWLcidQWywD0YgqfpJzf50w2VjzBml3TybHeJU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 h1:2duwAxN2+k0xLNpjnHTXoMUgnv6VPSp5fiqTuwSxjmI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk= google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= diff --git a/apps/playlist/go.mod b/apps/playlist/go.mod index 474148a6799..9b03e7fcc38 100644 --- a/apps/playlist/go.mod +++ b/apps/playlist/go.mod @@ -71,8 +71,8 @@ require ( golang.org/x/text v0.22.0 // indirect golang.org/x/time v0.9.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 // indirect google.golang.org/grpc v1.70.0 // indirect google.golang.org/protobuf v1.36.5 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/apps/playlist/go.sum b/apps/playlist/go.sum index bc0a2332d93..f21718f2a17 100644 --- a/apps/playlist/go.sum +++ b/apps/playlist/go.sum @@ -189,10 +189,11 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f h1:gap6+3Gk41EItBuyi4XX/bp4oqJ3UwuIMl25yGinuAA= -google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:Ic02D47M+zbarjYYUlK57y316f2MoN0gjAwI3f2S95o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= +google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 h1:5iw9XJTD4thFidQmFVvx0wi4g5yOHk76rNRUxz1ZG5g= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 h1:2duwAxN2+k0xLNpjnHTXoMUgnv6VPSp5fiqTuwSxjmI= +google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47/go.mod h1:AfA77qWLcidQWywD0YgqfpJzf50w2VjzBml3TybHeJU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 h1:2duwAxN2+k0xLNpjnHTXoMUgnv6VPSp5fiqTuwSxjmI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk= google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= diff --git a/go.mod b/go.mod index 5c909f4d188..fbd0290c7d3 100644 --- a/go.mod +++ b/go.mod @@ -5,9 +5,9 @@ go 1.23.5 require ( buf.build/gen/go/parca-dev/parca/connectrpc/go v1.17.0-20240902100956-02fd72488966.1 // @grafana/observability-traces-and-profiling buf.build/gen/go/parca-dev/parca/protocolbuffers/go v1.34.2-20240902100956-02fd72488966.2 // @grafana/observability-traces-and-profiling - cloud.google.com/go/kms v1.20.0 // @grafana/grafana-backend-group - cloud.google.com/go/spanner v1.70.0 // @grafana/grafana-search-and-storage - cloud.google.com/go/storage v1.43.0 // @grafana/grafana-backend-group + cloud.google.com/go/kms v1.20.5 // @grafana/grafana-backend-group + cloud.google.com/go/spanner v1.75.0 // @grafana/grafana-search-and-storage + cloud.google.com/go/storage v1.50.0 // @grafana/grafana-backend-group connectrpc.com/connect v1.17.0 // @grafana/observability-traces-and-profiling cuelang.org/go v0.11.1 // @grafana/grafana-as-code filippo.io/age v1.2.1 // @grafana/identity-access-team @@ -178,7 +178,7 @@ require ( golang.org/x/time v0.9.0 // @grafana/grafana-backend-group golang.org/x/tools v0.29.0 // indirect; @grafana/grafana-as-code gonum.org/v1/gonum v0.15.1 // @grafana/oss-big-tent - google.golang.org/api v0.216.0 // @grafana/grafana-backend-group + google.golang.org/api v0.220.0 // @grafana/grafana-backend-group google.golang.org/grpc v1.70.0 // @grafana/plugins-platform-backend google.golang.org/protobuf v1.36.5 // @grafana/plugins-platform-backend gopkg.in/ini.v1 v1.67.0 // @grafana/alerting-backend @@ -221,13 +221,13 @@ require github.com/grafana/grafana-api-golang-client v0.27.0 // @grafana/alertin require ( cel.dev/expr v0.19.0 // indirect - cloud.google.com/go v0.116.0 // indirect - cloud.google.com/go/auth v0.13.0 // indirect - cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect + cloud.google.com/go v0.118.2 // indirect + cloud.google.com/go/auth v0.14.1 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.7 // indirect cloud.google.com/go/compute/metadata v0.6.0 // indirect - cloud.google.com/go/iam v1.2.1 // indirect - cloud.google.com/go/longrunning v0.6.1 // indirect - cloud.google.com/go/monitoring v1.21.1 // indirect + cloud.google.com/go/iam v1.3.1 // indirect + cloud.google.com/go/longrunning v0.6.4 // indirect + cloud.google.com/go/monitoring v1.23.0 // indirect cuelabs.dev/go/oci/ociregistry v0.0.0-20240906074133-82eb438dd565 // indirect dario.cat/mergo v1.0.1 // indirect github.com/Azure/azure-pipeline-go v0.2.3 // indirect @@ -243,7 +243,7 @@ require ( github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2 // indirect github.com/FZambia/eagle v0.1.0 // indirect - github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.0 // indirect + github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.2 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 // indirect github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c // indirect @@ -308,7 +308,6 @@ require ( github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500 // indirect github.com/caio/go-tdigest v3.1.0+incompatible // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect - github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect github.com/centrifugal/protocol v0.13.4 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -335,7 +334,6 @@ require ( github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/emicklei/proto v1.13.2 // indirect github.com/emirpasic/gods v1.18.1 // indirect - github.com/envoyproxy/go-control-plane v0.13.1 // indirect github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -367,7 +365,7 @@ require ( github.com/google/flatbuffers v24.3.25+incompatible // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/s2a-go v0.1.8 // indirect + github.com/google/s2a-go v0.1.9 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect github.com/grafana/jsonparser v0.0.0-20240425183733-ea80629e1a32 // indirect github.com/grafana/loki/pkg/push v0.0.0-20231124142027-e52380921608 // indirect @@ -519,7 +517,7 @@ require ( go.mongodb.org/mongo-driver v1.16.1 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/contrib/detectors/gcp v1.32.0 // indirect + go.opentelemetry.io/contrib/detectors/gcp v1.33.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 // indirect go.opentelemetry.io/otel/metric v1.34.0 // indirect @@ -532,9 +530,9 @@ require ( golang.org/x/term v0.29.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect + google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect @@ -556,6 +554,12 @@ require ( sigs.k8s.io/yaml v1.4.0 // indirect ) +require ( + github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0 // indirect + github.com/envoyproxy/go-control-plane/envoy v1.32.3 // indirect +) + // Use fork of crewjam/saml with fixes for some issues until changes get merged into upstream replace github.com/crewjam/saml => github.com/grafana/saml v0.4.15-0.20240917091248-ae3bbdad8a56 diff --git a/go.sum b/go.sum index 627ce54fc2d..a186575cc8d 100644 --- a/go.sum +++ b/go.sum @@ -46,8 +46,8 @@ cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFO cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw= -cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= -cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= +cloud.google.com/go v0.118.2 h1:bKXO7RXMFDkniAAvvuMrAPtQ/VHrs9e7J5UT3yrGdTY= +cloud.google.com/go v0.118.2/go.mod h1:CFO4UPEPi8oV21xoezZCrd3d81K4fFkDTEJu4R8K+9M= cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= @@ -109,10 +109,10 @@ cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVo cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= -cloud.google.com/go/auth v0.13.0 h1:8Fu8TZy167JkW8Tj3q7dIkr2v4cndv41ouecJx0PAHs= -cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q= -cloud.google.com/go/auth/oauth2adapt v0.2.6 h1:V6a6XDu2lTwPZWOawrAa9HUK+DB2zfJyTuciBG5hFkU= -cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8= +cloud.google.com/go/auth v0.14.1 h1:AwoJbzUdxA/whv1qj3TLKwh3XX5sikny2fc40wUl+h0= +cloud.google.com/go/auth v0.14.1/go.mod h1:4JHUxlGXisL0AW8kXPtUF6ztuOksyfUQNFjfsOCXkPM= +cloud.google.com/go/auth/oauth2adapt v0.2.7 h1:/Lc7xODdqcEw8IrZ9SvwnlLX6j9FHQM74z6cBk9Rw6M= +cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc= cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= @@ -330,8 +330,8 @@ cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGE cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= -cloud.google.com/go/iam v1.2.1 h1:QFct02HRb7H12J/3utj0qf5tobFh9V4vR6h9eX5EBRU= -cloud.google.com/go/iam v1.2.1/go.mod h1:3VUIJDPpwT6p/amXRC5GY8fCCh70lxPygguVtI0Z4/g= +cloud.google.com/go/iam v1.3.1 h1:KFf8SaT71yYq+sQtRISn90Gyhyf4X8RGgeAVC8XGf3E= +cloud.google.com/go/iam v1.3.1/go.mod h1:3wMtuyT4NcbnYNPLMBzYRFiEfjKfJlLVLrisE7bwm34= cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= @@ -351,8 +351,8 @@ cloud.google.com/go/kms v1.8.0/go.mod h1:4xFEhYFqvW+4VMELtZyxomGSYtSQKzM178ylFW4 cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= cloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24= cloud.google.com/go/kms v1.10.1/go.mod h1:rIWk/TryCkR59GMC3YtHtXeLzd634lBbKenvyySAyYI= -cloud.google.com/go/kms v1.20.0 h1:uKUvjGqbBlI96xGE669hcVnEMw1Px/Mvfa62dhM5UrY= -cloud.google.com/go/kms v1.20.0/go.mod h1:/dMbFF1tLLFnQV44AoI2GlotbjowyUfgVwezxW291fM= +cloud.google.com/go/kms v1.20.5 h1:aQQ8esAIVZ1atdJRxihhdxGQ64/zEbJoJnCz/ydSmKg= +cloud.google.com/go/kms v1.20.5/go.mod h1:C5A8M1sv2YWYy1AE6iSrnddSG9lRGdJq5XEdBy28Lmw= cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= @@ -363,11 +363,13 @@ cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6 cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/logging v1.13.0 h1:7j0HgAp0B94o1YRDqiqm26w4q1rDMH7XNRU34lJXHYc= +cloud.google.com/go/logging v1.13.0/go.mod h1:36CoKh6KA/M0PbhPKMq6/qety2DCAErbhXT62TuXALA= cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= -cloud.google.com/go/longrunning v0.6.1 h1:lOLTFxYpr8hcRtcwWir5ITh1PAKUD/sG2lKrTSYjyMc= -cloud.google.com/go/longrunning v0.6.1/go.mod h1:nHISoOZpBcmlwbJmiVk5oDRz0qG/ZxPynEGs1iZ79s0= +cloud.google.com/go/longrunning v0.6.4 h1:3tyw9rO3E2XVXzSApn1gyEEnH2K9SynNQjMlBi3uHLg= +cloud.google.com/go/longrunning v0.6.4/go.mod h1:ttZpLCe6e7EXvn9OxpBRx7kZEB0efv8yBO6YnVMfhJs= cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= @@ -391,8 +393,8 @@ cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhI cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw= -cloud.google.com/go/monitoring v1.21.1 h1:zWtbIoBMnU5LP9A/fz8LmWMGHpk4skdfeiaa66QdFGc= -cloud.google.com/go/monitoring v1.21.1/go.mod h1:Rj++LKrlht9uBi8+Eb530dIrzG/cU/lB8mt+lbeFK1c= +cloud.google.com/go/monitoring v1.23.0 h1:M3nXww2gn9oZ/qWN2bZ35CjolnVHM3qnSbu6srCPgjk= +cloud.google.com/go/monitoring v1.23.0/go.mod h1:034NnlQPDzrQ64G2Gavhl0LUHZs9H3rRmhtnp7jiJgg= cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= @@ -539,8 +541,8 @@ cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+ cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= cloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M= -cloud.google.com/go/spanner v1.70.0 h1:nj6p/GJTgMDiSQ1gQ034ItsKuJgHiMOjtOlONOg8PSo= -cloud.google.com/go/spanner v1.70.0/go.mod h1:X5T0XftydYp0K1adeJQDJtdWpbrOeJ7wHecM4tK6FiE= +cloud.google.com/go/spanner v1.75.0 h1:2zrltTJv/4P3pCgpYgde4Eb1vN8Cgy1fNy7pbTnOovg= +cloud.google.com/go/spanner v1.75.0/go.mod h1:TLFZBvPQmx3We7sGh12eTk9lLsRLczzZaiweqfMpR80= cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= @@ -558,8 +560,8 @@ cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeL cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= -cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs= -cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0= +cloud.google.com/go/storage v1.50.0 h1:3TbVkzTooBvnZsk7WaAQfOsNrdoM8QHusXA1cpk6QJs= +cloud.google.com/go/storage v1.50.0/go.mod h1:l7XeiD//vx5lfqE3RavfmU9yvk5Pp0Zhcv482poyafY= cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= @@ -579,6 +581,8 @@ cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= cloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk= +cloud.google.com/go/trace v1.11.3 h1:c+I4YFjxRQjvAhRmSsmjpASUKq88chOX854ied0K/pE= +cloud.google.com/go/trace v1.11.3/go.mod h1:pt7zCYiDSQjC9Y2oqCsh9jF4GStB/hmjrYLsxRR27q8= cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= cloud.google.com/go/translate v1.5.0/go.mod h1:29YDSYveqqpA1CQFD7NQuP49xymq17RXNaUDdc0mNu0= @@ -711,10 +715,16 @@ github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3 github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/FZambia/eagle v0.1.0 h1:9gyX6x+xjoIfglgyPTcYm7dvY7FJ93us1QY5De4CyXA= github.com/FZambia/eagle v0.1.0/go.mod h1:YjGSPVkQTNcVLfzEUQJNgW9ScPR0K4u/Ky0yeFa4oDA= -github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.0 h1:oVLqHXhnYtUwM89y9T1fXGaK9wTkXHgNp8/ZNMQzUxE= -github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.0/go.mod h1:dppbR7CwXD4pgtV9t3wD1812RaLDcBjtblcDF5f1vI0= +github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.2 h1:DBjmt6/otSdULyJdVg2BlG0qGZO5tKL4VzOs0jpvw5Q= +github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.2/go.mod h1:dppbR7CwXD4pgtV9t3wD1812RaLDcBjtblcDF5f1vI0= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 h1:3c8yed4lgqTt+oTQ+JNMDo+F4xprBf+O/il4ZC0nRLw= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0/go.mod h1:obipzmGjfSjam60XLwGfqUkJsfiheAl+TUjG+4yzyPM= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0 h1:o90wcURuxekmXrtxmYWTyNla0+ZEHhud6DI1ZTxd1vI= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0/go.mod h1:6fTWu4m3jocfUZLYF5KsZC1TUfRvEjs7lM4crme/irw= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.49.0 h1:jJKWl98inONJAr/IZrdFQUWcwUO95DLY1XMD1ZIut+g= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.49.0/go.mod h1:l2fIqmwB+FKSfvn3bAD/0i+AXAxhIZjTK2svT/mgUXs= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0 h1:GYUJLfvd++4DMuMhCFLgLXvFwofIxh/qOwoGuS/LTew= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0/go.mod h1:wRbFgBQUVm1YXrvWKofAEmq9HNJTDphbAaJSSX01KUI= github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c h1:RGWPOewvKIROun94nF7v2cua9qP+thov/7M50KEoeSU= @@ -963,7 +973,6 @@ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK3 github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/centrifugal/centrifuge v0.33.3 h1:uyqBc27oM+qnC3NX5imvZxuk9+u2ze6QGWHDICZeoSc= github.com/centrifugal/centrifuge v0.33.3/go.mod h1:GaOF4CiREY5x6lW7zYUz46Qrc6aUZ6J/AMV/kROc2+U= @@ -1115,8 +1124,12 @@ github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go. github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q= -github.com/envoyproxy/go-control-plane v0.13.1 h1:vPfJZCkob6yTMEgS+0TwfTUfbHjfy/6vOJ8hUWX/uXE= -github.com/envoyproxy/go-control-plane v0.13.1/go.mod h1:X45hY0mufo6Fd0KW3rqsGvQMw58jvjymeCzBU3mWyHw= +github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= +github.com/envoyproxy/go-control-plane v0.13.4/go.mod h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA= +github.com/envoyproxy/go-control-plane/envoy v1.32.3 h1:hVEaommgvzTjTd4xCaFd+kEQ2iYBtGxP6luyLrx6uOk= +github.com/envoyproxy/go-control-plane/envoy v1.32.3/go.mod h1:F6hWupPfh75TBXGKA++MCT/CZHFq5r9/uwt/kQYkZfE= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= @@ -1467,8 +1480,8 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 github.com/google/s2a-go v0.1.0/go.mod h1:OJpEgntRZo8ugHpF9hkoLJbS5dSI20XZeXJ9JVywLlM= github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= -github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= -github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= +github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= +github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -2463,8 +2476,8 @@ go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJyS go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/collector/pdata v1.22.0 h1:3yhjL46NLdTMoP8rkkcE9B0pzjf2973crn0KKhX5UrI= go.opentelemetry.io/collector/pdata v1.22.0/go.mod h1:nLLf6uDg8Kn5g3WNZwGyu8+kf77SwOqQvMTb5AXEbEY= -go.opentelemetry.io/contrib/detectors/gcp v1.32.0 h1:P78qWqkLSShicHmAzfECaTgvslqHxblNE9j62Ws1NK8= -go.opentelemetry.io/contrib/detectors/gcp v1.32.0/go.mod h1:TVqo0Sda4Cv8gCIixd7LuLwW4EylumVWfhjZJjDD4DU= +go.opentelemetry.io/contrib/detectors/gcp v1.33.0 h1:FVPoXEoILwgbZUu4X7YSgsESsAmGRgoYcnXkzgQPhP4= +go.opentelemetry.io/contrib/detectors/gcp v1.33.0/go.mod h1:ZHrLmr4ikK2AwRj9QL+c9s2SOlgoSRyMpNVzUj2fZqI= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 h1:rgMkmiGfix9vFJDcDi1PK8WEQP4FLQwLDfhp5ZLpFeE= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.55.0/go.mod h1:rsg1EO8LXSs2po50PB5CeY/MSVlhghuKBgXlKnqm6ks= @@ -2490,6 +2503,8 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 h1:tgJ0u go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0/go.mod h1:U7HYyW0zt/a9x5J1Kjs+r1f/d4ZHnYFclhYY2+YbeoE= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 h1:BEj3SPM81McUZHYjRS5pEgNgnmzGJ5tRpU5krWnV8Bs= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0/go.mod h1:9cKLGBDzI/F3NoHLQGm4ZrYdIHsvGt6ej6hUowxY0J4= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0 h1:WDdP9acbMYjbKIyJUhTvtzj601sVJOqgWdUxSdR/Ysc= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0/go.mod h1:BLbf7zbNIONBLPwvFnwNHGj4zge8uTCM/UPIVW1Mq2I= go.opentelemetry.io/otel/metric v1.17.0/go.mod h1:h4skoxdZI17AxwITdmdZjjYJQH5nzijUUjm+wtPph5o= go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ= @@ -3119,8 +3134,8 @@ google.golang.org/api v0.118.0/go.mod h1:76TtD3vkgmZ66zZzp72bUUklpmQmKlhh6sYtIjY google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms= google.golang.org/api v0.124.0/go.mod h1:xu2HQurE5gi/3t1aFCvhPD781p0a3p11sdunTJ2BlP4= google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= -google.golang.org/api v0.216.0 h1:xnEHy+xWFrtYInWPy8OdGFsyIfWJjtVnO39g7pz2BFY= -google.golang.org/api v0.216.0/go.mod h1:K9wzQMvWi47Z9IU7OgdOofvZuw75Ge3PPITImZR/UyI= +google.golang.org/api v0.220.0 h1:3oMI4gdBgB72WFVwE1nerDD8W3HUOS4kypK6rRLbGns= +google.golang.org/api v0.220.0/go.mod h1:26ZAlY6aN/8WgpCzjPNy18QpYaz7Zgg1h0qe1GkZEmY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -3272,21 +3287,21 @@ google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOl google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/genproto v0.0.0-20230525234025-438c736192d0/go.mod h1:9ExIQyXL5hZrHzQceCwuSYwZZ5QZBazOcprJ5rgs3lY= google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= -google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU= -google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4= +google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4 h1:Pw6WnI9W/LIdRxqK7T6XGugGbHIRl5Q7q3BssH6xk4s= +google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4/go.mod h1:qbZzneIOXSq+KFAFut9krLfRLZiFLzZL5u2t8SV83EE= google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f h1:gap6+3Gk41EItBuyi4XX/bp4oqJ3UwuIMl25yGinuAA= -google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:Ic02D47M+zbarjYYUlK57y316f2MoN0gjAwI3f2S95o= +google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 h1:5iw9XJTD4thFidQmFVvx0wi4g5yOHk76rNRUxz1ZG5g= +google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47/go.mod h1:AfA77qWLcidQWywD0YgqfpJzf50w2VjzBml3TybHeJU= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 h1:2duwAxN2+k0xLNpjnHTXoMUgnv6VPSp5fiqTuwSxjmI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= diff --git a/go.work.sum b/go.work.sum index 49a43b5d80b..5ef60cf78bc 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1,240 +1,488 @@ buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.31.0-20230802163732-1c33ebd9ecfa.1 h1:tdpHgTbmbvEIARu+bixzmleMi14+3imnpoFXz+Qzjp4= buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.31.0-20230802163732-1c33ebd9ecfa.1/go.mod h1:xafc+XIsTxTy76GJQ1TKgvJWsSugFBqMaN27WhUblew= +cel.dev/expr v0.15.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg= +cel.dev/expr v0.16.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg= +cel.dev/expr v0.16.1/go.mod h1:AsGA5zb3WruAEQeQng1RZdGEXmBj0jvMWh6l5SnNuC8= cel.dev/expr v0.18.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= +cloud.google.com/go v0.110.10/go.mod h1:v1OoFqYxiBkUrruItNM3eT4lLByNjxmJSV/xDKJNnic= +cloud.google.com/go v0.112.2/go.mod h1:iEqjp//KquGIJV/m+Pk3xecgKNhV+ry+vVTsy4TbDms= +cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= +cloud.google.com/go v0.117.0/go.mod h1:ZbwhVTb1DBGt2Iwb3tNO6SEK4q+cplHZmLWH+DelYYc= +cloud.google.com/go v0.118.0/go.mod h1:zIt2pkedt/mo+DQjcT4/L3NDxzHPR29j5HcclNH+9PM= +cloud.google.com/go v0.118.1/go.mod h1:CFO4UPEPi8oV21xoezZCrd3d81K4fFkDTEJu4R8K+9M= cloud.google.com/go/accessapproval v1.8.1 h1:WC6pA5Gyqkrvdc18AHvriShwk8wgMe9EWvBAQSLxTc8= cloud.google.com/go/accessapproval v1.8.1/go.mod h1:3HAtm2ertsWdwgjSGObyas6fj3ZC/3zwV2WVZXO53sU= +cloud.google.com/go/accessapproval v1.8.3 h1:axlU03FRiXDNupsmPG7LKzuS4Enk1gf598M62lWVB74= +cloud.google.com/go/accessapproval v1.8.3/go.mod h1:3speETyAv63TDrDmo5lIkpVueFkQcQchkiw/TAMbBo4= cloud.google.com/go/accesscontextmanager v1.9.1 h1:+C7HM05/h80znK+8VNu25wAimueda6/NGNdus+jxaHI= cloud.google.com/go/accesscontextmanager v1.9.1/go.mod h1:wUVSoz8HmG7m9miQTh6smbyYuNOJrvZukK5g6WxSOp0= +cloud.google.com/go/accesscontextmanager v1.9.3 h1:8zVoeiBa4erMCLEXltOcqVEsZhS26JZ5/Vrgs59eQiI= +cloud.google.com/go/accesscontextmanager v1.9.3/go.mod h1:S1MEQV5YjkAKBoMekpGrkXKfrBdsi4x6Dybfq6gZ8BU= cloud.google.com/go/aiplatform v1.68.0 h1:EPPqgHDJpBZKRvv+OsB3cr0jYz3EL2pZ+802rBPcG8U= cloud.google.com/go/aiplatform v1.68.0/go.mod h1:105MFA3svHjC3Oazl7yjXAmIR89LKhRAeNdnDKJczME= +cloud.google.com/go/aiplatform v1.70.0 h1:vnqsPkgcwlDEpWl9t6C3/HLfHeweuGXs2gcYTzH6dMs= +cloud.google.com/go/aiplatform v1.70.0/go.mod h1:1cewyC4h+yvRs0qVvlCuU3V6j1pJ41doIcroYX3uv8o= cloud.google.com/go/analytics v0.25.1 h1:tMlK9KGTwHYASagAHXXbIPUVCRknA0Yv4jquim5HdRE= cloud.google.com/go/analytics v0.25.1/go.mod h1:hrAWcN/7tqyYwF/f60Nph1yz5UE3/PxOPzzFsJgtU+Y= +cloud.google.com/go/analytics v0.25.3 h1:hX6JAsNbXd2uVjqjIuMcKpmhIybKrEunBiGxK4SwEFI= +cloud.google.com/go/analytics v0.25.3/go.mod h1:pWoYg4yEr0iYg83LZRAicjDDdv54+Z//RyhzWwKbavI= cloud.google.com/go/apigateway v1.7.1 h1:BeR+5NtpGxsUoK8wa/IPkanORjqZdlyNmXZ8ke3tOhc= cloud.google.com/go/apigateway v1.7.1/go.mod h1:5JBcLrl7GHSGRzuDaISd5u0RKV05DNFiq4dRdfrhCP0= +cloud.google.com/go/apigateway v1.7.3 h1:Mn7cC5iWJz+cSMS/Hb+N2410CpZ6c8XpJKaexBl0Gxs= +cloud.google.com/go/apigateway v1.7.3/go.mod h1:uK0iRHdl2rdTe79bHW/bTsKhhXPcFihjUdb7RzhTPf4= cloud.google.com/go/apigeeconnect v1.7.1 h1:yMWIb/lv69K7Qz6Brv63u6gIACefIPKQSiI2aFXnJxo= cloud.google.com/go/apigeeconnect v1.7.1/go.mod h1:olkn1lOhIA/aorreenFzfEcEXmFN2pyAwkaUFbug9ZY= +cloud.google.com/go/apigeeconnect v1.7.3 h1:Wlr+30Tha0SMCvQYZKdrh+HkpOyl0CQFSlzeY/Gg1gs= +cloud.google.com/go/apigeeconnect v1.7.3/go.mod h1:2ZkT5VCAqhYrDqf4dz7lGp4N/+LeNBSfou8Qs5bIuSg= cloud.google.com/go/apigeeregistry v0.9.1 h1:AfMllcPbJ+qMgbYK2bC5QDPd8SmE8wQ5msiDILuxVm4= cloud.google.com/go/apigeeregistry v0.9.1/go.mod h1:XCwK9CS65ehi26z7E8/Vl4PEX5c/JJxpfxlB1QEyrZw= +cloud.google.com/go/apigeeregistry v0.9.3 h1:j9CJg/oC884OX5cDpiwNt1ZlDXNV6Zb9Mp1YmRrOG0k= +cloud.google.com/go/apigeeregistry v0.9.3/go.mod h1:oNCP2VjOeI6U8yuOuTmU4pkffdcXzR5KxeUD71gF+Dg= cloud.google.com/go/apikeys v0.6.0 h1:B9CdHFZTFjVti89tmyXXrO+7vSNo2jvZuHG8zD5trdQ= cloud.google.com/go/appengine v1.9.1 h1:mQMmn1Dv0DDLsDjYxfS+cVwQa8+ue++ymVeD1jkXze0= cloud.google.com/go/appengine v1.9.1/go.mod h1:jtguveqRWFfjrk3k/7SlJz1FpDBZhu5CWSRu+HBgClk= +cloud.google.com/go/appengine v1.9.3 h1:jrcanSzj9J1erevZuxldvsDwY+0k/DeFFzlnSfPGfL8= +cloud.google.com/go/appengine v1.9.3/go.mod h1:DtLsE/z3JufM/pCEIyVYebJ0h9UNPpN64GZQrYgOSyM= cloud.google.com/go/area120 v0.9.1 h1:YfDWbKHRHmhpd8ejTmAeK6eYi3n0qJKvPNEj1ON19PY= cloud.google.com/go/area120 v0.9.1/go.mod h1:foV1BSrnjVL/KydBnAlUQFSy85kWrMwGSmRfIraC+JU= +cloud.google.com/go/area120 v0.9.3 h1:dPQ07rW4eku8OgNWDOaQaVGcE4+XfhH8BSbVwdVQ+wU= +cloud.google.com/go/area120 v0.9.3/go.mod h1:F3vxS/+hqzrjJo55Xvda3Jznjjbd+4Foo43SN5eMd8M= cloud.google.com/go/artifactregistry v1.15.1 h1:ANE2nBEqP2vGGA/5plRRUpatT3E/3ydSK8Z+lXiV69s= cloud.google.com/go/artifactregistry v1.15.1/go.mod h1:ExJb4VN+IMTQWO5iY+mjcY19Rz9jUxCVGZ1YuyAgPBw= +cloud.google.com/go/artifactregistry v1.16.1 h1:ZNXGB6+T7VmWdf6//VqxLdZ/sk0no8W0ujanHeJwDRw= +cloud.google.com/go/artifactregistry v1.16.1/go.mod h1:sPvFPZhfMavpiongKwfg93EOwJ18Tnj9DIwTU9xWUgs= cloud.google.com/go/asset v1.20.2 h1:wAGSAzAmMC/KEFGZ6Z0zv3jOlz1fjBxuO7SiRX9FMuQ= cloud.google.com/go/asset v1.20.2/go.mod h1:IM1Kpzzo3wq7R/GEiktitzZyXx2zVpWqs9/5EGYs0GY= +cloud.google.com/go/asset v1.20.4 h1:6oNgjcs5KCPGBD71G0IccK6TfeFsEtBTyQ3Q+Dn09bs= +cloud.google.com/go/asset v1.20.4/go.mod h1:DP09pZ+SoFWUZyPZx26xVroHk+6+9umnQv+01yfJxbM= cloud.google.com/go/assuredworkloads v1.12.1 h1:B+hWc62fYL8NdntPjx0rzJJ67qx99w6dCeIVDpHf7QE= cloud.google.com/go/assuredworkloads v1.12.1/go.mod h1:nBnkK2GZNSdtjU3ER75oC5fikub5/+QchbolKgnMI/I= +cloud.google.com/go/assuredworkloads v1.12.3 h1:RU1WhF1zMggdXAZ+ezYTn4Eh/FdiX7sz8lLXGERn4Po= +cloud.google.com/go/assuredworkloads v1.12.3/go.mod h1:iGBkyMGdtlsxhCi4Ys5SeuvIrPTeI6HeuEJt7qJgJT8= +cloud.google.com/go/auth v0.3.0/go.mod h1:lBv6NKTWp8E3LPzmO1TbiiRKc4drLOfHsgmlH9ogv5w= +cloud.google.com/go/auth v0.9.9/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI= +cloud.google.com/go/auth v0.12.1/go.mod h1:BFMu+TNpF3DmvfBO9ClqTR/SiqVIm7LukKF9mbendF4= +cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q= +cloud.google.com/go/auth v0.14.0/go.mod h1:CYsoRL1PdiDuqeQpZE0bP2pnPrGqFcOkI0nldEQis+A= +cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= +cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc= +cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8= cloud.google.com/go/automl v1.14.1 h1:IrNnM7oClTzfFcf5XgaZCGwicETU2aCmrGzE8U2DlVs= cloud.google.com/go/automl v1.14.1/go.mod h1:BocG5mhT32cjmf5CXxVsdSM04VXzJW7chVT7CpSL2kk= +cloud.google.com/go/automl v1.14.4 h1:vkD+hQ75SMINMgJBT/KDpFYvfQLzJbtIQZdw0AWq8Rs= +cloud.google.com/go/automl v1.14.4/go.mod h1:sVfsJ+g46y7QiQXpVs9nZ/h8ntdujHm5xhjHW32b3n4= cloud.google.com/go/baremetalsolution v1.3.1 h1:Zbsrhw8vm4Byki+ynVuACZ6jxYiKzi1f8Hac5zXGD8Y= cloud.google.com/go/baremetalsolution v1.3.1/go.mod h1:D1djGGmBl4M6VlyjOMc1SEzDYlO4EeEG1TCUv5mCPi0= +cloud.google.com/go/baremetalsolution v1.3.3 h1:OL+KT+wCumdDhG44aeqGAdkwdT8Wa4Lh+o4INM+CQjw= +cloud.google.com/go/baremetalsolution v1.3.3/go.mod h1:uF9g08RfmXTF6ZKbXxixy5cGMGFcG6137Z99XjxLOUI= cloud.google.com/go/batch v1.11.1 h1:50TRhaaZv7QDCb60KcZUPkGx1oO46srDp5076wZkgI8= cloud.google.com/go/batch v1.11.1/go.mod h1:4GbJXfdxU8GH6uuo8G47y5tEFOgTLCL9pMKCUcn7VxE= +cloud.google.com/go/batch v1.11.5 h1:TLfFZJXu+89CGbDK2mMql8f6HHFXarr8uUsaQ6wKatU= +cloud.google.com/go/batch v1.11.5/go.mod h1:HUxnmZqnkG7zIZuF3NYCfUIrOMU3+SPArR5XA6NGu5s= cloud.google.com/go/beyondcorp v1.1.1 h1:owviaab14M9ySEvCj3EZdfzkRLnE+5j4JIkqVaQtEUU= cloud.google.com/go/beyondcorp v1.1.1/go.mod h1:L09o0gLkgXMxCZs4qojrgpI2/dhWtasMc71zPPiHMn4= +cloud.google.com/go/beyondcorp v1.1.3 h1:ezavJc0Gzh4N8zBskO/DnUVMWPa8lqH/tmQSyaknmCA= +cloud.google.com/go/beyondcorp v1.1.3/go.mod h1:3SlVKnlczNTSQFuH5SSyLuRd4KaBSc8FH/911TuF/Cc= cloud.google.com/go/bigquery v1.63.1 h1:/6syiWrSpardKNxdvldS5CUTRJX1iIkSPXCjLjiGL+g= cloud.google.com/go/bigquery v1.63.1/go.mod h1:ufaITfroCk17WTqBhMpi8CRjsfHjMX07pDrQaRKKX2o= +cloud.google.com/go/bigquery v1.66.0 h1:cDM3xEUUTf6RDepFEvNZokCysGFYoivHHTIZOWXbV2E= +cloud.google.com/go/bigquery v1.66.0/go.mod h1:Cm1hMRzZ8teV4Nn8KikgP8bT9jd54ivP8fvXWZREmG4= cloud.google.com/go/bigtable v1.33.0 h1:2BDaWLRAwXO14DJL/u8crbV2oUbMZkIa2eGq8Yao1bk= cloud.google.com/go/bigtable v1.33.0/go.mod h1:HtpnH4g25VT1pejHRtInlFPnN5sjTxbQlsYBjh9t5l0= +cloud.google.com/go/bigtable v1.34.0 h1:eIgi3QLcN4aq8p6n9U/zPgmHeBP34sm9FiKq4ik/ZoY= +cloud.google.com/go/bigtable v1.34.0/go.mod h1:p94uLf6cy6D73POkudMagaFF3x9c7ktZjRnOUVGjZAw= cloud.google.com/go/billing v1.19.1 h1:BtbMCM9QDWiszfNXEAcq0MB6vgCuc0/yzP3vye2Kz3U= cloud.google.com/go/billing v1.19.1/go.mod h1:c5l7ORJjOLH/aASJqUqNsEmwrhfjWZYHX+z0fIhuVpo= +cloud.google.com/go/billing v1.20.1 h1:xMlO3hc5BI0s23tRB40bL40xSpxUR1x3E07Y5/VWcjU= +cloud.google.com/go/billing v1.20.1/go.mod h1:DhT80hUZ9gz5UqaxtK/LNoDELfxH73704VTce+JZqrY= cloud.google.com/go/binaryauthorization v1.9.1 h1:fVtOG5rVU0eaVh2G2ORdT7nigsnK1R1JpqfGzW861OM= cloud.google.com/go/binaryauthorization v1.9.1/go.mod h1:jqBzP68bfzjoiMFT6Q1EdZtKJG39zW9ywwzHuv7V8ms= +cloud.google.com/go/binaryauthorization v1.9.3 h1:X8JRfmk0/vyRqLusEyAPr0nZCK6RKae9omB4lrit0XI= +cloud.google.com/go/binaryauthorization v1.9.3/go.mod h1:f3xcb/7vWklDoF+q2EaAIS+/A/e1278IgiYxonRX+Jk= cloud.google.com/go/certificatemanager v1.9.1 h1:fULhIdwsz3SoZfiXw8XaxSJBpRTR0xwsJleO+wEbbKA= cloud.google.com/go/certificatemanager v1.9.1/go.mod h1:a6bXZULtd6iQTRuSVs1fopcHLMJ/T3zSpIB7aJaq/js= +cloud.google.com/go/certificatemanager v1.9.3 h1:2UP31fg7b+y3F0OmNbPHOKPEJ+6LOMfxAXX4p8xGCy4= +cloud.google.com/go/certificatemanager v1.9.3/go.mod h1:O5T4Lg/dHbDHLFFooV2Mh/VsT3Mj2CzPEWRo4qw5prc= cloud.google.com/go/channel v1.19.0 h1:YdCa/Y6lhGVeR058gQGhTunEuR9zVuheukKL+pcldgI= cloud.google.com/go/channel v1.19.0/go.mod h1:8BEvuN5hWL4tT0rmJR4N8xsZHdfGof+KwemjQH6oXsw= +cloud.google.com/go/channel v1.19.2 h1:oHyO3QAZ6kdf6SwqnUTBz50ND6Nk2rxZtboUiF4dgLE= +cloud.google.com/go/channel v1.19.2/go.mod h1:syX5opXGXFt17DHCyCdbdlM464Tx0gHMi46UlEWY9Gg= cloud.google.com/go/cloudbuild v1.18.0 h1:82f6g0AzacK1bbO0E5ZqixWc4nRzWu4ichIQ0QKNtAQ= cloud.google.com/go/cloudbuild v1.18.0/go.mod h1:KCHWGIoS/5fj+By9YmgIQnUiDq8P6YURWOjX3hoc6As= +cloud.google.com/go/cloudbuild v1.20.0 h1:0BRKyrCnWMHlnkwtNKdEwcvpgPm3OA3NqQhzDS5c7ek= +cloud.google.com/go/cloudbuild v1.20.0/go.mod h1:TgSGCsKojPj2JZuYNw5Ur6Pw7oCJ9iK60PuMnaUps7s= cloud.google.com/go/clouddms v1.8.1 h1:vf5R4/FoLHxEP2BBKEafLHfYFWa6Zd9gwrXe/FjrwUg= cloud.google.com/go/clouddms v1.8.1/go.mod h1:bmW2eDFH1LjuwkHcKKeeppcmuBGS0r6Qz6TXanehKP0= +cloud.google.com/go/clouddms v1.8.3 h1:T/rkkKE0KhQFMcO3+QWL82xakA9kRumLXY1lq5adIts= +cloud.google.com/go/clouddms v1.8.3/go.mod h1:wn8O2KhhJWcOlQk0pMC7F/4TaJRS5sN6KdNWM8A7o6c= cloud.google.com/go/cloudtasks v1.13.1 h1:s1JTLBD+WbzQwxYPAwa2WIxPT3kOiv7MSKyvSEgNQtg= cloud.google.com/go/cloudtasks v1.13.1/go.mod h1:dyRD7tEEkLMbHLagb7UugkDa77UVJp9d/6O9lm3ModI= +cloud.google.com/go/cloudtasks v1.13.3 h1:rXdznKjCa7WpzmvR2plrn2KJ+RZC1oYxPiRWNQjjf3k= +cloud.google.com/go/cloudtasks v1.13.3/go.mod h1:f9XRvmuFTm3VhIKzkzLCPyINSU3rjjvFUsFVGR5wi24= +cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= cloud.google.com/go/compute v1.28.1 h1:XwPcZjgMCnU2tkwY10VleUjSAfpTj9RDn+kGrbYsi8o= cloud.google.com/go/compute v1.28.1/go.mod h1:b72iXMY4FucVry3NR3Li4kVyyTvbMDE7x5WsqvxjsYk= +cloud.google.com/go/compute v1.31.1 h1:SObuy8Fs6woazArpXp1fsHCw+ZH4iJ/8dGGTxUhHZQA= +cloud.google.com/go/compute v1.31.1/go.mod h1:hyOponWhXviDptJCJSoEh89XO1cfv616wbwbkde1/+8= cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= cloud.google.com/go/contactcenterinsights v1.15.0 h1:jHwyL2TQTaLauRRz5Uv7/sL7PNAK1VAMy/UIT9vsFzk= cloud.google.com/go/contactcenterinsights v1.15.0/go.mod h1:6bJGBQrJsnATv2s6Dh/c6HCRanq2kCZ0kIIjRV1G0mI= +cloud.google.com/go/contactcenterinsights v1.17.1 h1:xJoZbX0HM1zht8KxAB38hs2v4Hcl+vXGLo454LrdwxA= +cloud.google.com/go/contactcenterinsights v1.17.1/go.mod h1:n8OiNv7buLA2AkGVkfuvtW3HU13AdTmEwAlAu46bfxY= cloud.google.com/go/container v1.40.0 h1:JVoEg/4RvoGW37r2Eja/cTBc3X9c2loGWYq7QDsRDuI= cloud.google.com/go/container v1.40.0/go.mod h1:wNI1mOUivm+ZkpHMbouutgbD4sQxyphMwK31X5cThY4= +cloud.google.com/go/container v1.42.1 h1:eaMrgOl6NCk+Blhh29GgUVe3QGo7IiJQlP0w/EwLoV0= +cloud.google.com/go/container v1.42.1/go.mod h1:5huIxYuOD8Ocuj0KbcyRq9MzB3J1mQObS0KSWHTYceY= cloud.google.com/go/containeranalysis v0.13.1 h1:opZRo0HEVLm4ylTbbXw/H68M3vQjdkYOSMfUY63+D+0= cloud.google.com/go/containeranalysis v0.13.1/go.mod h1:bmd9H880BNR4Hc8JspEg8ge9WccSQfO+/N+CYvU3sEA= +cloud.google.com/go/containeranalysis v0.13.3 h1:1D8U75BeotZxrG4jR6NYBtOt+uAeBsWhpBZmSYLakQw= +cloud.google.com/go/containeranalysis v0.13.3/go.mod h1:0SYnagA1Ivb7qPqKNYPkCtphhkJn3IzgaSp3mj+9XAY= cloud.google.com/go/datacatalog v1.22.1 h1:i0DyKb/o7j+0vgaFtimcRFjYsD6wFw1jpnODYUyiYRs= cloud.google.com/go/datacatalog v1.22.1/go.mod h1:MscnJl9B2lpYlFoxRjicw19kFTwEke8ReKL5Y/6TWg8= +cloud.google.com/go/datacatalog v1.24.3 h1:3bAfstDB6rlHyK0TvqxEwaeOvoN9UgCs2bn03+VXmss= +cloud.google.com/go/datacatalog v1.24.3/go.mod h1:Z4g33XblDxWGHngDzcpfeOU0b1ERlDPTuQoYG6NkF1s= cloud.google.com/go/dataflow v0.10.1 h1:RoVpCZ1BjJBH/5mzaXCgNg+l9FgTIYQ7C9xBRGvhkzo= cloud.google.com/go/dataflow v0.10.1/go.mod h1:zP4/tNjONFRcS4NcI9R94YDQEkPalimdbPkijVNJt/g= +cloud.google.com/go/dataflow v0.10.3 h1:+7IfIXzYWSybIIDGK9FN2uqBsP/5b/Y0pBYzNhcmKSU= +cloud.google.com/go/dataflow v0.10.3/go.mod h1:5EuVGDh5Tg4mDePWXMMGAG6QYAQhLNyzxdNQ0A1FfW4= cloud.google.com/go/dataform v0.10.1 h1:FkOPrxf8sN9J2TMc4CIBhVivhMiO8D0eYN33s5A5Uo4= cloud.google.com/go/dataform v0.10.1/go.mod h1:c5y0hIOBCfszmBcLJyxnELF30gC1qC/NeHdmkzA7TNQ= +cloud.google.com/go/dataform v0.10.3 h1:ZpGkZV8OyhUhvN/tfLffU2ki5ERTtqOunkIaiVAhmw0= +cloud.google.com/go/dataform v0.10.3/go.mod h1:8SruzxHYCxtvG53gXqDZvZCx12BlsUchuV/JQFtyTCw= cloud.google.com/go/datafusion v1.8.1 h1:QqiQs3mSXl4gfeHGOTbK0v1y+tUOnxWJgXm6YWvoqY0= cloud.google.com/go/datafusion v1.8.1/go.mod h1:I5+nRt6Lob4g1eCbcxP4ayRNx8hyOZ8kA3PB/vGd9Lo= +cloud.google.com/go/datafusion v1.8.3 h1:FTMtsf2nfGGlDCuE84/RvVaCcTIYE7WQSB0noeO0cwI= +cloud.google.com/go/datafusion v1.8.3/go.mod h1:hyglMzE57KRf0Rf/N2VRPcHCwKfZAAucx+LATY6Jc6Q= cloud.google.com/go/datalabeling v0.9.1 h1:FrnZKagECxQy1bL+GQ1bjgwK9+szi1l7gqw7zp+Raqs= cloud.google.com/go/datalabeling v0.9.1/go.mod h1:umplHuZX+x5DItNPV5BFBXau5TDsljLNzEj5AB5uRUM= +cloud.google.com/go/datalabeling v0.9.3 h1:PqoA3gnOWaLcHCnqoZe4jh3jmiv6+Z7W2xUUkw/j4jE= +cloud.google.com/go/datalabeling v0.9.3/go.mod h1:3LDFUgOx+EuNUzDyjU7VElO8L+b5LeaZEFA/ZU1O1XU= cloud.google.com/go/dataplex v1.19.1 h1:0pgI0DwijXZq8vyLuGnQXSi9JB6eUaVqzpzhN2veUeE= cloud.google.com/go/dataplex v1.19.1/go.mod h1:WzoQ+vcxrAyM0cjJWmluEDVsg7W88IXXCfuy01BslKE= +cloud.google.com/go/dataplex v1.21.0 h1:oswf105Cr2EwHrW2n7wk3nRZQf7hCe3apE/GqJ8yjvY= +cloud.google.com/go/dataplex v1.21.0/go.mod h1:KXALVHwHdMBhz90IJAUSKh2gK0fEKB6CRjs4f6MrbMU= cloud.google.com/go/dataproc v1.12.0 h1:W47qHL3W4BPkAIbk4SWmIERwsWBaNnWm0P2sdx3YgGU= cloud.google.com/go/dataproc/v2 v2.9.0 h1:9fSMjWgFKQfmfKu7V10C5foxU/2iDa8bVkiBB8uh1EU= cloud.google.com/go/dataproc/v2 v2.9.0/go.mod h1:i4365hSwNP6Bx0SAUnzCC6VloeNxChDjJWH6BfVPcbs= +cloud.google.com/go/dataproc/v2 v2.10.1 h1:2vOv471LrcSn91VNzijcH+OkDRLa3kdyymOfKqbwZ4c= +cloud.google.com/go/dataproc/v2 v2.10.1/go.mod h1:fq+LSN/HYUaaV2EnUPFVPxfe1XpzGVqFnL0TTXs8juk= cloud.google.com/go/dataqna v0.9.1 h1:ptKKT+CNwp9Q+9Zxr+npUO7qUwKfyq/oF7/nS7CC6sc= cloud.google.com/go/dataqna v0.9.1/go.mod h1:86DNLE33yEfNDp5F2nrITsmTYubMbsF7zQRzC3CcZrY= +cloud.google.com/go/dataqna v0.9.3 h1:lGUj2FYs650EUPDMV6plWBAoh8qH9Bu1KCz1PUYF2VY= +cloud.google.com/go/dataqna v0.9.3/go.mod h1:PiAfkXxa2LZYxMnOWVYWz3KgY7txdFg9HEMQPb4u1JA= cloud.google.com/go/datastore v1.19.0 h1:p5H3bUQltOa26GcMRAxPoNwoqGkq5v8ftx9/ZBB35MI= cloud.google.com/go/datastore v1.19.0/go.mod h1:KGzkszuj87VT8tJe67GuB+qLolfsOt6bZq/KFuWaahc= +cloud.google.com/go/datastore v1.20.0 h1:NNpXoyEqIJmZFc0ACcwBEaXnmscUpcG4NkKnbCePmiM= +cloud.google.com/go/datastore v1.20.0/go.mod h1:uFo3e+aEpRfHgtp5pp0+6M0o147KoPaYNaPAKpfh8Ew= cloud.google.com/go/datastream v1.11.1 h1:YKY2qGKoxPpAvsDMtmJlIwL59SzhEm1DHM2uM4ib0TY= cloud.google.com/go/datastream v1.11.1/go.mod h1:a4j5tnptIxdZ132XboR6uQM/ZHcuv/hLqA6hH3NJWgk= +cloud.google.com/go/datastream v1.12.1 h1:j5cIRYJHjx/058aHa4Slip7fl62UTGHCJc4GL9bxQLQ= +cloud.google.com/go/datastream v1.12.1/go.mod h1:GxPeRBsokZ8ylxVJBp9Q39QG+z4Iri5QIBRJrKuzJVQ= cloud.google.com/go/deploy v1.23.0 h1:Bmh5UYEeakXtjggRkjVIawXfSBbQsTgDlm96pCw9D3k= cloud.google.com/go/deploy v1.23.0/go.mod h1:O7qoXcg44Ebfv9YIoFEgYjPmrlPsXD4boYSVEiTqdHY= +cloud.google.com/go/deploy v1.26.1 h1:Hm3pXBzMFJFPOdwtDkg5e/LP53bXqIpwQpjwsVasjhU= +cloud.google.com/go/deploy v1.26.1/go.mod h1:PwF9RP0Jh30Qd+I71wb52oM42LgfRKXRMSg87wKpK3I= cloud.google.com/go/dialogflow v1.58.0 h1:RTpoVCJHkgNLK8Co/f7F8ipyg3h8fJIaQzdaAbyg788= cloud.google.com/go/dialogflow v1.58.0/go.mod h1:sWcyFLdUrg+TWBJVq/OtwDyjcyDOfirTF0Gx12uKy7o= +cloud.google.com/go/dialogflow v1.64.1 h1:6fU4IKLpvgpXqiUCE8gUp8eV5u629SCtiyXMudXtZSg= +cloud.google.com/go/dialogflow v1.64.1/go.mod h1:jkv4vTiGhEUPBzmk1sJ+S1Duu2epCOBNHoWUImHkO5U= cloud.google.com/go/dlp v1.19.0 h1:AJB26PpDG0gOkf6wxQqbBXs9G+jOVnCjCagOlNiroKM= cloud.google.com/go/dlp v1.19.0/go.mod h1:cr8dKBq8un5LALiyGkz4ozcwzt3FyTlOwA4/fFzJ64c= +cloud.google.com/go/dlp v1.20.1 h1:qAEGTTtC97zuDm6YPBozNvy4BLBszVCJah3efNytl3g= +cloud.google.com/go/dlp v1.20.1/go.mod h1:NO0PLy43RQV0QI6vZcPiNTR9eiKu9pFzawaueBlDwz8= cloud.google.com/go/documentai v1.34.0 h1:gmBmrTLzbpZkllu2xExISZg2Hh/ai0y605SWdheWHvI= cloud.google.com/go/documentai v1.34.0/go.mod h1:onJlbHi4ZjQTsANSZJvW7fi2M8LZJrrupXkWDcy4gLY= +cloud.google.com/go/documentai v1.35.1 h1:52RfiUsoblXcE57CfKJGnITWLxRM30BcqNk/BKZl2LI= +cloud.google.com/go/documentai v1.35.1/go.mod h1:WJjwUAQfwQPJORW8fjz7RODprMULDzEGLA2E6WxenFw= cloud.google.com/go/domains v0.10.1 h1:HvZOm7Bx1fQY/MHQAbE5f8YwfJlc0NJVOGh0A0eWckc= cloud.google.com/go/domains v0.10.1/go.mod h1:RjDl3K8iq/ZZHMVqfZzRuBUr5t85gqA6LEXQBeBL5F4= +cloud.google.com/go/domains v0.10.3 h1:wnqN5YwMrtLSjn+HB2sChgmZ6iocOta4Q41giQsiRjY= +cloud.google.com/go/domains v0.10.3/go.mod h1:m7sLe18p0PQab56bVH3JATYOJqyRHhmbye6gz7isC7o= cloud.google.com/go/edgecontainer v1.3.1 h1:loDGWu/sdqnCP3Xlvj4OWHL7i0wocbcLg8ApQ9BE66E= cloud.google.com/go/edgecontainer v1.3.1/go.mod h1:qyz5+Nk/UAs6kXp6wiux9I2U4A2R624K15QhHYovKKM= +cloud.google.com/go/edgecontainer v1.4.1 h1:SwQuHQiheVfL7b5ar/AXDberiaqr/yiue8X55AdWnZU= +cloud.google.com/go/edgecontainer v1.4.1/go.mod h1:ubMQvXSxsvtEjJLyqcPFrdWrHfvjQxdoyt+SUrAi5ek= cloud.google.com/go/errorreporting v0.3.1 h1:E/gLk+rL7u5JZB9oq72iL1bnhVlLrnfslrgcptjJEUE= cloud.google.com/go/errorreporting v0.3.1/go.mod h1:6xVQXU1UuntfAf+bVkFk6nld41+CPyF2NSPCyXE3Ztk= +cloud.google.com/go/errorreporting v0.3.2 h1:isaoPwWX8kbAOea4qahcmttoS79+gQhvKsfg5L5AgH8= +cloud.google.com/go/errorreporting v0.3.2/go.mod h1:s5kjs5r3l6A8UUyIsgvAhGq6tkqyBCUss0FRpsoVTww= cloud.google.com/go/essentialcontacts v1.7.1 h1:qeZAOxqWFfD7sDd1vKYaNhjGh1eckkCkSJyx/OC5egE= cloud.google.com/go/essentialcontacts v1.7.1/go.mod h1:F/MMWNLRW7b42WwWklOsnx4zrMOWDYWqWykBf1jXKPY= +cloud.google.com/go/essentialcontacts v1.7.3 h1:Paw495vxVyKuAgcQ2NQk09iRZBhPYRytknydEnvzcv4= +cloud.google.com/go/essentialcontacts v1.7.3/go.mod h1:uimfZgDbhWNCmBpwUUPHe4vcMY2azsq/axC9f7vZFKI= cloud.google.com/go/eventarc v1.14.1 h1:Tw1DsE1OO9NZ3LZlAtxsi4otVl5qjQ3Y3QD9dCxtAyo= cloud.google.com/go/eventarc v1.14.1/go.mod h1:NG0YicE+z9MDcmh2u4tlzLDVLRjq5UHZlibyQlPhcxY= +cloud.google.com/go/eventarc v1.15.1 h1:RMymT7R87LaxKugOKwooOoheWXUm1NMeOfh3CVU9g54= +cloud.google.com/go/eventarc v1.15.1/go.mod h1:K2luolBpwaVOujZQyx6wdG4n2Xum4t0q1cMBmY1xVyI= cloud.google.com/go/filestore v1.9.1 h1:s8DPPSV80FzIB7rduoMJAgknktms9hZGE3+X9KFUlK8= cloud.google.com/go/filestore v1.9.1/go.mod h1:g/FNHBABpxjL1M9nNo0nW6vLYIMVlyOKhBKtYGgcKUI= +cloud.google.com/go/filestore v1.9.3 h1:vTXQI5qYKZ8dmCyHN+zVfaMyXCYbyZNM0CkPzpPUn7Q= +cloud.google.com/go/filestore v1.9.3/go.mod h1:Me0ZRT5JngT/aZPIKpIK6N4JGMzrFHRtGHd9ayUS4R4= cloud.google.com/go/firestore v1.17.0 h1:iEd1LBbkDZTFsLw3sTH50eyg4qe8eoG6CjocmEXO9aQ= cloud.google.com/go/firestore v1.17.0/go.mod h1:69uPx1papBsY8ZETooc71fOhoKkD70Q1DwMrtKuOT/Y= +cloud.google.com/go/firestore v1.18.0 h1:cuydCaLS7Vl2SatAeivXyhbhDEIR8BDmtn4egDhIn2s= +cloud.google.com/go/firestore v1.18.0/go.mod h1:5ye0v48PhseZBdcl0qbl3uttu7FIEwEYVaWm0UIEOEU= cloud.google.com/go/functions v1.19.1 h1:eWjTZohtJX/9rckZYXaYVViGi06JkNJRKvm0aO+ce+g= cloud.google.com/go/functions v1.19.1/go.mod h1:18RszySpwRg6aH5UTTVsRfdCwDooSf/5mvSnU7NAk4A= +cloud.google.com/go/functions v1.19.3 h1:V0vCHSgFTUqKn57+PUXp1UfQY0/aMkveAw7wXeM3Lq0= +cloud.google.com/go/functions v1.19.3/go.mod h1:nOZ34tGWMmwfiSJjoH/16+Ko5106x+1Iji29wzrBeOo= cloud.google.com/go/gaming v1.9.0 h1:7vEhFnZmd931Mo7sZ6pJy7uQPDxF7m7v8xtBheG08tc= cloud.google.com/go/gkebackup v1.6.1 h1:bV1go067LF5XaobFXXvgW2rsuvR974ajirDjD9oXFWg= cloud.google.com/go/gkebackup v1.6.1/go.mod h1:CEnHQCsNBn+cyxcxci0qbAPYe8CkivNEitG/VAZ08ms= +cloud.google.com/go/gkebackup v1.6.3 h1:djdExe/QgoKdp1gnIO1G5BoO1o/yGQOQJJEZ4QKTEXQ= +cloud.google.com/go/gkebackup v1.6.3/go.mod h1:JJzGsA8/suXpTDtqI7n9RZW97PXa2CIp+n8aRC/y57k= cloud.google.com/go/gkeconnect v0.11.1 h1:X7UpDP2Qg8JfaQ6vsJeFsTo4NcrGprk9Tg4Pf7MK8Qg= cloud.google.com/go/gkeconnect v0.11.1/go.mod h1:Vu3UoOI2c0amGyv4dT/EmltzscPH41pzS4AXPqQLej0= +cloud.google.com/go/gkeconnect v0.12.1 h1:YVpR0vlHSP/wD74PXEbKua4Aamud+wiYm4TiewNjD3M= +cloud.google.com/go/gkeconnect v0.12.1/go.mod h1:L1dhGY8LjINmWfR30vneozonQKRSIi5DWGIHjOqo58A= cloud.google.com/go/gkehub v0.15.1 h1:VMXUz3q9Vfhe+dtSjb/yqmiDmGbcEUTuXDyk0pj2GyU= cloud.google.com/go/gkehub v0.15.1/go.mod h1:cyUwa9iFQYd/pI7IQYl6A+OF6M8uIbhmJr090v9Z4UU= +cloud.google.com/go/gkehub v0.15.3 h1:yZ6lNJ9rNIoQmWrG14dB3+BFjS/EIRBf7Bo6jc5QWlE= +cloud.google.com/go/gkehub v0.15.3/go.mod h1:nzFT/Q+4HdQES/F+FP1QACEEWR9Hd+Sh00qgiH636cU= cloud.google.com/go/gkemulticloud v1.4.0 h1:t2HXXYrICui+rZXScietjU1YdrQDLXpfqqrTo7zWSYQ= cloud.google.com/go/gkemulticloud v1.4.0/go.mod h1:rg8YOQdRKEtMimsiNCzZUP74bOwImhLRv9wQ0FwBUP4= +cloud.google.com/go/gkemulticloud v1.5.1 h1:JWe6PDNpNU88ZYvQkTd7w28fgeIs/gg6i0hcjUkgZ3M= +cloud.google.com/go/gkemulticloud v1.5.1/go.mod h1:OdmhfSPXuJ0Kn9dQ2I3Ou7XZ3QK8caV4XVOJZwrIa3s= cloud.google.com/go/grafeas v0.3.10 h1:D9uP/DjVHq9ZzCekVd+aNvQEHb3Hkwp8ki9FDnhRRJ0= cloud.google.com/go/grafeas v0.3.10/go.mod h1:Mz/AoXmxNhj74VW0fz5Idc3kMN2VZMi4UT5+UPx5Pq0= +cloud.google.com/go/grafeas v0.3.11 h1:CobnwnyeY1j1Defi5vbEircI+jfrk3ci5m004ZjiFP4= +cloud.google.com/go/grafeas v0.3.11/go.mod h1:dcQyG2+T4tBgG0MvJAh7g2wl/xHV2w+RZIqivwuLjNg= cloud.google.com/go/gsuiteaddons v1.7.1 h1:YLh58kzaK+1Q/CHe8Cjp3hf9ZjNdJkQMavjrJUDgi9o= cloud.google.com/go/gsuiteaddons v1.7.1/go.mod h1:SxM63xEPFf0p/plgh4dP82mBSKtp2RWskz5DpVo9jh8= +cloud.google.com/go/gsuiteaddons v1.7.3 h1:QafYhVhyFGpidBUUlVhy6lUHFogFOycVYm9DV7MinhA= +cloud.google.com/go/gsuiteaddons v1.7.3/go.mod h1:0rR+LC21v1Sx1Yb6uohHI/F8DF3h2arSJSHvfi3GmyQ= +cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= +cloud.google.com/go/iam v1.2.2/go.mod h1:0Ys8ccaZHdI1dEUilwzqng/6ps2YB6vRsjIe00/+6JY= cloud.google.com/go/iap v1.10.1 h1:YF4jmMwEWXYrbfZZz024ozBXnWxUxJHzmkM6ccIzM0A= cloud.google.com/go/iap v1.10.1/go.mod h1:UKetCEzOZ4Zj7l9TSN/wzRNwbgIYzm4VM4bStaQ/tFc= +cloud.google.com/go/iap v1.10.3 h1:OWNYFHPyIBNHEAEFdVKOltYWe0g3izSrpFJW6Iidovk= +cloud.google.com/go/iap v1.10.3/go.mod h1:xKgn7bocMuCFYhzRizRWP635E2LNPnIXT7DW0TlyPJ8= cloud.google.com/go/ids v1.5.1 h1:UkHpZnlW46WulDVNtzKN+SEntZoOoHoG/Ob1GtuVCGQ= cloud.google.com/go/ids v1.5.1/go.mod h1:d/9jTtY506mTxw/nHH3UN4TFo80jhAX+tESwzj42yFo= +cloud.google.com/go/ids v1.5.3 h1:wbFF7twu0XScFr+dtsVxTTttbFIRYt/SJjZiHFidtYE= +cloud.google.com/go/ids v1.5.3/go.mod h1:a2MX8g18Eqs7yxD/pnEdid42SyBUm9LIzSWf8Jux9OY= cloud.google.com/go/iot v1.8.1 h1:PySjOJ2Nni1IDk0LqcNhUCKOGe0yPP4rM/Nc5yA/cjI= cloud.google.com/go/iot v1.8.1/go.mod h1:FNceQ9/EGvbE2az7RGoGPY0aqrsyJO3/LqAL0h83fZw= +cloud.google.com/go/iot v1.8.3 h1:aPWYQ+A1NX6ou/5U0nFAiXWdVT8OBxZYVZt2fBl2gWA= +cloud.google.com/go/iot v1.8.3/go.mod h1:dYhrZh+vUxIQ9m3uajyKRSW7moF/n0rYmA2PhYAkMFE= cloud.google.com/go/language v1.14.1 h1:lyBks2W2k7bVPvfEECH08eMOP3Vd7zkHCATt/Vy0sLM= cloud.google.com/go/language v1.14.1/go.mod h1:WaAL5ZdLLBjiorXl/8vqgb6/Fyt2qijl96c1ZP/vdc8= +cloud.google.com/go/language v1.14.3 h1:8hmFMiS3wjjj3TX/U1zZYTgzwZoUjDbo9PaqcYEmuB4= +cloud.google.com/go/language v1.14.3/go.mod h1:hjamj+KH//QzF561ZuU2J+82DdMlFUjmiGVWpovGGSA= cloud.google.com/go/lifesciences v0.10.1 h1:sGTR+IW9I85VhP789GMHNYOyCo7dkmvWRYh0uOfmWdo= cloud.google.com/go/lifesciences v0.10.1/go.mod h1:5D6va5/Gq3gtJPKSsE6vXayAigfOXK2eWLTdFUOTCDs= +cloud.google.com/go/lifesciences v0.10.3 h1:Z05C+Ui953f0EQx9hJ1la6+QQl8ADrIs3iNwP5Elkpg= +cloud.google.com/go/lifesciences v0.10.3/go.mod h1:hnUUFht+KcZcliixAg+iOh88FUwAzDQQt5tWd7iIpNg= cloud.google.com/go/logging v1.12.0 h1:ex1igYcGFd4S/RZWOCU51StlIEuey5bjqwH9ZYjHibk= cloud.google.com/go/logging v1.12.0/go.mod h1:wwYBt5HlYP1InnrtYI0wtwttpVU1rifnMT7RejksUAM= +cloud.google.com/go/longrunning v0.5.6/go.mod h1:vUaDrWYOMKRuhiv6JBnn49YxCPz2Ayn9GqyjaBT8/mA= +cloud.google.com/go/longrunning v0.6.2/go.mod h1:k/vIs83RN4bE3YCswdXC5PFfWVILjm3hpEUlSko4PiI= cloud.google.com/go/managedidentities v1.7.1 h1:9hC4E7JnWn/jSUls022Sj9ri+vriGnLzvDXo0cs1zcA= cloud.google.com/go/managedidentities v1.7.1/go.mod h1:iK4qqIBOOfePt5cJR/Uo3+uol6oAVIbbG7MGy917cYM= +cloud.google.com/go/managedidentities v1.7.3 h1:b9xGs24BIjfyvLgCtJoClOZpPi8d8owPgWe5JEINgaY= +cloud.google.com/go/managedidentities v1.7.3/go.mod h1:H9hO2aMkjlpY+CNnKWRh+WoQiUIDO8457wWzUGsdtLA= cloud.google.com/go/maps v1.14.0 h1:bLT2nvuOm4ye6YRgIJQ0L9zbKcbBj+TCg8k2g3c2Qlk= cloud.google.com/go/maps v1.14.0/go.mod h1:UepOes9un0UP7i8JBiaqgh8jqUaZAHVRXCYjrVlhSC8= +cloud.google.com/go/maps v1.17.1 h1:u7U/DieTxYYMDyvHQ00la5ayXLjDImTfnhdAsyPZXyY= +cloud.google.com/go/maps v1.17.1/go.mod h1:lGZCm2ILmN06GQyrRQwA1rScqQZuApQsCTX+0v+bdm8= cloud.google.com/go/mediatranslation v0.9.1 h1:7X1cA4TWO0+r1RT0JTT0RE+SyO41eoFUmBDw17Oi9T8= cloud.google.com/go/mediatranslation v0.9.1/go.mod h1:vQH1amULNhSGryBjbjLb37g54rxrOwVxywS8WvUCsIU= +cloud.google.com/go/mediatranslation v0.9.3 h1:nRBjeaMLipw05Br+qDAlSCcCQAAlat4mvpafztbEVgc= +cloud.google.com/go/mediatranslation v0.9.3/go.mod h1:KTrFV0dh7duYKDjmuzjM++2Wn6yw/I5sjZQVV5k3BAA= cloud.google.com/go/memcache v1.11.1 h1:2FGuyd3WY7buNDAkMBdmeIOheNWA3gwaXrttLrEdabI= cloud.google.com/go/memcache v1.11.1/go.mod h1:3zF+dEqmEmElHuO4NtHiShekQY5okQtssjPBv7jpmZ8= +cloud.google.com/go/memcache v1.11.3 h1:XH/qT3GbbSH//R0JTqR77lRpBxaa0N9sHgAzfwbTrv0= +cloud.google.com/go/memcache v1.11.3/go.mod h1:UeWI9cmY7hvjU1EU6dwJcQb6EFG4GaM3KNXOO2OFsbI= cloud.google.com/go/metastore v1.14.1 h1:kGx+IUSSYCVn8LisCT4fpxCC9rauEVonzi7RlygdqWY= cloud.google.com/go/metastore v1.14.1/go.mod h1:WDvsAcbQLl9M4xL+eIpbKogH7aEaPWMhO9aRBcFOnJE= +cloud.google.com/go/metastore v1.14.3 h1:jDqeCw6NGDRAPT9+2Y/EjnWAB0BfCcUfmPLOyhB0eHs= +cloud.google.com/go/metastore v1.14.3/go.mod h1:HlbGVOvg0ubBLVFRk3Otj3gtuzInuzO/TImOBwsKlG4= +cloud.google.com/go/monitoring v1.21.1/go.mod h1:Rj++LKrlht9uBi8+Eb530dIrzG/cU/lB8mt+lbeFK1c= +cloud.google.com/go/monitoring v1.21.2/go.mod h1:hS3pXvaG8KgWTSz+dAdyzPrGUYmi2Q+WFX8g2hqVEZU= cloud.google.com/go/networkconnectivity v1.15.1 h1:EizN+cFGHzRAyiFTK8jT1PqTo+cSnbc2IGh6OmllS7Y= cloud.google.com/go/networkconnectivity v1.15.1/go.mod h1:tYAcT4Ahvq+BiePXL/slYipf/8FF0oNJw3MqFhBnSPI= +cloud.google.com/go/networkconnectivity v1.16.1 h1:YsVhG71ZC4FkqCP2oCI55x/JeGFyd7738Lt8iNTrzJw= +cloud.google.com/go/networkconnectivity v1.16.1/go.mod h1:GBC1iOLkblcnhcnfRV92j4KzqGBrEI6tT7LP52nZCTk= cloud.google.com/go/networkmanagement v1.14.1 h1:0x3hVI6xbp3N/choffKPHMSxbzaPdHSD92cBElebXEk= cloud.google.com/go/networkmanagement v1.14.1/go.mod h1:3Ds8FZ3ZHjTVEedsBoZi9ef9haTE14iS6swTSqM39SI= +cloud.google.com/go/networkmanagement v1.18.0 h1:oEoFGPYxTBsY47h0zdoE2ojV5aU/541D83UmxfjHWaE= +cloud.google.com/go/networkmanagement v1.18.0/go.mod h1:yTxpAFuvQOOKgL3W7+k2Rp1bSKTxyRcZ5xNHGdHUM6w= cloud.google.com/go/networksecurity v0.10.1 h1:dHN1la6xnta3E4QtWGqtc8ZAPKIZH5m8UQceIIuXZIs= cloud.google.com/go/networksecurity v0.10.1/go.mod h1:tatO1hYJ9nNChLHOFdsjex5FeqZBlPQgKdKOex7REpU= +cloud.google.com/go/networksecurity v0.10.3 h1:JLJBFbxc8D7/OS81MyRoKhc2OvnVJxy5VMoQqqAhA7k= +cloud.google.com/go/networksecurity v0.10.3/go.mod h1:G85ABVcPscEgpw+gcu+HUxNZJWjn3yhTqEU7+SsltFM= cloud.google.com/go/notebooks v1.12.1 h1:0g61C2qdWcq2p8OFH3NiLzyneS1LFfsveC5+MnpM4p8= cloud.google.com/go/notebooks v1.12.1/go.mod h1:RJCyRkLjj8UnvLEKaDl9S6//xUCa+r+d/AsxZnYBl50= +cloud.google.com/go/notebooks v1.12.3 h1:+9DrGJcZhCu6B2t0JJorekjIUBvg/KvBmXJYGmfvVvA= +cloud.google.com/go/notebooks v1.12.3/go.mod h1:I0pMxZct+8Rega2LYrXL8jGAGZgLchSmh8Ksc+0xNyA= cloud.google.com/go/optimization v1.7.1 h1:E3/1qRZvGxqQpapaac/EKuzusxUauXLnpirWWXXzP5k= cloud.google.com/go/optimization v1.7.1/go.mod h1:s2AjwwQEv6uExFmgS4Bf1gidI07w7jCzvvs8exqR1yk= +cloud.google.com/go/optimization v1.7.3 h1:JwQjjoBZJpsoMQe/3mhVBMVZuSdagHg2pGOnwh2Jk+E= +cloud.google.com/go/optimization v1.7.3/go.mod h1:GlYFp4Mju0ybK5FlOUtV6zvWC00TIScdbsPyF6Iv144= cloud.google.com/go/orchestration v1.11.0 h1:yyi0kM47UZaJ3EEFYsBwfrkvqyPmvHwsoc3asxDmLuo= cloud.google.com/go/orchestration v1.11.0/go.mod h1:s3L89jinQaUHclqgWYw8JhBbzGSidVt5rVBxGrXeheI= +cloud.google.com/go/orchestration v1.11.4 h1:SFAsKyqvtS8VFcsq+JgXAeRkrksB9UH+AH7iFamkmlc= +cloud.google.com/go/orchestration v1.11.4/go.mod h1:UKR2JwogaZmDGnAcBgAQgCPn89QMqhXFUCYVhHd31vs= cloud.google.com/go/orgpolicy v1.14.0 h1:UuLmi1+94lIS3tCoeuinuwx4oxdx58nECiAvfwCW0SM= cloud.google.com/go/orgpolicy v1.14.0/go.mod h1:S6Pveh1JOxpSbs6+2ToJG7h3HwqC6Uf1YQ6JYG7wdM8= +cloud.google.com/go/orgpolicy v1.14.2 h1:WFvgmjq/FO5GiXlhebltA9N14KdbLMcgG88ME+SWeBo= +cloud.google.com/go/orgpolicy v1.14.2/go.mod h1:2fTDMT3X048iFKxc6DEgkG+a/gN+68qEgtPrHItKMzo= cloud.google.com/go/osconfig v1.14.1 h1:67ISL0vZVfq0se+1cPRMYgwTjsES2k9vmSmn8ZS0O5g= cloud.google.com/go/osconfig v1.14.1/go.mod h1:Rk62nyQscgy8x4bICaTn0iWiip5EpwEfG2UCBa2TP/s= +cloud.google.com/go/osconfig v1.14.3 h1:cyf1PMK5c2/WOIr5r2lxjH/XBJMA9P4zC8Tm10i0z3M= +cloud.google.com/go/osconfig v1.14.3/go.mod h1:9D2MS1Etne18r/mAeW5jtto3toc9H1qu9wLNDG3NvQg= cloud.google.com/go/oslogin v1.14.1 h1:HPPg7FWPwt7pKrbl+8VFI9UuJTbVrG2rSMHl4HkDAG4= cloud.google.com/go/oslogin v1.14.1/go.mod h1:mM/isJYnohyD3EfM12Fhy8uye46gxA1WjHRCwbkmlVw= +cloud.google.com/go/oslogin v1.14.3 h1:yomxnFPk+ye0zd0mJ15nn9fH4Ns7ex4xA3ll+u2q59A= +cloud.google.com/go/oslogin v1.14.3/go.mod h1:fDEGODTG/W9ZGUTHTlMh8euXWC1fTcgjJ9Kcxxy14a8= cloud.google.com/go/phishingprotection v0.9.1 h1:oUEGd4dttG5gIUmICdCh8A1U9iVQiw0TGwvYIGQ2I7U= cloud.google.com/go/phishingprotection v0.9.1/go.mod h1:LRiflQnCpYKCMhsmhNB3hDbW+AzQIojXYr6q5+5eRQk= +cloud.google.com/go/phishingprotection v0.9.3 h1:T5mGFV0ggBKg3qt9myFRiGJu+nIUucuHLAtVpAuQ08I= +cloud.google.com/go/phishingprotection v0.9.3/go.mod h1:ylzN9HruB/X7dD50I4sk+FfYzuPx9fm5JWsYI0t7ncc= cloud.google.com/go/policytroubleshooter v1.11.1 h1:/b3wruB/KvmCpy9Jfducc8TQmM3bsoPaeCs5z7TRodA= cloud.google.com/go/policytroubleshooter v1.11.1/go.mod h1:9nJIpgQ2vloJbB8y1JkPL5vxtaSdJnJYPCUvt6PpfRs= +cloud.google.com/go/policytroubleshooter v1.11.3 h1:ekIWI8JbKkpOfrgH/THGamQE/D16tcVBYJyrkseVcYI= +cloud.google.com/go/policytroubleshooter v1.11.3/go.mod h1:AFHlORqh4AnMC0twc2yPKfzlozp3DO0yo9OfOd9aNOs= cloud.google.com/go/privatecatalog v0.10.1 h1:Ew51FHLLQsUYUDJY57eMB/mVUOoWLIji957MRw4kumw= cloud.google.com/go/privatecatalog v0.10.1/go.mod h1:mFmn5bjE9J8MEjQuu1fOc4AxOP2MoEwDLMJk04xqQCQ= +cloud.google.com/go/privatecatalog v0.10.4 h1:fu2LABMi7CgZORQ2oNGbc0hoZ0FTqLkjGqIgAV/Kc7U= +cloud.google.com/go/privatecatalog v0.10.4/go.mod h1:n/vXBT+Wq8B4nSRUJNDsmqla5BYjbVxOlHzS6PjiF+w= cloud.google.com/go/pubsub v1.44.0 h1:pLaMJVDTlnUDIKT5L0k53YyLszfBbGoUBo/IqDK/fEI= cloud.google.com/go/pubsub v1.44.0/go.mod h1:BD4a/kmE8OePyHoa1qAHEw1rMzXX+Pc8Se54T/8mc3I= +cloud.google.com/go/pubsub v1.45.3 h1:prYj8EEAAAwkp6WNoGTE4ahe0DgHoyJd5Pbop931zow= +cloud.google.com/go/pubsub v1.45.3/go.mod h1:cGyloK/hXC4at7smAtxFnXprKEFTqmMXNNd9w+bd94Q= cloud.google.com/go/pubsublite v1.8.2 h1:jLQozsEVr+c6tOU13vDugtnaBSUy/PD5zK6mhm+uF1Y= cloud.google.com/go/pubsublite v1.8.2/go.mod h1:4r8GSa9NznExjuLPEJlF1VjOPOpgf3IT6k8x/YgaOPI= cloud.google.com/go/recaptchaenterprise v1.3.1 h1:u6EznTGzIdsyOsvm+Xkw0aSuKFXQlyjGE9a4exk6iNQ= cloud.google.com/go/recaptchaenterprise/v2 v2.17.2 h1:tHFLYu+8w0jjjGf63D4qgVEKS9R3lw4XP4Q1P4df2g8= cloud.google.com/go/recaptchaenterprise/v2 v2.17.2/go.mod h1:iigNZOnUpf++xlm8RdMZJTX/PihYVMrHidRLjHuekec= +cloud.google.com/go/recaptchaenterprise/v2 v2.19.4 h1:T5YGzaXwTesHaPDNTAuU3neDwZEnfjce70zufPFUwno= +cloud.google.com/go/recaptchaenterprise/v2 v2.19.4/go.mod h1:WaglfocMJGkqZVdXY/FVB7OhoVRONPS4uXqtNn6HfX0= cloud.google.com/go/recommendationengine v0.9.1 h1:TQne3UMow6joFVRtTpd9kDYyYr3Jkpq+o0vJkpQgZYI= cloud.google.com/go/recommendationengine v0.9.1/go.mod h1:FfWa3OnsnDab4unvTZM2VJmvoeGn1tnntF3n+vmfyzU= +cloud.google.com/go/recommendationengine v0.9.3 h1:kBpcYPx4ys4lrDGKp4OhP2uy8h7UjlmLW/qoO5Xb2bY= +cloud.google.com/go/recommendationengine v0.9.3/go.mod h1:QRnX5aM7DCvtqtSs7I0zay5Zfq3fzxqnsPbZF7pa1G8= cloud.google.com/go/recommender v1.13.1 h1:aQIUpMynK1pU1Q+EiuL7VJssLLjLwnfhL7px0vgM6xA= cloud.google.com/go/recommender v1.13.1/go.mod h1:l+n8rNMC6jZacckzLvVG/2LzKawlwAJYNO8Vl2pBlxc= +cloud.google.com/go/recommender v1.13.3 h1:dVlOjxsbjuhlwu4MIcyPWe09qVcDqc419iOjdPl5RHk= +cloud.google.com/go/recommender v1.13.3/go.mod h1:6yAmcfqJRKglZrVuTHsieTFEm4ai9JtY3nQzmX4TC0Q= cloud.google.com/go/redis v1.17.1 h1:E7TeGsvyoFB+m59bqFKrQ5GSH7+uW8cUDk6Y7iqGjJ0= cloud.google.com/go/redis v1.17.1/go.mod h1:YJHeYfSoW/agIMeCvM5rszxu75mVh5DOhbu3AEZEIQM= +cloud.google.com/go/redis v1.17.3 h1:ROQXi5dCDSJCVezt/2nD1g+Ym0T6sio3DIzZ56NgMZI= +cloud.google.com/go/redis v1.17.3/go.mod h1:23OoThXAU5bvhg4/oKsEcdVfq3wmyTEPNA9FP/t9xGo= cloud.google.com/go/resourcemanager v1.10.1 h1:fO/QoSJ1lepmTM9dCbSXYWgTIhecmQkpY0mM1X9OGN0= cloud.google.com/go/resourcemanager v1.10.1/go.mod h1:A/ANV/Sv7y7fcjd4LSH7PJGTZcWRkO/69yN5UhYUmvE= +cloud.google.com/go/resourcemanager v1.10.3 h1:SHOMw0kX0xWratC5Vb5VULBeWiGlPYAs82kiZqNtWpM= +cloud.google.com/go/resourcemanager v1.10.3/go.mod h1:JSQDy1JA3K7wtaFH23FBGld4dMtzqCoOpwY55XYR8gs= cloud.google.com/go/resourcesettings v1.8.1 h1:whJgmR9I5V9TSZiaoCPVDgbYD1jghYoauHVfBG8TvHI= cloud.google.com/go/resourcesettings v1.8.1/go.mod h1:6V87tIXUpvJMskim6YUa+TRDTm7v6OH8FxLOIRYosl4= +cloud.google.com/go/resourcesettings v1.8.3 h1:13HOFU7v4cEvIHXSAQbinF4wp2Baybbq7q9FMctg1Ek= +cloud.google.com/go/resourcesettings v1.8.3/go.mod h1:BzgfXFHIWOOmHe6ZV9+r3OWfpHJgnqXy8jqwx4zTMLw= cloud.google.com/go/retail v1.19.0 h1:OrXxtP/asKi7vFReWmQH5kXrMRPZ2R9Zw92x8O93PMA= cloud.google.com/go/retail v1.19.0/go.mod h1:QMhO+nkvN6Mns1lu6VXmteY0I3mhwPj9bOskn6PK5aY= +cloud.google.com/go/retail v1.19.2 h1:PT6CUlazIFIOLLJnV+bPBtiSH8iusKZ+FZRzZYFt2vk= +cloud.google.com/go/retail v1.19.2/go.mod h1:71tRFYAcR4MhrZ1YZzaJxr030LvaZiIcupH7bXfFBcY= cloud.google.com/go/run v1.6.0 h1:LRJvntufFKJ0Jcwt7BbIHwf/0Ipq4twzyJcH1qSEs84= cloud.google.com/go/run v1.6.0/go.mod h1:DXkPPa8bZ0jfRGLT+EKIlPbHvosBYBMdxTgo9EBbXZE= +cloud.google.com/go/run v1.8.1 h1:aeVLygw0BGLH+Zbj8v3K3nEHvKlgoq+j8fcRJaYZtxY= +cloud.google.com/go/run v1.8.1/go.mod h1:wR5IG8Nujk9pyyNai187K4p8jzSLeqCKCAFBrZ2Sd4c= cloud.google.com/go/scheduler v1.11.1 h1:uGaM4mRrGkJ0LLBMyxD8qbvIko4y+UlSOwJQqRd/lW8= cloud.google.com/go/scheduler v1.11.1/go.mod h1:ptS76q0oOS8hCHOH4Fb/y8YunPEN8emaDdtw0D7W1VE= +cloud.google.com/go/scheduler v1.11.3 h1:p6+h8BoYJC+TvUijGBfORN6nuhOvJ3EwZ2H84CZ1ZEU= +cloud.google.com/go/scheduler v1.11.3/go.mod h1:Io2+gcvUjLX1GdymwaSPJ6ZYxHN9/NNGL5kIV3Ax5+Q= cloud.google.com/go/secretmanager v1.14.1 h1:xlWSIg8rtBn5qCr2f3XtQP19+5COyf/ll49SEvi/0vM= cloud.google.com/go/secretmanager v1.14.1/go.mod h1:L+gO+u2JA9CCyXpSR8gDH0o8EV7i/f0jdBOrUXcIV0U= +cloud.google.com/go/secretmanager v1.14.3 h1:XVGHbcXEsbrgi4XHzgK5np81l1eO7O72WOXHhXUemrM= +cloud.google.com/go/secretmanager v1.14.3/go.mod h1:Pwzcfn69Ni9Lrk1/XBzo1H9+MCJwJ6CDCoeoQUsMN+c= cloud.google.com/go/security v1.18.1 h1:w7XbMR90Ir0y8NUxKJ3uyRHuHYWPUxVI5Z/sGqbrdAQ= cloud.google.com/go/security v1.18.1/go.mod h1:5P1q9rqwt0HuVeL9p61pTqQ6Lgio1c64jL2ZMWZV21Y= +cloud.google.com/go/security v1.18.3 h1:ya9gfY1ign6Yy25VMMMgZ9xy7D/TczDB0ElXcyWmEVE= +cloud.google.com/go/security v1.18.3/go.mod h1:NmlSnEe7vzenMRoTLehUwa/ZTZHDQE59IPRevHcpCe4= cloud.google.com/go/securitycenter v1.35.1 h1:unUyFDeSHv89W7FPBMk10mf3R7+taAJ+1ow+0zpCzGw= cloud.google.com/go/securitycenter v1.35.1/go.mod h1:UDeknPuHWi15TaxrJCIv3aN1VDTz9nqWVUmW2vGayTo= +cloud.google.com/go/securitycenter v1.35.3 h1:H8UvBpcvs1OjI4jZuXX8xsN1IZo88a9PezHXkU2sGps= +cloud.google.com/go/securitycenter v1.35.3/go.mod h1:kjsA8Eg4jlMHW1JwxbMC8148I+gcjgkWPdbDycatoRQ= cloud.google.com/go/servicecontrol v1.11.1 h1:d0uV7Qegtfaa7Z2ClDzr9HJmnbJW7jn0WhZ7wOX6hLE= cloud.google.com/go/servicedirectory v1.12.1 h1:LjbIXEZiyqsIADrj6Y81FnbSlaHPQHJ8UDQQnUegowc= cloud.google.com/go/servicedirectory v1.12.1/go.mod h1:d2H6joDMjnTQ4cUUCZn6k9NgZFbXjLVJbHETjoJR9k0= +cloud.google.com/go/servicedirectory v1.12.3 h1:oFkCp6ti7fc7hzeROmOPQuPBHFqwyhcsv3Yrma28+uc= +cloud.google.com/go/servicedirectory v1.12.3/go.mod h1:dwTKSCYRD6IZMrqoBCIvZek+aOYK/6+jBzOGw8ks5aY= cloud.google.com/go/servicemanagement v1.8.0 h1:fopAQI/IAzlxnVeiKn/8WiV6zKndjFkvi+gzu+NjywY= cloud.google.com/go/serviceusage v1.6.0 h1:rXyq+0+RSIm3HFypctp7WoXxIA563rn206CfMWdqXX4= cloud.google.com/go/shell v1.8.1 h1:etoJal+LB7Pn8+5vE2aAh6QcFbBmerIOh5MxNDoXykw= cloud.google.com/go/shell v1.8.1/go.mod h1:jaU7OHeldDhTwgs3+clM0KYEDYnBAPevUI6wNLf7ycE= +cloud.google.com/go/shell v1.8.3 h1:mjYgUsOtV3jl9xvDmcvlRRmA64deEPf52zOfuc68b/g= +cloud.google.com/go/shell v1.8.3/go.mod h1:OYcrgWF6JSp/uk76sNTtYFlMD0ho2+Cdzc7U3P/bF54= +cloud.google.com/go/spanner v1.70.0/go.mod h1:X5T0XftydYp0K1adeJQDJtdWpbrOeJ7wHecM4tK6FiE= +cloud.google.com/go/spanner v1.73.0/go.mod h1:mw98ua5ggQXVWwp83yjwggqEmW9t8rjs9Po1ohcUGW4= cloud.google.com/go/speech v1.25.1 h1:iGZJS3wrdkje/Vqiacx1+r+zVwUZoXVMdklYIVsvfNw= cloud.google.com/go/speech v1.25.1/go.mod h1:WgQghvghkZ1htG6BhYn98mP7Tg0mti8dBFDLMVXH/vM= +cloud.google.com/go/speech v1.26.0 h1:qvURtJs7BQzQhbxWxwai0pT79S8KLVKJ/4W8igVkt1Y= +cloud.google.com/go/speech v1.26.0/go.mod h1:78bqDV2SgwFlP/M4n3i3PwLthFq6ta7qmyG6lUV7UCA= +cloud.google.com/go/storage v1.35.1/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= +cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0= cloud.google.com/go/storagetransfer v1.11.1 h1:Hd7H1zXGQGEWyWXxWVXDMuNCGasNQim1y9CIaMZIBX8= cloud.google.com/go/storagetransfer v1.11.1/go.mod h1:xnJo9pWysRIha8MgZxhrBEwLYbEdvdmEedhNsP5NINM= +cloud.google.com/go/storagetransfer v1.12.1 h1:W3v9A7MGBN7H9sAFstyciwP/1XEQhUhZfrjclmDnpMs= +cloud.google.com/go/storagetransfer v1.12.1/go.mod h1:hQqbfs8/LTmObJyCC0KrlBw8yBJ2bSFlaGila0qBMk4= cloud.google.com/go/talent v1.7.1 h1:J3iZU+HPfoD18Lx8JsgIpwe8llQ9Fu/evcQudQCB+pk= cloud.google.com/go/talent v1.7.1/go.mod h1:X8UKtTgcP+h51MtDO/b+y3X1GxTTc7gPJ2y0aX3X1hM= +cloud.google.com/go/talent v1.8.0 h1:olv+s2g+LGXeJi+MYF1wI44/TwHaVnO0N7PiucVf5ZQ= +cloud.google.com/go/talent v1.8.0/go.mod h1:/gvOzSrtMcfTL/9xWhdYaZATaxUNhQ+L+3ZaGOGs7bA= cloud.google.com/go/texttospeech v1.8.1 h1:LpX9xKoGObltmT6+RGxqUeSJIq0uqPzo+fcbbOmujbY= cloud.google.com/go/texttospeech v1.8.1/go.mod h1:WoTykB+4mfSDDYPuk7smrdXNRGoJJS6dXRR6l4XqD9g= +cloud.google.com/go/texttospeech v1.11.0 h1:YF/RdNb+jUEp22cIZCvqiFjfA5OxGE+Dxss3mhXU7oQ= +cloud.google.com/go/texttospeech v1.11.0/go.mod h1:7M2ro3I2QfIEvArFk1TJ+pqXJqhszDtxUpnIv/150As= cloud.google.com/go/tpu v1.7.1 h1:MP2GYTVEPkg1KlhY3A4CF9Do8eklQOOfgbIYNINcVaE= cloud.google.com/go/tpu v1.7.1/go.mod h1:kgvyq1Z1yuBJSk5ihUaYxX58YMioCYg1UPuIHSxBX3M= +cloud.google.com/go/tpu v1.8.0 h1:BvMNijOb6Vd46Rr/SR5jWv1MPosOhVsi0UaeAGNjeds= +cloud.google.com/go/tpu v1.8.0/go.mod h1:XyNzyK1xc55WvL5rZEML0Z9/TUHDfnq0uICkQw6rWMo= cloud.google.com/go/trace v1.11.1 h1:UNqdP+HYYtnm6lb91aNA5JQ0X14GnxkABGlfz2PzPew= cloud.google.com/go/trace v1.11.1/go.mod h1:IQKNQuBzH72EGaXEodKlNJrWykGZxet2zgjtS60OtjA= +cloud.google.com/go/trace v1.11.2/go.mod h1:bn7OwXd4pd5rFuAnTrzBuoZ4ax2XQeG3qNgYmfCy0Io= +cloud.google.com/go/translate v1.10.3/go.mod h1:GW0vC1qvPtd3pgtypCv4k4U8B7EdgK9/QEF2aJEUovs= cloud.google.com/go/translate v1.12.1 h1:Vws9BGpVcaOeI6HodyWdvysUzHUBFvk7ymHu1tzFvuM= cloud.google.com/go/translate v1.12.1/go.mod h1:5f4RvC7/hh76qSl6LYuqOJaKbIzEpR1Sj+CMA6gSgIk= +cloud.google.com/go/translate v1.12.3 h1:XJ7LipYJi80BCgVk2lx1fwc7DIYM6oV2qx1G4IAGQ5w= +cloud.google.com/go/translate v1.12.3/go.mod h1:qINOVpgmgBnY4YTFHdfVO4nLrSBlpvlIyosqpGEgyEg= cloud.google.com/go/video v1.23.1 h1:U+fu5Jwi3q8WDDOh1hr8kcdXVUJGmP3vWsZ13jwkWFA= cloud.google.com/go/video v1.23.1/go.mod h1:ncFS3D2plMLhXkWkob/bH4bxQkubrpAlln5x7RWluXA= +cloud.google.com/go/video v1.23.3 h1:C2FH+6yr6LCZC4fP0gm9FwJB/SRh5Ul88O5Sc/bL83I= +cloud.google.com/go/video v1.23.3/go.mod h1:Kvh/BheubZxGZDXSb0iO6YX7ZNcaYHbLjnnaC8Qyy3g= cloud.google.com/go/videointelligence v1.12.1 h1:4XScHLWL/1Q1FVczlxiZT+kSynUQPUktIUTqpIkOMeU= cloud.google.com/go/videointelligence v1.12.1/go.mod h1:C9bQom4KOeBl7IFPj+NiOS6WKEm1P6OOkF/ahFfE1Eg= +cloud.google.com/go/videointelligence v1.12.3 h1:zNTOUQyatGQtnCJ2dR3faRtpWQOlC8wszJqwG5CtwVM= +cloud.google.com/go/videointelligence v1.12.3/go.mod h1:dUA6V+NH7CVgX6TePq0IelVeBMGzvehxKPR4FGf1dtw= cloud.google.com/go/vision v1.2.0 h1:/CsSTkbmO9HC8iQpxbK8ATms3OQaX3YQUeTMGCxlaK4= cloud.google.com/go/vision/v2 v2.9.1 h1:jpK/E7/SJXpbnQVgfr2nGsIIzSQ9GkOsBf2iak1O8nc= cloud.google.com/go/vision/v2 v2.9.1/go.mod h1:keORalKMowhEZB5hEWi1XSVnGALMjLlRwZbDiCPFuQY= +cloud.google.com/go/vision/v2 v2.9.3 h1:dPvfDuPqPH+Yscf0f2f1RprvKkoo+N/j0a+IbLYX7Cs= +cloud.google.com/go/vision/v2 v2.9.3/go.mod h1:weAcT8aNYSgrWWVTC2PuJTc7fcXKvUeAyDq8B6HkLSg= cloud.google.com/go/vmmigration v1.8.1 h1:dyK3bFJVx28FInAkzeLVANpChwWgAmiaUM4GNtEQS/Q= cloud.google.com/go/vmmigration v1.8.1/go.mod h1:MB7vpxl6Oz2w+CecyITUTDFkhWSMQmRTgREwkBZFyZk= +cloud.google.com/go/vmmigration v1.8.3 h1:dpCQq3pj2HnKdbvGTftdWymm3r4ovF7JW5z8xBcO2x4= +cloud.google.com/go/vmmigration v1.8.3/go.mod h1:8CzUpK9eBzohgpL4RvBVtW4sY/sDliVyQonTFQfWcJ4= cloud.google.com/go/vmwareengine v1.3.1 h1:CCdTFQnOatMPbtbMnCja//K4slk5Tjt0u3XEb1T9Qlw= cloud.google.com/go/vmwareengine v1.3.1/go.mod h1:mSYu3wnGKJqvvhIhs7VA47/A/kLoMiJz3gfQAh7cfaI= +cloud.google.com/go/vmwareengine v1.3.3 h1:TfuQr5j7qriINulUMotaC/+27SQaW2thIkF3Gb6VJ38= +cloud.google.com/go/vmwareengine v1.3.3/go.mod h1:G7vz05KGijha0c0dj1INRKyDAaQW8TRMZt/FrfOZVXc= cloud.google.com/go/vpcaccess v1.8.1 h1:e1wJ1wQGMqOf44Gw44PU9G6NYITKm0f2We4eKzMwyEs= cloud.google.com/go/vpcaccess v1.8.1/go.mod h1:cWlLCpLOuMH8oaNmobaymgmLesasLd9w1isrKpiGwIc= +cloud.google.com/go/vpcaccess v1.8.3 h1:vxVaoFM64M/ht619c4wZNF0iq0QPaMWElOh7Ns4r41A= +cloud.google.com/go/vpcaccess v1.8.3/go.mod h1:bqOhyeSh/nEmLIsIUoCiQCBHeNPNjaK9M3bIvKxFdsY= cloud.google.com/go/webrisk v1.10.1 h1:mYYjXXMILCwIEqtChUDNGamMBgJKnoJXa9Os2e76uzk= cloud.google.com/go/webrisk v1.10.1/go.mod h1:VzmUIag5P6V71nVAuzc7Hu0VkIDKjDa543K7HOulH/k= +cloud.google.com/go/webrisk v1.10.3 h1:yh0v/5n49VO4/i9pYfDm1gLJUj1Ph3Xzegn8WvK9YRA= +cloud.google.com/go/webrisk v1.10.3/go.mod h1:rRAqCA5/EQOX8ZEEF4HMIrLHGTK/Y1hEQgWMnih+jAw= cloud.google.com/go/websecurityscanner v1.7.1 h1:VyJObL4Pzd4ypF2814rKlesrVibrf1WpZ2yp4jJvKyw= cloud.google.com/go/websecurityscanner v1.7.1/go.mod h1:vAZ6hyqECDhgF+gyVRGzfXMrURQN5NH75Y9yW/7sSHU= +cloud.google.com/go/websecurityscanner v1.7.3 h1:/uxhVCWKXzPw5pVfnBOVjaSiQ6Bm0tDExDOCLV40thw= +cloud.google.com/go/websecurityscanner v1.7.3/go.mod h1:gy0Kmct4GNLoCePWs9xkQym1D7D59ld5AjhXrjipxSs= cloud.google.com/go/workflows v1.13.1 h1:DkxrZ4HyXvjQLZWsYAUOV1w7d2a43XscM9dmkIGmrDc= cloud.google.com/go/workflows v1.13.1/go.mod h1:xNdYtD6Sjoug+khNCAtBMK/rdh8qkjyL6aBas2XlkNc= +cloud.google.com/go/workflows v1.13.3 h1:lNFDMranJymDEB7cTI7DI9czbc1WU0RWY9KCEv9zuDY= +cloud.google.com/go/workflows v1.13.3/go.mod h1:Xi7wggEt/ljoEcyk+CB/Oa1AHBCk0T1f5UH/exBB5CE= contrib.go.opencensus.io/exporter/aws v0.0.0-20230502192102-15967c811cec h1:CSNP8nIEQt4sZEo2sGUiWSmVJ9c5QdyIQvwzZAsn+8Y= contrib.go.opencensus.io/exporter/aws v0.0.0-20230502192102-15967c811cec/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= contrib.go.opencensus.io/exporter/ocagent v0.6.0 h1:Z1n6UAyr0QwM284yUuh5Zd8JlvxUGAhFZcgMJkMPrGM= @@ -276,6 +524,9 @@ github.com/DmitriyVTitov/size v1.5.0 h1:/PzqxYrOyOUX1BXj6J9OuVRVGe+66VL4D9FlUaW5 github.com/DmitriyVTitov/size v1.5.0/go.mod h1:le6rNI4CoLQV1b9gzp1+3d7hMAD/uu2QcJ+aYbNgiU0= github.com/GoogleCloudPlatform/cloudsql-proxy v1.36.0 h1:kAtNAWwvTt5+iew6baV0kbOrtjYTXPtWNSyOFlcxkBU= github.com/GoogleCloudPlatform/cloudsql-proxy v1.36.0/go.mod h1:VRKXU8C7Y/aUKjRBTGfw0Ndv4YqNxlB8zAPJJDxbASE= +github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.0/go.mod h1:dppbR7CwXD4pgtV9t3wD1812RaLDcBjtblcDF5f1vI0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1/go.mod h1:jyqM3eLpJ3IbIFDTKVz2rF9T/xWGW0rIriGwnz8l9Tk= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1/go.mod h1:viRWSEhtMZqz1rhwmOVKkWl6SwmVowfL9O2YR5gI2PE= github.com/IBM/go-sdk-core/v5 v5.17.4 h1:VGb9+mRrnS2HpHZFM5hy4J6ppIWnwNrw0G+tLSgcJLc= github.com/IBM/go-sdk-core/v5 v5.17.4/go.mod h1:KsAAI7eStAWwQa4F96MLy+whYSh39JzNjklZRbN/8ns= github.com/IBM/ibm-cos-sdk-go v1.11.0 h1:Jp55NLN3OvBwucMGpP5wNybyjncsmTZ9+GPHai/1cE8= @@ -354,6 +605,8 @@ github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuP github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/baidubce/bce-sdk-go v0.9.188 h1:8MA7ewe4VpX01uYl7Kic6ZvfIReUFdSKbY46ZqlQM7U= github.com/baidubce/bce-sdk-go v0.9.188/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg= +github.com/bazelbuild/rules_go v0.49.0 h1:5vCbuvy8Q11g41lseGJDc5vxhDjJtfxr6nM/IC4VmqM= +github.com/bazelbuild/rules_go v0.49.0/go.mod h1:Dhcz716Kqg1RHNWos+N6MlXNkjNP2EwZQ0LukRKJfMs= github.com/benbjohnson/immutable v0.4.0 h1:CTqXbEerYso8YzVPxmWxh2gnoRQbbB9X1quUC8+vGZA= github.com/benbjohnson/immutable v0.4.0/go.mod h1:iAr8OjJGLnLmVUr9MZ/rz4PWUy6Ouc2JLYuMArmvAJM= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= @@ -398,6 +651,7 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible h1:C29Ae4G5GtYyY github.com/circonus-labs/circonusllhist v0.1.3 h1:TJH+oke8D16535+jHExHj4nQvzlZrj7ug5D7I/orNUA= github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk= +github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c h1:2zRrJWIt/f9c9HhNHAgrRgq0San5gRRUJTBXLkchal0= github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA= github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= @@ -502,6 +756,7 @@ github.com/elastic/go-windows v1.0.1 h1:AlYZOldA+UJ0/2nBuqWdo90GFCgG9xuyw9SYzGUt github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss= github.com/elazarl/goproxy v1.3.0/go.mod h1:X/5W/t+gzDyLfHW4DrMdpjqYjpXsURlBt9lpBDxZZZQ= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw= +github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= @@ -593,10 +848,17 @@ github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAx github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg= github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/googleapis/cloud-bigtable-clients-test v0.0.2 h1:S+sCHWAiAc+urcEnvg5JYJUOdlQEm/SEzQ/c/IdAH5M= github.com/googleapis/cloud-bigtable-clients-test v0.0.2/go.mod h1:mk3CrkrouRgtnhID6UZQDK3DrFFa7cYCAJcEmNsHYrY= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= +github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= +github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A= +github.com/googleapis/gax-go/v2 v2.14.0/go.mod h1:lhBCnjdLrWRaPvLWhmc8IS24m9mr07qSYnHncrgo+zk= github.com/googleapis/gnostic v0.3.0 h1:CcQijm0XKekKjP/YCz28LXVSpgguuB+nCxaSjCe09y0= github.com/googleapis/go-type-adapters v1.0.0 h1:9XdMn+d/G57qq1s8dNc5IesGCXHf6V2HZ2JwRxfA2tA= github.com/googleapis/google-cloud-go-testing v0.0.0-20210719221736-1c9a4c676720 h1:zC34cGQu69FG7qzJ3WiKW244WfhDC3xxYMeNOX2gtUQ= @@ -627,6 +889,7 @@ github.com/grafana/grafana/apps/investigation v0.0.0-20250121113133-e747350fee2d github.com/grafana/grafana/apps/playlist v0.0.0-20250121113133-e747350fee2d/go.mod h1:DjJe5osrW/BKrzN9hAAOSElNWutj1bcriExa7iDP7kA= github.com/grafana/grafana/pkg/aggregator v0.0.0-20250121113133-e747350fee2d/go.mod h1:1sq0guad+G4SUTlBgx7SXfhnzy7D86K/LcVOtiQCiMA= github.com/grafana/grafana/pkg/build v0.0.0-20250220114259-be81314e2118/go.mod h1:STVpVboMYeBAfyn6Zw6XHhTHqUxzMy7pzRiVgk1l0W0= +github.com/grafana/grafana/pkg/build v0.0.0-20250227105625-8f465f124924/go.mod h1:Vw0LdoMma64VgIMVpRY3i0D156jddgUGjTQBOcyeF3k= github.com/grafana/grafana/pkg/build v0.0.0-20250227163402-d78c646f93bb/go.mod h1:Vw0LdoMma64VgIMVpRY3i0D156jddgUGjTQBOcyeF3k= github.com/grafana/grafana/pkg/semconv v0.0.0-20250121113133-e747350fee2d/go.mod h1:tfLnBpPYgwrBMRz4EXqPCZJyCjEG4Ev37FSlXnocJ2c= github.com/grafana/grafana/pkg/storage/unified/apistore v0.0.0-20250121113133-e747350fee2d/go.mod h1:CXpwZ3Mkw6xVlGKc0SqUxqXCP3Uv182q6qAQnLaLxRg= @@ -894,6 +1157,7 @@ github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFt github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad h1:fiWzISvDn0Csy5H0iwgAuJGQTUpVfEMJJd4nRFXogbc= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= @@ -1046,12 +1310,18 @@ go.opentelemetry.io/contrib/bridges/prometheus v0.53.0 h1:BdkKDtcrHThgjcEia1737O go.opentelemetry.io/contrib/bridges/prometheus v0.53.0/go.mod h1:ZkhVxcJgeXlL/lVyT/vxNHVFiSG5qOaDwYaSgD8IfZo= go.opentelemetry.io/contrib/config v0.7.0 h1:b1rK5tGTuhhPirJiMxOcyQfZs76j2VapY6ODn3b2Dbs= go.opentelemetry.io/contrib/config v0.7.0/go.mod h1:8tdiFd8N5etOi3XzBmAoMxplEzI3TcL8dU5rM5/xcOQ= +go.opentelemetry.io/contrib/detectors/gcp v1.29.0/go.mod h1:GW2aWZNwR2ZxDLdv8OyC2G8zkRoQBuURgV7RPQgcPoU= +go.opentelemetry.io/contrib/detectors/gcp v1.32.0/go.mod h1:TVqo0Sda4Cv8gCIixd7LuLwW4EylumVWfhjZJjDD4DU= go.opentelemetry.io/contrib/exporters/autoexport v0.53.0 h1:13K+tY7E8GJInkrvRiPAhC0gi/7vKjzDNhtmCf+QXG8= go.opentelemetry.io/contrib/exporters/autoexport v0.53.0/go.mod h1:lyQF6xQ4iDnMg4sccNdFs1zf62xd79YI8vZqKjOTwMs= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0/go.mod h1:HDBUsEjOuRC0EzKZ1bSaRGZWUBAzo+MhAcUUORSr4D0= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.58.0/go.mod h1:uosvgpqTcTXtcPQORTbEkZNDQTCDOgTz1fe6aLSyqrQ= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q= go.opentelemetry.io/contrib/propagators/b3 v1.27.0 h1:IjgxbomVrV9za6bRi8fWCNXENs0co37SZedQilP2hm0= go.opentelemetry.io/contrib/propagators/b3 v1.27.0/go.mod h1:Dv9obQz25lCisDvvs4dy28UPh974CxkahRDUPsY7y9E= @@ -1059,6 +1329,8 @@ go.opentelemetry.io/contrib/propagators/jaeger v1.33.0/go.mod h1:ku/EpGk44S5lyVM go.opentelemetry.io/contrib/samplers/jaegerremote v0.27.0/go.mod h1:IohbtCIY5Erb6wKnDddXOMNlG7GwyZnkrgcqjPmhpaA= go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= +go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= go.opentelemetry.io/otel/bridge/opencensus v1.27.0 h1:ao9aGGHd+G4YfjBpGs6vbkvt5hoC67STlJA9fCnOAcs= go.opentelemetry.io/otel/bridge/opencensus v1.27.0/go.mod h1:uRvWtAAXzyVOST0WMPX5JHGBaAvBws+2F8PcC5gMnTk= @@ -1080,12 +1352,20 @@ go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.28.0 h1:EVSnY9JbEEW92bE go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.28.0/go.mod h1:Ea1N1QQryNXpCD0I1fdLibBAIpQuBkznMmkdKrapk1Y= go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= +go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= +go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= +go.opentelemetry.io/otel/sdk v1.30.0/go.mod h1:p14X4Ok8S+sygzblytT1nqG98QG2KYKv++HE0LY/mhg= go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/sdk/metric v1.29.0/go.mod h1:6zZLdCl2fkauYoZIOn/soQIDSWFmNSRcICarHfuhNJQ= +go.opentelemetry.io/otel/sdk/metric v1.30.0/go.mod h1:waS6P3YqFNzeP01kuo/MBBYqaoBJl7efRQHOaydhy1Y= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= +go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -1118,6 +1398,7 @@ golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= @@ -1126,6 +1407,8 @@ golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= +golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= @@ -1137,8 +1420,10 @@ golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457 h1:zf5N6UOrA487eEFacMePxjXAJctxKmyjKUsjA11Uzuk= golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= @@ -1147,7 +1432,9 @@ golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= @@ -1158,26 +1445,60 @@ golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6f gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc= gonum.org/v1/plot v0.14.0 h1:+LBDVFYwFe4LHhdP8coW6296MBEY4nQ+Y4vuUpJopcE= gonum.org/v1/plot v0.14.0/go.mod h1:MLdR9424SJed+5VqC6MsouEpig9pZX2VZ57H9ko2bXU= +google.golang.org/api v0.152.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY= +google.golang.org/api v0.177.0/go.mod h1:srbhue4MLjkjbkux5p3dw/ocYOSZTaIEvf7bCOnFQDw= +google.golang.org/api v0.203.0/go.mod h1:BuOVyCSYEPwJb3npWvDnNmFI92f3GeRnHNkETneT3SI= +google.golang.org/api v0.211.0/go.mod h1:XOloB4MXFH4UTlQSGuNUxw0UT74qdENK8d6JNsXKLi0= +google.golang.org/api v0.214.0/go.mod h1:bYPpLG8AyeMWwDU6NXoB00xC0DFkikVvd5MfwoxjLqE= +google.golang.org/api v0.217.0/go.mod h1:qMc2E8cBAbQlRypBTBWHklNJlaZZJBwDv81B1Iu8oSI= +google.golang.org/api v0.218.0/go.mod h1:5VGHBAkxrA/8EFjLVEYmMUJ8/8+gWWQ3s4cFH0FxG2M= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/genproto v0.0.0-20230731193218-e0aa005b6bdf/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8= +google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= +google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53/go.mod h1:fheguH3Am2dGp1LfXkrvwqC/KlFq8F0nLq3LryOMrrE= +google.golang.org/genproto v0.0.0-20241118233622-e639e219e697/go.mod h1:JJrvXBWRZaFMxBufik1a4RpFw4HhgVtBBWQeQgUj2cc= +google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= +google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= +google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= +google.golang.org/genproto/googleapis/api v0.0.0-20240429193739-8cf5692501f6/go.mod h1:10yRODfgim2/T8csjQsMPgZOMvtytXKTDRzH6HRGzRw= google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117/go.mod h1:OimBR/bc1wPO9iV4NC2bpyjy3VnAwZh5EBPQdtaE5oo= +google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo= +google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:wp2WsuBYj6j8wUdo3ToZsdxxixbvQNAHqVJrTgi5E5M= google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53/go.mod h1:riSXTwQ4+nqmPGtobMFyW5FqVAmIs0St6VPp4Ug7CE4= +google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697/go.mod h1:+D9ySVjN8nY8YCVjc5O7PZDIdZporIDY3KaGfJunh88= google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a/go.mod h1:jehYqy3+AhJU9ve55aNOaSml7wUXjF9x6z2LcCfpAhY= +google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08= google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:E5//3O5ZIG2l71Xnt+P/CYUY8Bxs8E7WMoZ9tlcMbAY= +google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:Ic02D47M+zbarjYYUlK57y316f2MoN0gjAwI3f2S95o= google.golang.org/genproto/googleapis/bytestream v0.0.0-20250102185135-69823020774d h1:NZBSeFsuFS5YrgHMW/8xfTbzNXMshQPNgq2Yb7xipEs= google.golang.org/genproto/googleapis/bytestream v0.0.0-20250102185135-69823020774d/go.mod h1:s4mHJ3FfG8P6A3O+gZ8TVqB3ufjOl9UG3ANCMMwCHmo= +google.golang.org/genproto/googleapis/bytestream v0.0.0-20250127172529-29210b9bc287 h1:c/HGC2hBfwgjeBtQMLjfmuS2KG28ngtUpn5XiX8o3rY= +google.golang.org/genproto/googleapis/bytestream v0.0.0-20250127172529-29210b9bc287/go.mod h1:7VGktjvijnuhf2AobFqsoaBGnG8rImcxqoL+QPBPRq4= google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240429193739-8cf5692501f6/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241206012308-a4fef0638583/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250124145028-65684f501c47/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250127172529-29210b9bc287/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk= google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= +google.golang.org/grpc v1.67.3/go.mod h1:YGaHCc6Oap+FzBJTZLBzkGSYt/cvGPFTPxkn7QfSU8s= google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= @@ -1186,6 +1507,7 @@ google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojt google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= diff --git a/pkg/aggregator/go.mod b/pkg/aggregator/go.mod index cac9067a6a9..fe5a29c5024 100644 --- a/pkg/aggregator/go.mod +++ b/pkg/aggregator/go.mod @@ -146,9 +146,9 @@ require ( golang.org/x/time v0.9.0 // indirect golang.org/x/tools v0.29.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect - google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect + google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 // indirect google.golang.org/grpc v1.70.0 // indirect google.golang.org/protobuf v1.36.5 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect diff --git a/pkg/aggregator/go.sum b/pkg/aggregator/go.sum index 11bd9b72803..acf0f589b72 100644 --- a/pkg/aggregator/go.sum +++ b/pkg/aggregator/go.sum @@ -482,12 +482,15 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU= -google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4= -google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f h1:gap6+3Gk41EItBuyi4XX/bp4oqJ3UwuIMl25yGinuAA= -google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:Ic02D47M+zbarjYYUlK57y316f2MoN0gjAwI3f2S95o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= +google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4 h1:Pw6WnI9W/LIdRxqK7T6XGugGbHIRl5Q7q3BssH6xk4s= +google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4/go.mod h1:qbZzneIOXSq+KFAFut9krLfRLZiFLzZL5u2t8SV83EE= +google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 h1:5iw9XJTD4thFidQmFVvx0wi4g5yOHk76rNRUxz1ZG5g= +google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47/go.mod h1:AfA77qWLcidQWywD0YgqfpJzf50w2VjzBml3TybHeJU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 h1:2duwAxN2+k0xLNpjnHTXoMUgnv6VPSp5fiqTuwSxjmI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk= +google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4 h1:Pw6WnI9W/LIdRxqK7T6XGugGbHIRl5Q7q3BssH6xk4s= +google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 h1:5iw9XJTD4thFidQmFVvx0wi4g5yOHk76rNRUxz1ZG5g= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 h1:2duwAxN2+k0xLNpjnHTXoMUgnv6VPSp5fiqTuwSxjmI= google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= diff --git a/pkg/apimachinery/go.mod b/pkg/apimachinery/go.mod index c702c33a2ca..cf9304efb51 100644 --- a/pkg/apimachinery/go.mod +++ b/pkg/apimachinery/go.mod @@ -42,7 +42,7 @@ require ( golang.org/x/sync v0.11.0 // indirect golang.org/x/sys v0.30.0 // indirect golang.org/x/text v0.22.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 // indirect google.golang.org/grpc v1.70.0 // indirect google.golang.org/protobuf v1.36.5 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/pkg/apimachinery/go.sum b/pkg/apimachinery/go.sum index 4982a368eb5..da0e0ee3648 100644 --- a/pkg/apimachinery/go.sum +++ b/pkg/apimachinery/go.sum @@ -147,8 +147,9 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 h1:2duwAxN2+k0xLNpjnHTXoMUgnv6VPSp5fiqTuwSxjmI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 h1:2duwAxN2+k0xLNpjnHTXoMUgnv6VPSp5fiqTuwSxjmI= google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= diff --git a/pkg/apiserver/go.mod b/pkg/apiserver/go.mod index 59a16f25782..0902897c1a9 100644 --- a/pkg/apiserver/go.mod +++ b/pkg/apiserver/go.mod @@ -89,9 +89,9 @@ require ( golang.org/x/text v0.22.0 // indirect golang.org/x/time v0.9.0 // indirect golang.org/x/tools v0.29.0 // indirect - google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect + google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 // indirect google.golang.org/grpc v1.70.0 // indirect google.golang.org/protobuf v1.36.5 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect diff --git a/pkg/apiserver/go.sum b/pkg/apiserver/go.sum index f1076d70d55..336976f8472 100644 --- a/pkg/apiserver/go.sum +++ b/pkg/apiserver/go.sum @@ -298,12 +298,12 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU= -google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4= -google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f h1:gap6+3Gk41EItBuyi4XX/bp4oqJ3UwuIMl25yGinuAA= -google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:Ic02D47M+zbarjYYUlK57y316f2MoN0gjAwI3f2S95o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= +google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4 h1:Pw6WnI9W/LIdRxqK7T6XGugGbHIRl5Q7q3BssH6xk4s= +google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4/go.mod h1:qbZzneIOXSq+KFAFut9krLfRLZiFLzZL5u2t8SV83EE= +google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 h1:5iw9XJTD4thFidQmFVvx0wi4g5yOHk76rNRUxz1ZG5g= +google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47/go.mod h1:AfA77qWLcidQWywD0YgqfpJzf50w2VjzBml3TybHeJU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 h1:2duwAxN2+k0xLNpjnHTXoMUgnv6VPSp5fiqTuwSxjmI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk= google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= diff --git a/pkg/build/go.mod b/pkg/build/go.mod index fd52527bf94..6eeec2f5377 100644 --- a/pkg/build/go.mod +++ b/pkg/build/go.mod @@ -8,7 +8,7 @@ go 1.23.1 replace github.com/docker/docker => github.com/moby/moby v26.0.0+incompatible require ( - cloud.google.com/go/storage v1.43.0 // @grafana/grafana-backend-group + cloud.google.com/go/storage v1.50.0 // @grafana/grafana-backend-group github.com/Masterminds/semver/v3 v3.3.0 // @grafana/grafana-developer-enablement-squad github.com/aws/aws-sdk-go v1.55.5 // @grafana/aws-datasources github.com/docker/docker v27.4.1+incompatible // @grafana/grafana-developer-enablement-squad @@ -33,18 +33,18 @@ require ( golang.org/x/sync v0.11.0 // indirect; @grafana/alerting-backend golang.org/x/text v0.22.0 // indirect; @grafana/grafana-backend-group golang.org/x/time v0.9.0 // indirect; @grafana/grafana-backend-group - google.golang.org/api v0.216.0 // @grafana/grafana-backend-group + google.golang.org/api v0.220.0 // @grafana/grafana-backend-group google.golang.org/grpc v1.70.0 // indirect; @grafana/plugins-platform-backend google.golang.org/protobuf v1.36.5 // indirect; @grafana/plugins-platform-backend gopkg.in/yaml.v3 v3.0.1 // @grafana/alerting-backend ) require ( - cloud.google.com/go v0.116.0 // indirect - cloud.google.com/go/auth v0.13.0 // indirect - cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect + cloud.google.com/go v0.118.2 // indirect + cloud.google.com/go/auth v0.14.1 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.7 // indirect cloud.google.com/go/compute/metadata v0.6.0 // indirect - cloud.google.com/go/iam v1.2.1 // indirect + cloud.google.com/go/iam v1.3.1 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/bmatcuk/doublestar v1.3.4 // indirect github.com/buildkite/yaml v2.1.0+incompatible // indirect @@ -60,9 +60,8 @@ require ( github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 // indirect github.com/go-logr/logr v1.4.2 // indirect; @grafana/grafana-app-platform-squad github.com/go-logr/stdr v1.2.2 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/s2a-go v0.1.8 // indirect + github.com/google/s2a-go v0.1.9 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect @@ -70,34 +69,44 @@ require ( github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect go.opentelemetry.io/otel/metric v1.34.0 // indirect go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect golang.org/x/sys v0.30.0 // indirect - google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect; @grafana/grafana-backend-group - google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect + google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4 // indirect; @grafana/grafana-backend-group + google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) require dagger.io/dagger v0.11.8-rc.2 require ( + cel.dev/expr v0.19.0 // indirect + cloud.google.com/go/monitoring v1.23.0 // indirect github.com/99designs/gqlgen v0.17.44 // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0 // indirect github.com/Khan/genqlient v0.7.0 // indirect github.com/adrg/xdg v0.4.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 // indirect github.com/containerd/log v0.1.0 // indirect github.com/distribution/reference v0.6.0 // indirect + github.com/envoyproxy/go-control-plane/envoy v1.32.3 // indirect + github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/term v0.5.0 // indirect + github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/sosodev/duration v1.2.0 // indirect github.com/vektah/gqlparser/v2 v2.5.20 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/detectors/gcp v1.33.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.0.0-20240518090000-14441aefdf88 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.4.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 // indirect @@ -105,6 +114,7 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 // indirect go.opentelemetry.io/otel/log v0.4.0 // indirect go.opentelemetry.io/otel/sdk/log v0.4.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.32.0 // indirect go.opentelemetry.io/proto/otlp v1.5.0 // indirect golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect gotest.tools/v3 v3.5.1 // indirect diff --git a/pkg/build/go.sum b/pkg/build/go.sum index b1e8e4c3aa9..8d07672f075 100644 --- a/pkg/build/go.sum +++ b/pkg/build/go.sum @@ -1,18 +1,26 @@ +cel.dev/expr v0.19.0 h1:lXuo+nDhpyJSpWxpPVi5cPUwzKb+dsdOiw6IreM5yt0= +cel.dev/expr v0.19.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= -cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= -cloud.google.com/go/auth v0.13.0 h1:8Fu8TZy167JkW8Tj3q7dIkr2v4cndv41ouecJx0PAHs= -cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q= -cloud.google.com/go/auth/oauth2adapt v0.2.6 h1:V6a6XDu2lTwPZWOawrAa9HUK+DB2zfJyTuciBG5hFkU= -cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8= +cloud.google.com/go v0.118.2 h1:bKXO7RXMFDkniAAvvuMrAPtQ/VHrs9e7J5UT3yrGdTY= +cloud.google.com/go v0.118.2/go.mod h1:CFO4UPEPi8oV21xoezZCrd3d81K4fFkDTEJu4R8K+9M= +cloud.google.com/go/auth v0.14.1 h1:AwoJbzUdxA/whv1qj3TLKwh3XX5sikny2fc40wUl+h0= +cloud.google.com/go/auth v0.14.1/go.mod h1:4JHUxlGXisL0AW8kXPtUF6ztuOksyfUQNFjfsOCXkPM= +cloud.google.com/go/auth/oauth2adapt v0.2.7 h1:/Lc7xODdqcEw8IrZ9SvwnlLX6j9FHQM74z6cBk9Rw6M= +cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc= cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= -cloud.google.com/go/iam v1.2.1 h1:QFct02HRb7H12J/3utj0qf5tobFh9V4vR6h9eX5EBRU= -cloud.google.com/go/iam v1.2.1/go.mod h1:3VUIJDPpwT6p/amXRC5GY8fCCh70lxPygguVtI0Z4/g= -cloud.google.com/go/longrunning v0.6.1 h1:lOLTFxYpr8hcRtcwWir5ITh1PAKUD/sG2lKrTSYjyMc= -cloud.google.com/go/longrunning v0.6.1/go.mod h1:nHISoOZpBcmlwbJmiVk5oDRz0qG/ZxPynEGs1iZ79s0= -cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs= -cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0= +cloud.google.com/go/iam v1.3.1 h1:KFf8SaT71yYq+sQtRISn90Gyhyf4X8RGgeAVC8XGf3E= +cloud.google.com/go/iam v1.3.1/go.mod h1:3wMtuyT4NcbnYNPLMBzYRFiEfjKfJlLVLrisE7bwm34= +cloud.google.com/go/logging v1.13.0 h1:7j0HgAp0B94o1YRDqiqm26w4q1rDMH7XNRU34lJXHYc= +cloud.google.com/go/logging v1.13.0/go.mod h1:36CoKh6KA/M0PbhPKMq6/qety2DCAErbhXT62TuXALA= +cloud.google.com/go/longrunning v0.6.4 h1:3tyw9rO3E2XVXzSApn1gyEEnH2K9SynNQjMlBi3uHLg= +cloud.google.com/go/longrunning v0.6.4/go.mod h1:ttZpLCe6e7EXvn9OxpBRx7kZEB0efv8yBO6YnVMfhJs= +cloud.google.com/go/monitoring v1.23.0 h1:M3nXww2gn9oZ/qWN2bZ35CjolnVHM3qnSbu6srCPgjk= +cloud.google.com/go/monitoring v1.23.0/go.mod h1:034NnlQPDzrQ64G2Gavhl0LUHZs9H3rRmhtnp7jiJgg= +cloud.google.com/go/storage v1.50.0 h1:3TbVkzTooBvnZsk7WaAQfOsNrdoM8QHusXA1cpk6QJs= +cloud.google.com/go/storage v1.50.0/go.mod h1:l7XeiD//vx5lfqE3RavfmU9yvk5Pp0Zhcv482poyafY= +cloud.google.com/go/trace v1.11.3 h1:c+I4YFjxRQjvAhRmSsmjpASUKq88chOX854ied0K/pE= +cloud.google.com/go/trace v1.11.3/go.mod h1:pt7zCYiDSQjC9Y2oqCsh9jF4GStB/hmjrYLsxRR27q8= dagger.io/dagger v0.11.8-rc.2 h1:HCP3gXgAfJJBFitJm0jRdKWJsIKgSWNmVN9UV+CkOdk= dagger.io/dagger v0.11.8-rc.2/go.mod h1:kIzxLfN8N8FXUCN9u5EHLBJUJMJm0t6XynecUzp0A5w= github.com/99designs/basicauth-go v0.0.0-20160802081356-2a93ba0f464d/go.mod h1:3cARGAK9CfW3HoxCy1a0G4TKrdiKke8ftOMEOHyySYs= @@ -24,6 +32,14 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 h1:3c8yed4lgqTt+oTQ+JNMDo+F4xprBf+O/il4ZC0nRLw= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0/go.mod h1:obipzmGjfSjam60XLwGfqUkJsfiheAl+TUjG+4yzyPM= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0 h1:o90wcURuxekmXrtxmYWTyNla0+ZEHhud6DI1ZTxd1vI= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0/go.mod h1:6fTWu4m3jocfUZLYF5KsZC1TUfRvEjs7lM4crme/irw= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.49.0 h1:jJKWl98inONJAr/IZrdFQUWcwUO95DLY1XMD1ZIut+g= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.49.0/go.mod h1:l2fIqmwB+FKSfvn3bAD/0i+AXAxhIZjTK2svT/mgUXs= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0 h1:GYUJLfvd++4DMuMhCFLgLXvFwofIxh/qOwoGuS/LTew= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0/go.mod h1:wRbFgBQUVm1YXrvWKofAEmq9HNJTDphbAaJSSX01KUI= github.com/Khan/genqlient v0.7.0 h1:GZ1meyRnzcDTK48EjqB8t3bcfYvHArCUUvgOwpz1D4w= github.com/Khan/genqlient v0.7.0/go.mod h1:HNyy3wZvuYwmW3Y7mkoQLZsa/R5n5yIRajS1kPBvSFM= github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= @@ -47,11 +63,15 @@ github.com/buildkite/yaml v2.1.0+incompatible/go.mod h1:UoU8vbcwu1+vjZq01+KrpSeL github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 h1:QVw89YDxXxEe+l8gU8ETbOasdwEV+avkR75ZzsVV9WI= +github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/containerd/containerd v1.3.4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= @@ -87,7 +107,15 @@ github.com/drone/signal v1.0.0/go.mod h1:S8t92eFT0g4WUgEc/LxG+LCuiskpMNsG0ajAMGn github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= +github.com/envoyproxy/go-control-plane v0.13.4/go.mod h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA= +github.com/envoyproxy/go-control-plane/envoy v1.32.3 h1:hVEaommgvzTjTd4xCaFd+kEQ2iYBtGxP6luyLrx6uOk= +github.com/envoyproxy/go-control-plane/envoy v1.32.3/go.mod h1:F6hWupPfh75TBXGKA++MCT/CZHFq5r9/uwt/kQYkZfE= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= +github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -102,9 +130,6 @@ github.com/gogo/protobuf v0.0.0-20170307180453-100ba4e88506/go.mod h1:r8qH/GZQm5 github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -115,7 +140,6 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -125,7 +149,6 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-github/v69 v69.2.0 h1:wR+Wi/fN2zdUx9YxSmYE0ktiX9IAR/BeePzeaUUbEHE= @@ -134,9 +157,8 @@ github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= -github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= -github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= +github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= @@ -185,6 +207,8 @@ github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2sz github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -210,7 +234,6 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= @@ -225,10 +248,10 @@ github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRT github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/detectors/gcp v1.33.0 h1:FVPoXEoILwgbZUu4X7YSgsESsAmGRgoYcnXkzgQPhP4= +go.opentelemetry.io/contrib/detectors/gcp v1.33.0/go.mod h1:ZHrLmr4ikK2AwRj9QL+c9s2SOlgoSRyMpNVzUj2fZqI= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 h1:rgMkmiGfix9vFJDcDi1PK8WEQP4FLQwLDfhp5ZLpFeE= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s= @@ -245,6 +268,8 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 h1:tgJ0u go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0/go.mod h1:U7HYyW0zt/a9x5J1Kjs+r1f/d4ZHnYFclhYY2+YbeoE= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 h1:BEj3SPM81McUZHYjRS5pEgNgnmzGJ5tRpU5krWnV8Bs= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0/go.mod h1:9cKLGBDzI/F3NoHLQGm4ZrYdIHsvGt6ej6hUowxY0J4= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0 h1:WDdP9acbMYjbKIyJUhTvtzj601sVJOqgWdUxSdR/Ysc= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0/go.mod h1:BLbf7zbNIONBLPwvFnwNHGj4zge8uTCM/UPIVW1Mq2I= go.opentelemetry.io/otel/log v0.4.0 h1:/vZ+3Utqh18e8TPjuc3ecg284078KWrR8BRz+PQAj3o= go.opentelemetry.io/otel/log v0.4.0/go.mod h1:DhGnQvky7pHy82MIRV43iXh3FlKN8UUKftn0KbLOq6I= go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= @@ -287,7 +312,6 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -332,25 +356,24 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.216.0 h1:xnEHy+xWFrtYInWPy8OdGFsyIfWJjtVnO39g7pz2BFY= -google.golang.org/api v0.216.0/go.mod h1:K9wzQMvWi47Z9IU7OgdOofvZuw75Ge3PPITImZR/UyI= +google.golang.org/api v0.220.0 h1:3oMI4gdBgB72WFVwE1nerDD8W3HUOS4kypK6rRLbGns= +google.golang.org/api v0.220.0/go.mod h1:26ZAlY6aN/8WgpCzjPNy18QpYaz7Zgg1h0qe1GkZEmY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU= -google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4= -google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f h1:gap6+3Gk41EItBuyi4XX/bp4oqJ3UwuIMl25yGinuAA= -google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:Ic02D47M+zbarjYYUlK57y316f2MoN0gjAwI3f2S95o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= +google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4 h1:Pw6WnI9W/LIdRxqK7T6XGugGbHIRl5Q7q3BssH6xk4s= +google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4/go.mod h1:qbZzneIOXSq+KFAFut9krLfRLZiFLzZL5u2t8SV83EE= +google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 h1:5iw9XJTD4thFidQmFVvx0wi4g5yOHk76rNRUxz1ZG5g= +google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47/go.mod h1:AfA77qWLcidQWywD0YgqfpJzf50w2VjzBml3TybHeJU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 h1:2duwAxN2+k0xLNpjnHTXoMUgnv6VPSp5fiqTuwSxjmI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -359,7 +382,6 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= diff --git a/pkg/promlib/go.mod b/pkg/promlib/go.mod index fb2946bb264..29499e52ad2 100644 --- a/pkg/promlib/go.mod +++ b/pkg/promlib/go.mod @@ -117,9 +117,9 @@ require ( golang.org/x/text v0.22.0 // indirect golang.org/x/tools v0.29.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect - google.golang.org/api v0.216.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect + google.golang.org/api v0.220.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 // indirect google.golang.org/grpc v1.70.0 // indirect google.golang.org/protobuf v1.36.5 // indirect gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect diff --git a/pkg/promlib/go.sum b/pkg/promlib/go.sum index f6b5b3b3d42..7d0e120b3f8 100644 --- a/pkg/promlib/go.sum +++ b/pkg/promlib/go.sum @@ -1,7 +1,9 @@ -cloud.google.com/go/auth v0.13.0 h1:8Fu8TZy167JkW8Tj3q7dIkr2v4cndv41ouecJx0PAHs= -cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q= -cloud.google.com/go/auth/oauth2adapt v0.2.6 h1:V6a6XDu2lTwPZWOawrAa9HUK+DB2zfJyTuciBG5hFkU= -cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8= +cloud.google.com/go/auth v0.14.1 h1:AwoJbzUdxA/whv1qj3TLKwh3XX5sikny2fc40wUl+h0= +cloud.google.com/go/auth v0.14.1/go.mod h1:4JHUxlGXisL0AW8kXPtUF6ztuOksyfUQNFjfsOCXkPM= +cloud.google.com/go/auth/oauth2adapt v0.2.7 h1:/Lc7xODdqcEw8IrZ9SvwnlLX6j9FHQM74z6cBk9Rw6M= +cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc= +cloud.google.com/go/auth v0.14.1 h1:AwoJbzUdxA/whv1qj3TLKwh3XX5sikny2fc40wUl+h0= +cloud.google.com/go/auth/oauth2adapt v0.2.7 h1:/Lc7xODdqcEw8IrZ9SvwnlLX6j9FHQM74z6cBk9Rw6M= cloud.google.com/go/compute v1.23.4 h1:EBT9Nw4q3zyE7G45Wvv3MzolIrCJEuHys5muLY0wvAw= cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= @@ -106,8 +108,9 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= -github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= +github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= +github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= +github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= @@ -387,12 +390,15 @@ golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhS golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gonum.org/v1/gonum v0.15.1 h1:FNy7N6OUZVUaWG9pTiD+jlhdQ3lMP+/LcTpJ6+a8sQ0= gonum.org/v1/gonum v0.15.1/go.mod h1:eZTZuRFrzu5pcyjN5wJhcIhnUdNijYxX1T2IcrOGY0o= -google.golang.org/api v0.216.0 h1:xnEHy+xWFrtYInWPy8OdGFsyIfWJjtVnO39g7pz2BFY= -google.golang.org/api v0.216.0/go.mod h1:K9wzQMvWi47Z9IU7OgdOofvZuw75Ge3PPITImZR/UyI= -google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f h1:gap6+3Gk41EItBuyi4XX/bp4oqJ3UwuIMl25yGinuAA= -google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:Ic02D47M+zbarjYYUlK57y316f2MoN0gjAwI3f2S95o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= +google.golang.org/api v0.220.0 h1:3oMI4gdBgB72WFVwE1nerDD8W3HUOS4kypK6rRLbGns= +google.golang.org/api v0.220.0/go.mod h1:26ZAlY6aN/8WgpCzjPNy18QpYaz7Zgg1h0qe1GkZEmY= +google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 h1:5iw9XJTD4thFidQmFVvx0wi4g5yOHk76rNRUxz1ZG5g= +google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47/go.mod h1:AfA77qWLcidQWywD0YgqfpJzf50w2VjzBml3TybHeJU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 h1:2duwAxN2+k0xLNpjnHTXoMUgnv6VPSp5fiqTuwSxjmI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk= +google.golang.org/api v0.220.0 h1:3oMI4gdBgB72WFVwE1nerDD8W3HUOS4kypK6rRLbGns= +google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 h1:5iw9XJTD4thFidQmFVvx0wi4g5yOHk76rNRUxz1ZG5g= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 h1:2duwAxN2+k0xLNpjnHTXoMUgnv6VPSp5fiqTuwSxjmI= google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= diff --git a/pkg/services/sqlstore/database_config.go b/pkg/services/sqlstore/database_config.go index 171ff4972b9..e3cc626066a 100644 --- a/pkg/services/sqlstore/database_config.go +++ b/pkg/services/sqlstore/database_config.go @@ -203,6 +203,8 @@ func (dbCfg *DatabaseConfig) buildConnectionString(cfg *setting.Cfg, features fe } cnnstr += buildExtraConnectionString('&', dbCfg.UrlQueryParams) + case migrator.Spanner: + cnnstr = dbCfg.Name default: return fmt.Errorf("unknown database type: %s", dbCfg.Type) } diff --git a/pkg/services/sqlstore/migrator/migrations.go b/pkg/services/sqlstore/migrator/migrations.go index b26e68fd12f..025c2b36d32 100644 --- a/pkg/services/sqlstore/migrator/migrations.go +++ b/pkg/services/sqlstore/migrator/migrations.go @@ -85,6 +85,10 @@ func (m *RawSQLMigration) Mssql(sql string) *RawSQLMigration { return m.Set(MSSQL, sql) } +func (m *RawSQLMigration) Spanner(sql string) *RawSQLMigration { + return m.Set(Spanner, sql) +} + type AddColumnMigration struct { MigrationBase tableName string diff --git a/pkg/services/sqlstore/migrator/migrator.go b/pkg/services/sqlstore/migrator/migrator.go index cdf5603cf31..73fd3fab4f2 100644 --- a/pkg/services/sqlstore/migrator/migrator.go +++ b/pkg/services/sqlstore/migrator/migrator.go @@ -400,6 +400,11 @@ func (mg *Migrator) InTransaction(callback dbTransactionFunc) error { sess := mg.DBEngine.NewSession() defer sess.Close() + // XXX: Spanner cannot execute DDL statements in transactions + if mg.Dialect.DriverName() == Spanner { + return callback(sess) + } + if err := sess.Begin(); err != nil { return err } diff --git a/pkg/services/sqlstore/migrator/spanner_dialect.go b/pkg/services/sqlstore/migrator/spanner_dialect.go new file mode 100644 index 00000000000..47d2fc001d5 --- /dev/null +++ b/pkg/services/sqlstore/migrator/spanner_dialect.go @@ -0,0 +1,84 @@ +//go:build enterprise || pro + +package migrator + +import ( + "errors" + "fmt" + + "cloud.google.com/go/spanner" + "google.golang.org/grpc/codes" + "xorm.io/core" +) + +type SpannerDialect struct { + BaseDialect + d core.Dialect +} + +func init() { + supportedDialects[Spanner] = NewSpannerDialect +} + +func NewSpannerDialect() Dialect { + d := SpannerDialect{d: core.QueryDialect(Spanner)} + d.BaseDialect.dialect = &d + d.BaseDialect.driverName = Spanner + return &d +} + +func (s *SpannerDialect) AutoIncrStr() string { return s.d.AutoIncrStr() } +func (s *SpannerDialect) Quote(name string) string { return s.d.Quote(name) } +func (s *SpannerDialect) SupportEngine() bool { return s.d.SupportEngine() } +func (s *SpannerDialect) IndexCheckSQL(tableName, indexName string) (string, []any) { + return s.d.IndexCheckSql(tableName, indexName) +} +func (s *SpannerDialect) SQLType(col *Column) string { + c := core.NewColumn(col.Name, "", core.SQLType{Name: col.Type}, col.Length, col.Length2, col.Nullable) + return s.d.SqlType(c) +} + +func (s *SpannerDialect) BatchSize() int { return 1000 } +func (s *SpannerDialect) BooleanStr(b bool) string { + if b { + return "true" + } + return "false" +} +func (s *SpannerDialect) ErrorMessage(err error) string { + return spanner.ErrDesc(spanner.ToSpannerError(err)) +} +func (s *SpannerDialect) IsDeadlock(err error) bool { + return spanner.ErrCode(spanner.ToSpannerError(err)) == codes.Aborted +} +func (s *SpannerDialect) IsUniqueConstraintViolation(err error) bool { + return spanner.ErrCode(spanner.ToSpannerError(err)) == codes.AlreadyExists +} + +func (s *SpannerDialect) CreateTableSQL(table *Table) string { + t := core.NewEmptyTable() + t.Name = table.Name + t.PrimaryKeys = table.PrimaryKeys + for _, c := range table.Columns { + t.AddColumn(core.NewColumn(c.Name, c.Name, core.SQLType{Name: c.Type}, c.Length, c.Length2, c.Nullable)) + } + return s.d.CreateTableSql(t, t.Name, "", "") +} + +func (s *SpannerDialect) CreateIndexSQL(tableName string, index *Index) string { + idx := core.NewIndex(index.Name, index.Type) + idx.Cols = index.Cols + return s.d.CreateIndexSql(tableName, idx) +} + +func (s *SpannerDialect) UpsertMultipleSQL(tableName string, keyCols, updateCols []string, count int) (string, error) { + return "", errors.New("not supported") +} + +func (s *SpannerDialect) DropIndexSQL(tableName string, index *Index) string { + return fmt.Sprintf("DROP INDEX %v", s.Quote(index.XName(tableName))) +} + +func (s *SpannerDialect) DropTable(tableName string) string { + return fmt.Sprintf("DROP TABLE %s", s.Quote(tableName)) +} diff --git a/pkg/services/sqlstore/migrator/types.go b/pkg/services/sqlstore/migrator/types.go index b923a8fa9ac..095c4a9224e 100644 --- a/pkg/services/sqlstore/migrator/types.go +++ b/pkg/services/sqlstore/migrator/types.go @@ -12,6 +12,7 @@ const ( SQLite = "sqlite3" MySQL = "mysql" MSSQL = "mssql" + Spanner = "spanner" ) type Migration interface { diff --git a/pkg/storage/unified/apistore/go.mod b/pkg/storage/unified/apistore/go.mod index 30a247fd9ed..7eabff03b79 100644 --- a/pkg/storage/unified/apistore/go.mod +++ b/pkg/storage/unified/apistore/go.mod @@ -31,12 +31,14 @@ require ( require ( cel.dev/expr v0.19.0 // indirect - cloud.google.com/go v0.116.0 // indirect - cloud.google.com/go/auth v0.13.0 // indirect - cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect + cloud.google.com/go v0.118.2 // indirect + cloud.google.com/go/auth v0.14.1 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.7 // indirect cloud.google.com/go/compute/metadata v0.6.0 // indirect - cloud.google.com/go/iam v1.2.1 // indirect - cloud.google.com/go/storage v1.43.0 // indirect + cloud.google.com/go/iam v1.3.1 // indirect + cloud.google.com/go/monitoring v1.23.0 // indirect + cloud.google.com/go/spanner v1.75.0 // indirect + cloud.google.com/go/storage v1.50.0 // indirect dario.cat/mergo v1.0.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 // indirect @@ -48,6 +50,10 @@ require ( github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2 // indirect github.com/BurntSushi/toml v1.4.0 // indirect + github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.2 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0 // indirect github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver v1.5.0 // indirect @@ -119,6 +125,7 @@ require ( github.com/cheekybits/genny v1.0.0 // indirect github.com/chromedp/cdproto v0.0.0-20240810084448-b931b754e476 // indirect github.com/cloudflare/circl v1.3.7 // indirect + github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 // indirect github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect @@ -137,6 +144,7 @@ require ( github.com/elazarl/goproxy v1.7.1 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect + github.com/envoyproxy/go-control-plane/envoy v1.32.3 // indirect github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect github.com/fatih/color v1.17.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -186,7 +194,7 @@ require ( github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/s2a-go v0.1.8 // indirect + github.com/google/s2a-go v0.1.9 // indirect github.com/google/wire v0.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect github.com/googleapis/gax-go/v2 v2.14.1 // indirect @@ -300,6 +308,7 @@ require ( github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/pressly/goose/v3 v3.24.0 // indirect github.com/prometheus/alertmanager v0.27.0 // indirect @@ -349,6 +358,7 @@ require ( go.mongodb.org/mongo-driver v1.16.1 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/detectors/gcp v1.33.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.59.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect @@ -360,6 +370,7 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 // indirect go.opentelemetry.io/otel/metric v1.34.0 // indirect go.opentelemetry.io/otel/sdk v1.34.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.32.0 // indirect go.opentelemetry.io/otel/trace v1.34.0 // indirect go.opentelemetry.io/proto/otlp v1.5.0 // indirect go.uber.org/atomic v1.11.0 // indirect @@ -378,10 +389,10 @@ require ( golang.org/x/tools v0.29.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect gonum.org/v1/gonum v0.15.1 // indirect - google.golang.org/api v0.216.0 // indirect - google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect + google.golang.org/api v0.220.0 // indirect + google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 // indirect google.golang.org/protobuf v1.36.5 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect diff --git a/pkg/storage/unified/apistore/go.sum b/pkg/storage/unified/apistore/go.sum index 6a18c347c14..9a68c6083f1 100644 --- a/pkg/storage/unified/apistore/go.sum +++ b/pkg/storage/unified/apistore/go.sum @@ -6,6 +6,7 @@ cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7h cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= @@ -16,37 +17,606 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= -cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= -cloud.google.com/go/auth v0.13.0 h1:8Fu8TZy167JkW8Tj3q7dIkr2v4cndv41ouecJx0PAHs= -cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q= -cloud.google.com/go/auth/oauth2adapt v0.2.6 h1:V6a6XDu2lTwPZWOawrAa9HUK+DB2zfJyTuciBG5hFkU= -cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= +cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go v0.118.2 h1:bKXO7RXMFDkniAAvvuMrAPtQ/VHrs9e7J5UT3yrGdTY= +cloud.google.com/go v0.118.2/go.mod h1:CFO4UPEPi8oV21xoezZCrd3d81K4fFkDTEJu4R8K+9M= +cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= +cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= +cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/accesscontextmanager v1.7.0/go.mod h1:CEGLewx8dwa33aDAZQujl7Dx+uYhS0eay198wB/VumQ= +cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= +cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= +cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/aiplatform v1.36.1/go.mod h1:WTm12vJRPARNvJ+v6P52RDHCNe4AhvjcIZ/9/RRHy/k= +cloud.google.com/go/aiplatform v1.37.0/go.mod h1:IU2Cv29Lv9oCn/9LkFiiuKfwrRTq+QQMbW+hPCxJGZw= +cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= +cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= +cloud.google.com/go/analytics v0.17.0/go.mod h1:WXFa3WSym4IZ+JiKmavYdJwGG/CvpqiqczmL59bTD9M= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/analytics v0.19.0/go.mod h1:k8liqf5/HCnOUkbawNtrWWc+UAzyDlW89doe8TtoDsE= +cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= +cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= +cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apigeeregistry v0.6.0/go.mod h1:BFNzW7yQVLZ3yj0TKcwzb8n25CFBri51GVGOEUcgQsc= +cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/apikeys v0.6.0/go.mod h1:kbpXu5upyiAlGkKrJgQl8A0rKNNJ7dQ377pdroRSSi8= +cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= +cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/appengine v1.7.0/go.mod h1:eZqpbHFCqRGa2aCdope7eC0SWLV1j0neb/QnMJVWx6A= +cloud.google.com/go/appengine v1.7.1/go.mod h1:IHLToyb/3fKutRysUlFO0BPt5j7RiQ45nrzEJmKTo6E= +cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= +cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= +cloud.google.com/go/area120 v0.7.0/go.mod h1:a3+8EUD1SX5RUcCs3MY5YasiO1z6yLiNLRiFrykbynY= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= +cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= +cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= +cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= +cloud.google.com/go/artifactregistry v1.11.1/go.mod h1:lLYghw+Itq9SONbCa1YWBoWs1nOucMH0pwXN1rOBZFI= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/artifactregistry v1.12.0/go.mod h1:o6P3MIvtzTOnmvGagO9v/rOjjA0HmhJ+/6KAXrmYDCI= +cloud.google.com/go/artifactregistry v1.13.0/go.mod h1:uy/LNfoOIivepGhooAUpL1i30Hgee3Cu0l4VTWHUC08= +cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= +cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= +cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= +cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= +cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/asset v1.12.0/go.mod h1:h9/sFOa4eDIyKmH6QMpm4eUK3pDojWnUhTgJlk762Hg= +cloud.google.com/go/asset v1.13.0/go.mod h1:WQAMyYek/b7NBpYq/K4KJWcRqzoalEsxz/t/dTk4THw= +cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= +cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= +cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= +cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= +cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/auth v0.14.1 h1:AwoJbzUdxA/whv1qj3TLKwh3XX5sikny2fc40wUl+h0= +cloud.google.com/go/auth v0.14.1/go.mod h1:4JHUxlGXisL0AW8kXPtUF6ztuOksyfUQNFjfsOCXkPM= +cloud.google.com/go/auth/oauth2adapt v0.2.7 h1:/Lc7xODdqcEw8IrZ9SvwnlLX6j9FHQM74z6cBk9Rw6M= +cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc= +cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= +cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= +cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= +cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= +cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= +cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= +cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/beyondcorp v0.5.0/go.mod h1:uFqj9X+dSfrheVp7ssLTaRHd2EHqSL4QZmH4e8WXGGU= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= +cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= +cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= +cloud.google.com/go/bigquery v1.47.0/go.mod h1:sA9XOgy0A8vQK9+MWhEQTY6Tix87M/ZurWFIxmF9I/E= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/bigquery v1.49.0/go.mod h1:Sv8hMmTFFYBlt/ftw2uN6dFdQPzBlREY9yBh7Oy7/4Q= +cloud.google.com/go/bigquery v1.50.0/go.mod h1:YrleYEh2pSEbgTBZYMJ5SuSr0ML3ypjRB1zgf7pvQLU= +cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= +cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= +cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= +cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/billing v1.13.0/go.mod h1:7kB2W9Xf98hP9Sr12KfECgfGclsH3CQR0R08tnRlRbc= +cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= +cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= +cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= +cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= +cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= +cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/channel v1.12.0/go.mod h1:VkxCGKASi4Cq7TbXxlaBezonAYpp1GCnKMY6tnMQnLU= +cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= +cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= +cloud.google.com/go/cloudbuild v1.6.0/go.mod h1:UIbc/w9QCbH12xX+ezUsgblrWv+Cv4Tw83GiSMHOn9M= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/cloudbuild v1.9.0/go.mod h1:qK1d7s4QlO0VwfYn5YuClDGg2hfmLZEb4wQGAbIgL1s= +cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= +cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= +cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= +cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= +cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/cloudtasks v1.10.0/go.mod h1:NDSoTLkZ3+vExFEWu2UJV1arUyzVDAiZtdWcsUyNwBs= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= +cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= +cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= +cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= +cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= +cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= +cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= +cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= +cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/container v1.14.0/go.mod h1:3AoJMPhHfLDxLvrlVWaK57IXzaPnLaZq63WX59aQBfM= +cloud.google.com/go/container v1.15.0/go.mod h1:ft+9S0WGjAyjDggg5S06DXj+fHJICWg8L7isCQe9pQA= +cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= +cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/containeranalysis v0.9.0/go.mod h1:orbOANbwk5Ejoom+s+DUCTTJ7IBdBQJDcSylAx/on9s= +cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= +cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= +cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= +cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= +cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= +cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/datacatalog v1.13.0/go.mod h1:E4Rj9a5ZtAxcQJlEBTLgMTphfP11/lNaAshpoBgemX8= +cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= +cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= +cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= +cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/dataform v0.7.0/go.mod h1:7NulqnVozfHvWUBpMDfKMUESr+85aJsC/2O0o3jWPDE= +cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= +cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= +cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= +cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataplex v1.6.0/go.mod h1:bMsomC/aEJOSpHXdFKFGQ1b0TDPIeL28nJObeO1ppRs= +cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= +cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= +cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/iam v1.2.1 h1:QFct02HRb7H12J/3utj0qf5tobFh9V4vR6h9eX5EBRU= -cloud.google.com/go/iam v1.2.1/go.mod h1:3VUIJDPpwT6p/amXRC5GY8fCCh70lxPygguVtI0Z4/g= -cloud.google.com/go/longrunning v0.6.1 h1:lOLTFxYpr8hcRtcwWir5ITh1PAKUD/sG2lKrTSYjyMc= -cloud.google.com/go/longrunning v0.6.1/go.mod h1:nHISoOZpBcmlwbJmiVk5oDRz0qG/ZxPynEGs1iZ79s0= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastore v1.11.0/go.mod h1:TvGxBIHCS50u8jzG+AW/ppf87v1of8nwzFNgEZU1D3c= +cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= +cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= +cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= +cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/datastream v1.7.0/go.mod h1:uxVRMm2elUSPuh65IbZpzJNMbuzkcvu5CjMqVIUHrww= +cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= +cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/deploy v1.8.0/go.mod h1:z3myEJnA/2wnB4sgjqdMfgxCA0EqC3RBTNcVPs93mtQ= +cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= +cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= +cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= +cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= +cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= +cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dialogflow v1.32.0/go.mod h1:jG9TRJl8CKrDhMEcvfcfFkkpp8ZhgPz3sBGmAUYJ2qE= +cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= +cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= +cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= +cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= +cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/documentai v1.18.0/go.mod h1:F6CK6iUH8J81FehpskRmhLq/3VlwQvb7TvwOceQ2tbs= +cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= +cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= +cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/edgecontainer v1.0.0/go.mod h1:cttArqZpBB2q58W/upSG++ooo6EsblxDIolxa3jSjbY= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= +cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= +cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/eventarc v1.11.0/go.mod h1:PyUjsUKPWoRBCHeOxZd/lbOOjahV41icXyUY5kSTvVY= +cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= +cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/filestore v1.6.0/go.mod h1:di5unNuss/qfZTw2U9nhFqo8/ZDSc466dre85Kydllg= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= +cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= +cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= +cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/functions v1.12.0/go.mod h1:AXWGrF3e2C/5ehvwYo/GH6O5s09tOPksiKhz+hH8WkA= +cloud.google.com/go/functions v1.13.0/go.mod h1:EU4O007sQm6Ef/PwRsI8N2umygGqPBS/IZQKBQBcJ3c= +cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= +cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= +cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= +cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= +cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= +cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= +cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkehub v0.12.0/go.mod h1:djiIwwzTTBrF5NaXCGv3mf7klpEMcST17VBTVVDcuaw= +cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= +cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= +cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= +cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= +cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= +cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= +cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= +cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= +cloud.google.com/go/iam v1.3.1 h1:KFf8SaT71yYq+sQtRISn90Gyhyf4X8RGgeAVC8XGf3E= +cloud.google.com/go/iam v1.3.1/go.mod h1:3wMtuyT4NcbnYNPLMBzYRFiEfjKfJlLVLrisE7bwm34= +cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= +cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/iap v1.7.0/go.mod h1:beqQx56T9O1G1yNPph+spKpNibDlYIiIixiqsQXxLIo= +cloud.google.com/go/iap v1.7.1/go.mod h1:WapEwPc7ZxGt2jFGB/C/bm+hP0Y6NXzOYGjpPnmMS74= +cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= +cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= +cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/iot v1.6.0/go.mod h1:IqdAsmE2cTYYNO1Fvjfzo9po179rAtJeVGUvkLN3rLE= +cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= +cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= +cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= +cloud.google.com/go/kms v1.8.0/go.mod h1:4xFEhYFqvW+4VMELtZyxomGSYtSQKzM178ylFW4jMAg= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24= +cloud.google.com/go/kms v1.10.1/go.mod h1:rIWk/TryCkR59GMC3YtHtXeLzd634lBbKenvyySAyYI= +cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= +cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= +cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= +cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= +cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/logging v1.13.0 h1:7j0HgAp0B94o1YRDqiqm26w4q1rDMH7XNRU34lJXHYc= +cloud.google.com/go/logging v1.13.0/go.mod h1:36CoKh6KA/M0PbhPKMq6/qety2DCAErbhXT62TuXALA= +cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= +cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/longrunning v0.6.4 h1:3tyw9rO3E2XVXzSApn1gyEEnH2K9SynNQjMlBi3uHLg= +cloud.google.com/go/longrunning v0.6.4/go.mod h1:ttZpLCe6e7EXvn9OxpBRx7kZEB0efv8yBO6YnVMfhJs= +cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= +cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/maps v0.7.0/go.mod h1:3GnvVl3cqeSvgMcpRlQidXsPYuDGQ8naBis7MVzpXsY= +cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= +cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= +cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= +cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= +cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= +cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= +cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= +cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= +cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw= +cloud.google.com/go/monitoring v1.23.0 h1:M3nXww2gn9oZ/qWN2bZ35CjolnVHM3qnSbu6srCPgjk= +cloud.google.com/go/monitoring v1.23.0/go.mod h1:034NnlQPDzrQ64G2Gavhl0LUHZs9H3rRmhtnp7jiJgg= +cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= +cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= +cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= +cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkconnectivity v1.11.0/go.mod h1:iWmDD4QF16VCDLXUqvyspJjIEtBR/4zq5hwnY2X3scM= +cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= +cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= +cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/networksecurity v0.8.0/go.mod h1:B78DkqsxFG5zRSVuwYFRZ9Xz8IcQ5iECsNrPn74hKHU= +cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= +cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= +cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= +cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/notebooks v1.8.0/go.mod h1:Lq6dYKOYOWUCTvw5t2q1gp1lAp0zxAxRycayS0iJcqQ= +cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= +cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= +cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= +cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= +cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= +cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= +cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= +cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= +cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= +cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= +cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= +cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/policytroubleshooter v1.6.0/go.mod h1:zYqaPTsmfvpjm5ULxAyD/lINQxJ0DDsnWOP/GZ7xzBc= +cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= +cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/privatecatalog v0.8.0/go.mod h1:nQ6pfaegeDAq/Q5lrfCQzQLhubPiZhSaNhIgfJlnIXs= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= +cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsub v1.30.0/go.mod h1:qWi1OPS0B+b5L+Sg6Gmc9zD1Y+HaM0MdUr7LsupY1P4= +cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/pubsublite v1.7.0/go.mod h1:8hVMwRXfDfvGm3fahVbtDbiLePT3gpoiJYJY+vxWxVM= +cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= +cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= +cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= +cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= +cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= +cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recaptchaenterprise/v2 v2.7.0/go.mod h1:19wVj/fs5RtYtynAPJdDTb69oW0vNHYDBTbB4NvMD9c= +cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= +cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= +cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= +cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= +cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= +cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= +cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= +cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= +cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcemanager v1.6.0/go.mod h1:YcpXGRs8fDzcUl1Xw8uOVmI8JEadvhRIkoXXUNVYcVo= +cloud.google.com/go/resourcemanager v1.7.0/go.mod h1:HlD3m6+bwhzj9XCouqmeiGuni95NTrExfhoSrkC/3EI= +cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= +cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= +cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= +cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= +cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= +cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/run v0.9.0/go.mod h1:Wwu+/vvg8Y+JUApMwEDfVfhetv30hCG4ZwDR/IXl2Qg= +cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= +cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= +cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= +cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/scheduler v1.9.0/go.mod h1:yexg5t+KSmqu+njTIh3b7oYPheFtBWGcbVUYF1GGMIc= +cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= +cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= +cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= +cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= +cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= +cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= +cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/security v1.13.0/go.mod h1:Q1Nvxl1PAgmeW0y3HTt54JYIvUdtcpYKVfIB8AOMZ+0= +cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= +cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= +cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= +cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/securitycenter v1.19.0/go.mod h1:LVLmSg8ZkkyaNy4u7HCIshAngSQ8EcIRREP3xBnyfag= +cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= +cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= +cloud.google.com/go/servicecontrol v1.10.0/go.mod h1:pQvyvSRh7YzUF2efw7H87V92mxU8FnFDawMClGCNuAA= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicecontrol v1.11.1/go.mod h1:aSnNNlwEFBY+PWGQ2DoM0JJ/QUXqV5/ZD9DOLB7SnUk= +cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= +cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= +cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= +cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicedirectory v1.9.0/go.mod h1:29je5JjiygNYlmsGz8k6o+OZ8vd4f//bQLtvzkPPT/s= +cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= +cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/servicemanagement v1.8.0/go.mod h1:MSS2TDlIEQD/fzsSGfCdJItQveu9NXnUniTrq/L8LK4= +cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= +cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/serviceusage v1.6.0/go.mod h1:R5wwQcbOWsyuOfbP9tGdAnCAc6B9DRwPG1xtWMDeuPA= +cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= +cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M= +cloud.google.com/go/spanner v1.75.0 h1:2zrltTJv/4P3pCgpYgde4Eb1vN8Cgy1fNy7pbTnOovg= +cloud.google.com/go/spanner v1.75.0/go.mod h1:TLFZBvPQmx3We7sGh12eTk9lLsRLczzZaiweqfMpR80= +cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= +cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= +cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= +cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/speech v1.15.0/go.mod h1:y6oH7GhqCaZANH7+Oe0BhgIogsNInLlz542tg3VqeYI= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs= -cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= +cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= +cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= +cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= +cloud.google.com/go/storage v1.50.0 h1:3TbVkzTooBvnZsk7WaAQfOsNrdoM8QHusXA1cpk6QJs= +cloud.google.com/go/storage v1.50.0/go.mod h1:l7XeiD//vx5lfqE3RavfmU9yvk5Pp0Zhcv482poyafY= +cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= +cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/storagetransfer v1.8.0/go.mod h1:JpegsHHU1eXg7lMHkvf+KE5XDJ7EQu0GwNJbbVGanEw= +cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= +cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= +cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= +cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= +cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= +cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= +cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk= +cloud.google.com/go/trace v1.11.3 h1:c+I4YFjxRQjvAhRmSsmjpASUKq88chOX854ied0K/pE= +cloud.google.com/go/trace v1.11.3/go.mod h1:pt7zCYiDSQjC9Y2oqCsh9jF4GStB/hmjrYLsxRR27q8= +cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= +cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= +cloud.google.com/go/translate v1.5.0/go.mod h1:29YDSYveqqpA1CQFD7NQuP49xymq17RXNaUDdc0mNu0= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/translate v1.7.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= +cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= +cloud.google.com/go/video v1.12.0/go.mod h1:MLQew95eTuaNDEGriQdcYn0dTwf9oWiA4uYebxM5kdg= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/video v1.14.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= +cloud.google.com/go/video v1.15.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= +cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= +cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= +cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= +cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= +cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= +cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= +cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= +cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vision/v2 v2.7.0/go.mod h1:H89VysHy21avemp6xcf9b9JvZHVehWbET0uT/bcuY/0= +cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= +cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmmigration v1.6.0/go.mod h1:bopQ/g4z+8qXzichC7GW1w2MjbErL54rk3/C843CjfY= +cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vmwareengine v0.3.0/go.mod h1:wvoyMvNWdIzxMYSpH/R7y2h5h3WFkx6d+1TIsP39WGY= +cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= +cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= +cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= +cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= +cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= +cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= +cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= +cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= +cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= cuelang.org/go v0.11.1 h1:pV+49MX1mmvDm8Qh3Za3M786cty8VKPWzQ1Ho4gZRP0= cuelang.org/go v0.11.1/go.mod h1:PBY6XvPUswPPJ2inpvUozP9mebDVTXaeehQikhZPBz0= dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= @@ -54,6 +624,8 @@ dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= +git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 h1:g0EZJwz7xkXQiZAI5xi9f3WWFYBlX1CPTrR+NDToRkQ= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0/go.mod h1:XCW7KnZet0Opnr7HccfUw1PLc4CjHqpcaxW8DHklNkQ= @@ -85,6 +657,16 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.2 h1:DBjmt6/otSdULyJdVg2BlG0qGZO5tKL4VzOs0jpvw5Q= +github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.2/go.mod h1:dppbR7CwXD4pgtV9t3wD1812RaLDcBjtblcDF5f1vI0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 h1:3c8yed4lgqTt+oTQ+JNMDo+F4xprBf+O/il4ZC0nRLw= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0/go.mod h1:obipzmGjfSjam60XLwGfqUkJsfiheAl+TUjG+4yzyPM= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0 h1:o90wcURuxekmXrtxmYWTyNla0+ZEHhud6DI1ZTxd1vI= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0/go.mod h1:6fTWu4m3jocfUZLYF5KsZC1TUfRvEjs7lM4crme/irw= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.49.0 h1:jJKWl98inONJAr/IZrdFQUWcwUO95DLY1XMD1ZIut+g= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.49.0/go.mod h1:l2fIqmwB+FKSfvn3bAD/0i+AXAxhIZjTK2svT/mgUXs= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0 h1:GYUJLfvd++4DMuMhCFLgLXvFwofIxh/qOwoGuS/LTew= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0/go.mod h1:wRbFgBQUVm1YXrvWKofAEmq9HNJTDphbAaJSSX01KUI= github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c h1:RGWPOewvKIROun94nF7v2cua9qP+thov/7M50KEoeSU= @@ -105,6 +687,7 @@ github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/RoaringBitmap/roaring v1.9.3 h1:t4EbC5qQwnisr5PrP9nt0IRhRTb9gMUgQF4t4S2OByM= @@ -115,6 +698,10 @@ github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f h1:HR5nRmUQgX github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f/go.mod h1:f3HiCrHjHBdcm6E83vGaXh1KomZMA2P6aeo3hKx/wg0= github.com/Yiling-J/theine-go v0.6.0 h1:jv7V/tcD6ijL0T4kfbJDKP81TCZBkoriNTPSqwivWuY= github.com/Yiling-J/theine-go v0.6.0/go.mod h1:mdch1vjgGWd7s3rWKvY+MF5InRLfRv/CWVI9RVNQ8wY= +github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= +github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -122,13 +709,18 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0= github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= github.com/apache/arrow-go/v18 v18.0.1-0.20241212180703-82be143d7c30 h1:hXVi7QKuCQ0E8Yujfu9b0f0RnzZ72efpWvPnZgnJPrE= github.com/apache/arrow-go/v18 v18.0.1-0.20241212180703-82be143d7c30/go.mod h1:RNuWDIiGjq5nndL2PyQrndUy9nMLwheA3uWaAV7fe4U= +github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= +github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= github.com/apache/thrift v0.21.0 h1:tdPmh/ptjE1IJnhbhrcl2++TauVjy242rkV/UzJChnE= github.com/apache/thrift v0.21.0/go.mod h1:W1H8aR/QRtYNvrPeFXBtobyRkd0/YVhTc6i07XIAgDw= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= @@ -237,6 +829,8 @@ github.com/blevesearch/zapx/v15 v15.3.16/go.mod h1:Turk/TNRKj9es7ZpKK95PS7f6D44Y github.com/blevesearch/zapx/v16 v16.1.8 h1:Bxzpw6YQpFs7UjoCV1+RvDw6fmAT2GZxldwX8b3wVBM= github.com/blevesearch/zapx/v16 v16.1.8/go.mod h1:JqQlOqlRVaYDkpLIl3JnKql8u4zKTNlVEa3nLsi0Gn8= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 h1:N7oVaKyGp8bttX0bfZGmcGkjz7DLQXhAn3DNd3T0ous= github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= @@ -249,7 +843,11 @@ github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= @@ -266,7 +864,20 @@ github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUK github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 h1:QVw89YDxXxEe+l8gU8ETbOasdwEV+avkR75ZzsVV9WI= +github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= @@ -281,6 +892,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cznic/b v0.0.0-20180115125044-35e9bbe41f07/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8= github.com/cznic/fileutil v0.0.0-20180108211300-6a051e75936f/go.mod h1:8S58EK26zhXSxzv7NQFpnliaOQsmDUxvoQO3rt154Vg= github.com/cznic/golex v0.0.0-20170803123110-4ab7c5e190e4/go.mod h1:+bmmJDNmKlhWNG+gwWCkaBoTy39Fs+bzRxVBzoTQbIc= @@ -318,6 +930,7 @@ github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6 github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2 h1:u3PMzfF8RkKd3lB9pZ2bfn0qEG+1Gms9599cr0REMww= github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2/go.mod h1:mIEZOHnFx4ZMQeawhw9rhsj+0zwQj7adVsnBX7t+eKY= github.com/dolthub/go-icu-regex v0.0.0-20241215010122-db690dd53c90 h1:Sni8jrP0sy/w9ZYXoff4g/ixe+7bFCZlfCqXKJSU+zM= @@ -328,6 +941,7 @@ github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 h1:bMGS25NWAGTE github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71/go.mod h1:2/2zjLQ/JOOSbbSboojeg+cAwcRV0fDLzIiWch/lhqI= github.com/dolthub/vitess v0.0.0-20250123002143-3b45b8cacbfa h1:kyoPzxViSXAyqfO0Mab7Qo1UogFIrxZKKyBU6kBOl+E= github.com/dolthub/vitess v0.0.0-20250123002143-3b45b8cacbfa/go.mod h1:1gQZs/byeHLMSul3Lvl3MzioMtOW1je79QYGyi2fd70= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= @@ -343,8 +957,27 @@ github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FM github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q= +github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= +github.com/envoyproxy/go-control-plane v0.13.4/go.mod h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA= +github.com/envoyproxy/go-control-plane/envoy v1.32.3 h1:hVEaommgvzTjTd4xCaFd+kEQ2iYBtGxP6luyLrx6uOk= +github.com/envoyproxy/go-control-plane/envoy v1.32.3/go.mod h1:F6hWupPfh75TBXGKA++MCT/CZHFq5r9/uwt/kQYkZfE= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= +github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= +github.com/envoyproxy/go-control-plane/envoy v1.32.3 h1:hVEaommgvzTjTd4xCaFd+kEQ2iYBtGxP6luyLrx6uOk= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= @@ -354,6 +987,8 @@ github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -368,8 +1003,14 @@ github.com/gchaincl/sqlhooks v1.3.0 h1:yKPXxW9a5CjXaVf2HkQn6wn7TZARvbAOAelr3H8vK github.com/gchaincl/sqlhooks v1.3.0/go.mod h1:9BypXnereMT0+Ys8WGWHqzgkkOfHIhyeUCqXC24ra34= github.com/getkin/kin-openapi v0.129.0 h1:QGYTNcmyP5X0AtFQ2Dkou9DGBJsUETeLH9rFrJXZh30= github.com/getkin/kin-openapi v0.129.0/go.mod h1:gmWI+b/J45xqpyK5wJmRRZse5wefA5H0RDMK46kLUtI= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= +github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= +github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -380,6 +1021,8 @@ github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= +github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= github.com/go-ldap/ldap/v3 v3.4.4 h1:qPjipEpt+qDa6SI/h1fzuGWoRUY+qqQ9sOZq67/PYUs= github.com/go-ldap/ldap/v3 v3.4.4/go.mod h1:fe1MsuN5eJJ1FeLT/LEBVdWfNWKh459R7aXgXtJC+aI= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -415,6 +1058,8 @@ github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+Gr github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58= github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ= +github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -432,6 +1077,7 @@ github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM= github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0= @@ -454,9 +1100,12 @@ github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17w github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-migrate/migrate/v4 v4.7.0 h1:gONcHxHApDTKXDyLH/H97gEHmpu1zcnnbAaq2zgrPrs= github.com/golang-migrate/migrate/v4 v4.7.0/go.mod h1:Qvut3N4xKWjoH3sokBccML6WyHSnggXm/DvMMnTsQIc= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 h1:gtexQ/VGyN+VVFRXSFiguSNcXmS6rkKT+X7FdIrTtfo= github.com/golang/geo v0.0.0-20210211234256-740aa86cb551/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -469,6 +1118,8 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U= github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -486,11 +1137,15 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -499,6 +1154,7 @@ github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/cel-go v0.22.1 h1:AfVXx3chM2qwoSbM7Da8g8hX8OVSkBFwX+rz2+PcK40= github.com/google/cel-go v0.22.1/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8= +github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI= github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= @@ -514,6 +1170,9 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= @@ -532,6 +1191,9 @@ github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -541,23 +1203,48 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= -github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= +github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= +github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI= github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= +github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= +github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= +github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q= github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= @@ -611,6 +1298,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a534 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340/go.mod h1:3bDW6wMZJB7tiONtC/1Xpicra6Wp5GgbTbQWCbI5fkc= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg= github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= @@ -657,7 +1346,9 @@ github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbg github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E= @@ -711,7 +1402,10 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs= github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= @@ -719,15 +1413,20 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4= github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -749,6 +1448,9 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= @@ -773,6 +1475,7 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -890,15 +1593,24 @@ github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNH github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= +github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= +github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -922,6 +1634,7 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1: github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= @@ -954,12 +1667,16 @@ github.com/prometheus/sigv4 v0.1.0/go.mod h1:doosPW9dOitMzYe2I2BN0jZqUuBrGPbXrNs github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E= github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= @@ -967,6 +1684,8 @@ github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= +github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= @@ -999,6 +1718,10 @@ github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= @@ -1021,11 +1744,13 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= @@ -1073,6 +1798,7 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= @@ -1107,10 +1833,14 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/detectors/gcp v1.33.0 h1:FVPoXEoILwgbZUu4X7YSgsESsAmGRgoYcnXkzgQPhP4= +go.opentelemetry.io/contrib/detectors/gcp v1.33.0/go.mod h1:ZHrLmr4ikK2AwRj9QL+c9s2SOlgoSRyMpNVzUj2fZqI= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 h1:rgMkmiGfix9vFJDcDi1PK8WEQP4FLQwLDfhp5ZLpFeE= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.59.0 h1:iQZYNQ7WwIcYXzOPR46FQv9O0dS1PW16RjvR0TjDOe8= @@ -1130,6 +1860,8 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glB go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 h1:tgJ0uaNS4c98WRNUEx5U3aDlrDOI5Rs+1Vifcw4DJ8U= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0/go.mod h1:U7HYyW0zt/a9x5J1Kjs+r1f/d4ZHnYFclhYY2+YbeoE= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0 h1:WDdP9acbMYjbKIyJUhTvtzj601sVJOqgWdUxSdR/Ysc= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0/go.mod h1:BLbf7zbNIONBLPwvFnwNHGj4zge8uTCM/UPIVW1Mq2I= go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= @@ -1141,6 +1873,9 @@ go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRY go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -1165,10 +1900,13 @@ golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= @@ -1177,20 +1915,36 @@ golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1m golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1201,6 +1955,8 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -1209,9 +1965,15 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= @@ -1252,15 +2014,38 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= @@ -1273,7 +2058,30 @@ golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= +golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= +golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1287,7 +2095,10 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= @@ -1333,28 +2144,63 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= @@ -1365,8 +2211,11 @@ golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= @@ -1378,9 +2227,14 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= @@ -1391,12 +2245,17 @@ golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -1412,6 +2271,7 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1440,10 +2300,26 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE= @@ -1452,10 +2328,22 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= +gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= +gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= gonum.org/v1/gonum v0.15.1 h1:FNy7N6OUZVUaWG9pTiD+jlhdQ3lMP+/LcTpJ6+a8sQ0= gonum.org/v1/gonum v0.15.1/go.mod h1:eZTZuRFrzu5pcyjN5wJhcIhnUdNijYxX1T2IcrOGY0o= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= +gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= @@ -1474,8 +2362,49 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.216.0 h1:xnEHy+xWFrtYInWPy8OdGFsyIfWJjtVnO39g7pz2BFY= -google.golang.org/api v0.216.0/go.mod h1:K9wzQMvWi47Z9IU7OgdOofvZuw75Ge3PPITImZR/UyI= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= +google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= +google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= +google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= +google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= +google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= +google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= +google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= +google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= +google.golang.org/api v0.220.0 h1:3oMI4gdBgB72WFVwE1nerDD8W3HUOS4kypK6rRLbGns= +google.golang.org/api v0.220.0/go.mod h1:26ZAlY6aN/8WgpCzjPNy18QpYaz7Zgg1h0qe1GkZEmY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1484,6 +2413,7 @@ google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1510,18 +2440,121 @@ google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU= -google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4= -google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f h1:gap6+3Gk41EItBuyi4XX/bp4oqJ3UwuIMl25yGinuAA= -google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:Ic02D47M+zbarjYYUlK57y316f2MoN0gjAwI3f2S95o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= +google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= +google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= +google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= +google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA= +google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= +google.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= +google.golang.org/genproto v0.0.0-20230303212802-e74f57abe488/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4 h1:Pw6WnI9W/LIdRxqK7T6XGugGbHIRl5Q7q3BssH6xk4s= +google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4/go.mod h1:qbZzneIOXSq+KFAFut9krLfRLZiFLzZL5u2t8SV83EE= +google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 h1:5iw9XJTD4thFidQmFVvx0wi4g5yOHk76rNRUxz1ZG5g= +google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47/go.mod h1:AfA77qWLcidQWywD0YgqfpJzf50w2VjzBml3TybHeJU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 h1:2duwAxN2+k0xLNpjnHTXoMUgnv6VPSp5fiqTuwSxjmI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -1537,10 +2570,38 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= +google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1553,6 +2614,11 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= @@ -1583,6 +2649,7 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1602,6 +2669,7 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= k8s.io/api v0.32.1 h1:f562zw9cy+GvXzXf0CKlVQ7yHJVYzLfL6JAS4kOAaOc= k8s.io/api v0.32.1/go.mod h1:/Yi/BqkuueW1BgpoePYBRdDYfjPF5sgTr5+YqDZra5k= k8s.io/apimachinery v0.32.1 h1:683ENpaCBjma4CYqsmZyhEzrGz6cjn1MY/X2jB2hkZs= @@ -1622,33 +2690,67 @@ k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJ k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ= modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ= +modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= +modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= +modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= +modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= modernc.org/ccgo/v4 v4.19.2 h1:lwQZgvboKD0jBwdaeVCTouxhxAyN6iawF3STraAal8Y= modernc.org/ccgo/v4 v4.19.2/go.mod h1:ysS3mxiMV38XGRTTcgo0DQTeTmAO4oCmJl1nX9VFI3s= +modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw= modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI= modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= +modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= +modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= +modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= +modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= +modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= +modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U= modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w= +modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= +modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= +modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= modernc.org/sqlite v1.34.4 h1:sjdARozcL5KJBvYQvLlZEmctRgW9xqIZc2ncN7PU0P8= modernc.org/sqlite v1.34.4/go.mod h1:3QQFCG2SEMtc2nv+Wq4cQCH7Hjcg+p/RMlS1XK+zwbk= +modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= +modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= +modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= +modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 h1:CPT0ExVicCzcpeN4baWEV2ko2Z/AsiZgEdwgcfwLgMo= diff --git a/pkg/storage/unified/resource/go.mod b/pkg/storage/unified/resource/go.mod index 5fe39d78291..6d3c7466b6c 100644 --- a/pkg/storage/unified/resource/go.mod +++ b/pkg/storage/unified/resource/go.mod @@ -33,12 +33,15 @@ require ( ) require ( - cloud.google.com/go v0.116.0 // indirect - cloud.google.com/go/auth v0.13.0 // indirect - cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect + cel.dev/expr v0.19.0 // indirect + cloud.google.com/go v0.118.2 // indirect + cloud.google.com/go/auth v0.14.1 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.7 // indirect cloud.google.com/go/compute/metadata v0.6.0 // indirect - cloud.google.com/go/iam v1.2.1 // indirect - cloud.google.com/go/storage v1.43.0 // indirect + cloud.google.com/go/iam v1.3.1 // indirect + cloud.google.com/go/monitoring v1.23.0 // indirect + cloud.google.com/go/spanner v1.75.0 // indirect + cloud.google.com/go/storage v1.50.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.1 // indirect @@ -48,6 +51,10 @@ require ( github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2 // indirect github.com/BurntSushi/toml v1.4.0 // indirect + github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.2 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0 // indirect github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f // indirect github.com/apache/arrow-go/v18 v18.0.1-0.20241212180703-82be143d7c30 // indirect github.com/armon/go-metrics v0.4.1 // indirect @@ -76,14 +83,18 @@ require ( github.com/bufbuild/protocompile v0.4.0 // indirect github.com/bwmarrin/snowflake v0.3.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cheekybits/genny v1.0.0 // indirect github.com/chromedp/cdproto v0.0.0-20240810084448-b931b754e476 // indirect + github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/elazarl/goproxy v1.7.1 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/envoyproxy/go-control-plane v0.13.1 // indirect + github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect github.com/fatih/color v1.17.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect @@ -112,7 +123,7 @@ require ( github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/s2a-go v0.1.8 // indirect + github.com/google/s2a-go v0.1.9 // indirect github.com/google/wire v0.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect github.com/googleapis/gax-go/v2 v2.14.1 // indirect @@ -181,6 +192,7 @@ require ( github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/alertmanager v0.27.0 // indirect github.com/prometheus/client_model v0.6.1 // indirect @@ -205,6 +217,7 @@ require ( github.com/zeebo/xxh3 v1.0.2 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/detectors/gcp v1.33.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.59.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect @@ -215,6 +228,7 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 // indirect go.opentelemetry.io/otel/metric v1.34.0 // indirect go.opentelemetry.io/otel/sdk v1.34.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.32.0 // indirect go.opentelemetry.io/proto/otlp v1.5.0 // indirect go.uber.org/atomic v1.11.0 // indirect golang.org/x/crypto v0.35.0 // indirect @@ -228,10 +242,10 @@ require ( golang.org/x/time v0.9.0 // indirect golang.org/x/tools v0.29.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect - google.golang.org/api v0.216.0 // indirect - google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect + google.golang.org/api v0.220.0 // indirect + google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 // indirect gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/pkg/storage/unified/resource/go.sum b/pkg/storage/unified/resource/go.sum index 656e395e5b9..65c6a8c7583 100644 --- a/pkg/storage/unified/resource/go.sum +++ b/pkg/storage/unified/resource/go.sum @@ -1,26 +1,631 @@ +cel.dev/expr v0.19.0 h1:lXuo+nDhpyJSpWxpPVi5cPUwzKb+dsdOiw6IreM5yt0= +cel.dev/expr v0.19.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= -cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= -cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= -cloud.google.com/go/auth v0.13.0 h1:8Fu8TZy167JkW8Tj3q7dIkr2v4cndv41ouecJx0PAHs= -cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q= -cloud.google.com/go/auth/oauth2adapt v0.2.6 h1:V6a6XDu2lTwPZWOawrAa9HUK+DB2zfJyTuciBG5hFkU= -cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= +cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go v0.118.2 h1:bKXO7RXMFDkniAAvvuMrAPtQ/VHrs9e7J5UT3yrGdTY= +cloud.google.com/go v0.118.2/go.mod h1:CFO4UPEPi8oV21xoezZCrd3d81K4fFkDTEJu4R8K+9M= +cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= +cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= +cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/accesscontextmanager v1.7.0/go.mod h1:CEGLewx8dwa33aDAZQujl7Dx+uYhS0eay198wB/VumQ= +cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= +cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= +cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/aiplatform v1.36.1/go.mod h1:WTm12vJRPARNvJ+v6P52RDHCNe4AhvjcIZ/9/RRHy/k= +cloud.google.com/go/aiplatform v1.37.0/go.mod h1:IU2Cv29Lv9oCn/9LkFiiuKfwrRTq+QQMbW+hPCxJGZw= +cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= +cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= +cloud.google.com/go/analytics v0.17.0/go.mod h1:WXFa3WSym4IZ+JiKmavYdJwGG/CvpqiqczmL59bTD9M= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/analytics v0.19.0/go.mod h1:k8liqf5/HCnOUkbawNtrWWc+UAzyDlW89doe8TtoDsE= +cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= +cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= +cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apigeeregistry v0.6.0/go.mod h1:BFNzW7yQVLZ3yj0TKcwzb8n25CFBri51GVGOEUcgQsc= +cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/apikeys v0.6.0/go.mod h1:kbpXu5upyiAlGkKrJgQl8A0rKNNJ7dQ377pdroRSSi8= +cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= +cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/appengine v1.7.0/go.mod h1:eZqpbHFCqRGa2aCdope7eC0SWLV1j0neb/QnMJVWx6A= +cloud.google.com/go/appengine v1.7.1/go.mod h1:IHLToyb/3fKutRysUlFO0BPt5j7RiQ45nrzEJmKTo6E= +cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= +cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= +cloud.google.com/go/area120 v0.7.0/go.mod h1:a3+8EUD1SX5RUcCs3MY5YasiO1z6yLiNLRiFrykbynY= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= +cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= +cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= +cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= +cloud.google.com/go/artifactregistry v1.11.1/go.mod h1:lLYghw+Itq9SONbCa1YWBoWs1nOucMH0pwXN1rOBZFI= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/artifactregistry v1.12.0/go.mod h1:o6P3MIvtzTOnmvGagO9v/rOjjA0HmhJ+/6KAXrmYDCI= +cloud.google.com/go/artifactregistry v1.13.0/go.mod h1:uy/LNfoOIivepGhooAUpL1i30Hgee3Cu0l4VTWHUC08= +cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= +cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= +cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= +cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= +cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/asset v1.12.0/go.mod h1:h9/sFOa4eDIyKmH6QMpm4eUK3pDojWnUhTgJlk762Hg= +cloud.google.com/go/asset v1.13.0/go.mod h1:WQAMyYek/b7NBpYq/K4KJWcRqzoalEsxz/t/dTk4THw= +cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= +cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= +cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= +cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= +cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/auth v0.14.1 h1:AwoJbzUdxA/whv1qj3TLKwh3XX5sikny2fc40wUl+h0= +cloud.google.com/go/auth v0.14.1/go.mod h1:4JHUxlGXisL0AW8kXPtUF6ztuOksyfUQNFjfsOCXkPM= +cloud.google.com/go/auth/oauth2adapt v0.2.7 h1:/Lc7xODdqcEw8IrZ9SvwnlLX6j9FHQM74z6cBk9Rw6M= +cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc= +cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= +cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= +cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= +cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= +cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= +cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= +cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/beyondcorp v0.5.0/go.mod h1:uFqj9X+dSfrheVp7ssLTaRHd2EHqSL4QZmH4e8WXGGU= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= +cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= +cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= +cloud.google.com/go/bigquery v1.47.0/go.mod h1:sA9XOgy0A8vQK9+MWhEQTY6Tix87M/ZurWFIxmF9I/E= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/bigquery v1.49.0/go.mod h1:Sv8hMmTFFYBlt/ftw2uN6dFdQPzBlREY9yBh7Oy7/4Q= +cloud.google.com/go/bigquery v1.50.0/go.mod h1:YrleYEh2pSEbgTBZYMJ5SuSr0ML3ypjRB1zgf7pvQLU= +cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= +cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= +cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= +cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/billing v1.13.0/go.mod h1:7kB2W9Xf98hP9Sr12KfECgfGclsH3CQR0R08tnRlRbc= +cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= +cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= +cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= +cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= +cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= +cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/channel v1.12.0/go.mod h1:VkxCGKASi4Cq7TbXxlaBezonAYpp1GCnKMY6tnMQnLU= +cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= +cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= +cloud.google.com/go/cloudbuild v1.6.0/go.mod h1:UIbc/w9QCbH12xX+ezUsgblrWv+Cv4Tw83GiSMHOn9M= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/cloudbuild v1.9.0/go.mod h1:qK1d7s4QlO0VwfYn5YuClDGg2hfmLZEb4wQGAbIgL1s= +cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= +cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= +cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= +cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= +cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/cloudtasks v1.10.0/go.mod h1:NDSoTLkZ3+vExFEWu2UJV1arUyzVDAiZtdWcsUyNwBs= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= +cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= +cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= +cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= +cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= +cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= -cloud.google.com/go/iam v1.2.1 h1:QFct02HRb7H12J/3utj0qf5tobFh9V4vR6h9eX5EBRU= -cloud.google.com/go/iam v1.2.1/go.mod h1:3VUIJDPpwT6p/amXRC5GY8fCCh70lxPygguVtI0Z4/g= -cloud.google.com/go/longrunning v0.6.1 h1:lOLTFxYpr8hcRtcwWir5ITh1PAKUD/sG2lKrTSYjyMc= -cloud.google.com/go/longrunning v0.6.1/go.mod h1:nHISoOZpBcmlwbJmiVk5oDRz0qG/ZxPynEGs1iZ79s0= -cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs= -cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0= +cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= +cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= +cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/container v1.14.0/go.mod h1:3AoJMPhHfLDxLvrlVWaK57IXzaPnLaZq63WX59aQBfM= +cloud.google.com/go/container v1.15.0/go.mod h1:ft+9S0WGjAyjDggg5S06DXj+fHJICWg8L7isCQe9pQA= +cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= +cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/containeranalysis v0.9.0/go.mod h1:orbOANbwk5Ejoom+s+DUCTTJ7IBdBQJDcSylAx/on9s= +cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= +cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= +cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= +cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= +cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= +cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/datacatalog v1.13.0/go.mod h1:E4Rj9a5ZtAxcQJlEBTLgMTphfP11/lNaAshpoBgemX8= +cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= +cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= +cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= +cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/dataform v0.7.0/go.mod h1:7NulqnVozfHvWUBpMDfKMUESr+85aJsC/2O0o3jWPDE= +cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= +cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= +cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= +cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataplex v1.6.0/go.mod h1:bMsomC/aEJOSpHXdFKFGQ1b0TDPIeL28nJObeO1ppRs= +cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= +cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= +cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastore v1.11.0/go.mod h1:TvGxBIHCS50u8jzG+AW/ppf87v1of8nwzFNgEZU1D3c= +cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= +cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= +cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= +cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/datastream v1.7.0/go.mod h1:uxVRMm2elUSPuh65IbZpzJNMbuzkcvu5CjMqVIUHrww= +cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= +cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/deploy v1.8.0/go.mod h1:z3myEJnA/2wnB4sgjqdMfgxCA0EqC3RBTNcVPs93mtQ= +cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= +cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= +cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= +cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= +cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= +cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dialogflow v1.32.0/go.mod h1:jG9TRJl8CKrDhMEcvfcfFkkpp8ZhgPz3sBGmAUYJ2qE= +cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= +cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= +cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= +cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= +cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/documentai v1.18.0/go.mod h1:F6CK6iUH8J81FehpskRmhLq/3VlwQvb7TvwOceQ2tbs= +cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= +cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= +cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/edgecontainer v1.0.0/go.mod h1:cttArqZpBB2q58W/upSG++ooo6EsblxDIolxa3jSjbY= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= +cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= +cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/eventarc v1.11.0/go.mod h1:PyUjsUKPWoRBCHeOxZd/lbOOjahV41icXyUY5kSTvVY= +cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= +cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/filestore v1.6.0/go.mod h1:di5unNuss/qfZTw2U9nhFqo8/ZDSc466dre85Kydllg= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= +cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= +cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= +cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/functions v1.12.0/go.mod h1:AXWGrF3e2C/5ehvwYo/GH6O5s09tOPksiKhz+hH8WkA= +cloud.google.com/go/functions v1.13.0/go.mod h1:EU4O007sQm6Ef/PwRsI8N2umygGqPBS/IZQKBQBcJ3c= +cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= +cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= +cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= +cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= +cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= +cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= +cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkehub v0.12.0/go.mod h1:djiIwwzTTBrF5NaXCGv3mf7klpEMcST17VBTVVDcuaw= +cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= +cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= +cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= +cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= +cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= +cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= +cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= +cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= +cloud.google.com/go/iam v1.3.1 h1:KFf8SaT71yYq+sQtRISn90Gyhyf4X8RGgeAVC8XGf3E= +cloud.google.com/go/iam v1.3.1/go.mod h1:3wMtuyT4NcbnYNPLMBzYRFiEfjKfJlLVLrisE7bwm34= +cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= +cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/iap v1.7.0/go.mod h1:beqQx56T9O1G1yNPph+spKpNibDlYIiIixiqsQXxLIo= +cloud.google.com/go/iap v1.7.1/go.mod h1:WapEwPc7ZxGt2jFGB/C/bm+hP0Y6NXzOYGjpPnmMS74= +cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= +cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= +cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/iot v1.6.0/go.mod h1:IqdAsmE2cTYYNO1Fvjfzo9po179rAtJeVGUvkLN3rLE= +cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= +cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= +cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= +cloud.google.com/go/kms v1.8.0/go.mod h1:4xFEhYFqvW+4VMELtZyxomGSYtSQKzM178ylFW4jMAg= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24= +cloud.google.com/go/kms v1.10.1/go.mod h1:rIWk/TryCkR59GMC3YtHtXeLzd634lBbKenvyySAyYI= +cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= +cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= +cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= +cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= +cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/logging v1.13.0 h1:7j0HgAp0B94o1YRDqiqm26w4q1rDMH7XNRU34lJXHYc= +cloud.google.com/go/logging v1.13.0/go.mod h1:36CoKh6KA/M0PbhPKMq6/qety2DCAErbhXT62TuXALA= +cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= +cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/longrunning v0.6.4 h1:3tyw9rO3E2XVXzSApn1gyEEnH2K9SynNQjMlBi3uHLg= +cloud.google.com/go/longrunning v0.6.4/go.mod h1:ttZpLCe6e7EXvn9OxpBRx7kZEB0efv8yBO6YnVMfhJs= +cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= +cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/maps v0.7.0/go.mod h1:3GnvVl3cqeSvgMcpRlQidXsPYuDGQ8naBis7MVzpXsY= +cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= +cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= +cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= +cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= +cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= +cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= +cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= +cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= +cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw= +cloud.google.com/go/monitoring v1.23.0 h1:M3nXww2gn9oZ/qWN2bZ35CjolnVHM3qnSbu6srCPgjk= +cloud.google.com/go/monitoring v1.23.0/go.mod h1:034NnlQPDzrQ64G2Gavhl0LUHZs9H3rRmhtnp7jiJgg= +cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= +cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= +cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= +cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkconnectivity v1.11.0/go.mod h1:iWmDD4QF16VCDLXUqvyspJjIEtBR/4zq5hwnY2X3scM= +cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= +cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= +cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/networksecurity v0.8.0/go.mod h1:B78DkqsxFG5zRSVuwYFRZ9Xz8IcQ5iECsNrPn74hKHU= +cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= +cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= +cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= +cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/notebooks v1.8.0/go.mod h1:Lq6dYKOYOWUCTvw5t2q1gp1lAp0zxAxRycayS0iJcqQ= +cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= +cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= +cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= +cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= +cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= +cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= +cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= +cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= +cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= +cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= +cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= +cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/policytroubleshooter v1.6.0/go.mod h1:zYqaPTsmfvpjm5ULxAyD/lINQxJ0DDsnWOP/GZ7xzBc= +cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= +cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/privatecatalog v0.8.0/go.mod h1:nQ6pfaegeDAq/Q5lrfCQzQLhubPiZhSaNhIgfJlnIXs= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= +cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsub v1.30.0/go.mod h1:qWi1OPS0B+b5L+Sg6Gmc9zD1Y+HaM0MdUr7LsupY1P4= +cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/pubsublite v1.7.0/go.mod h1:8hVMwRXfDfvGm3fahVbtDbiLePT3gpoiJYJY+vxWxVM= +cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= +cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= +cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= +cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= +cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= +cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recaptchaenterprise/v2 v2.7.0/go.mod h1:19wVj/fs5RtYtynAPJdDTb69oW0vNHYDBTbB4NvMD9c= +cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= +cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= +cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= +cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= +cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= +cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= +cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= +cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= +cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcemanager v1.6.0/go.mod h1:YcpXGRs8fDzcUl1Xw8uOVmI8JEadvhRIkoXXUNVYcVo= +cloud.google.com/go/resourcemanager v1.7.0/go.mod h1:HlD3m6+bwhzj9XCouqmeiGuni95NTrExfhoSrkC/3EI= +cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= +cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= +cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= +cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= +cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= +cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/run v0.9.0/go.mod h1:Wwu+/vvg8Y+JUApMwEDfVfhetv30hCG4ZwDR/IXl2Qg= +cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= +cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= +cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= +cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/scheduler v1.9.0/go.mod h1:yexg5t+KSmqu+njTIh3b7oYPheFtBWGcbVUYF1GGMIc= +cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= +cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= +cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= +cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= +cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= +cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= +cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/security v1.13.0/go.mod h1:Q1Nvxl1PAgmeW0y3HTt54JYIvUdtcpYKVfIB8AOMZ+0= +cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= +cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= +cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= +cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/securitycenter v1.19.0/go.mod h1:LVLmSg8ZkkyaNy4u7HCIshAngSQ8EcIRREP3xBnyfag= +cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= +cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= +cloud.google.com/go/servicecontrol v1.10.0/go.mod h1:pQvyvSRh7YzUF2efw7H87V92mxU8FnFDawMClGCNuAA= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicecontrol v1.11.1/go.mod h1:aSnNNlwEFBY+PWGQ2DoM0JJ/QUXqV5/ZD9DOLB7SnUk= +cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= +cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= +cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= +cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicedirectory v1.9.0/go.mod h1:29je5JjiygNYlmsGz8k6o+OZ8vd4f//bQLtvzkPPT/s= +cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= +cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/servicemanagement v1.8.0/go.mod h1:MSS2TDlIEQD/fzsSGfCdJItQveu9NXnUniTrq/L8LK4= +cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= +cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/serviceusage v1.6.0/go.mod h1:R5wwQcbOWsyuOfbP9tGdAnCAc6B9DRwPG1xtWMDeuPA= +cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= +cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M= +cloud.google.com/go/spanner v1.75.0 h1:2zrltTJv/4P3pCgpYgde4Eb1vN8Cgy1fNy7pbTnOovg= +cloud.google.com/go/spanner v1.75.0/go.mod h1:TLFZBvPQmx3We7sGh12eTk9lLsRLczzZaiweqfMpR80= +cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= +cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= +cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= +cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/speech v1.15.0/go.mod h1:y6oH7GhqCaZANH7+Oe0BhgIogsNInLlz542tg3VqeYI= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= +cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= +cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= +cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= +cloud.google.com/go/storage v1.50.0 h1:3TbVkzTooBvnZsk7WaAQfOsNrdoM8QHusXA1cpk6QJs= +cloud.google.com/go/storage v1.50.0/go.mod h1:l7XeiD//vx5lfqE3RavfmU9yvk5Pp0Zhcv482poyafY= +cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= +cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/storagetransfer v1.8.0/go.mod h1:JpegsHHU1eXg7lMHkvf+KE5XDJ7EQu0GwNJbbVGanEw= +cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= +cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= +cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= +cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= +cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= +cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= +cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk= +cloud.google.com/go/trace v1.11.3 h1:c+I4YFjxRQjvAhRmSsmjpASUKq88chOX854ied0K/pE= +cloud.google.com/go/trace v1.11.3/go.mod h1:pt7zCYiDSQjC9Y2oqCsh9jF4GStB/hmjrYLsxRR27q8= +cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= +cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= +cloud.google.com/go/translate v1.5.0/go.mod h1:29YDSYveqqpA1CQFD7NQuP49xymq17RXNaUDdc0mNu0= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/translate v1.7.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= +cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= +cloud.google.com/go/video v1.12.0/go.mod h1:MLQew95eTuaNDEGriQdcYn0dTwf9oWiA4uYebxM5kdg= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/video v1.14.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= +cloud.google.com/go/video v1.15.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= +cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= +cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= +cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= +cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= +cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= +cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= +cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= +cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vision/v2 v2.7.0/go.mod h1:H89VysHy21avemp6xcf9b9JvZHVehWbET0uT/bcuY/0= +cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= +cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmmigration v1.6.0/go.mod h1:bopQ/g4z+8qXzichC7GW1w2MjbErL54rk3/C843CjfY= +cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vmwareengine v0.3.0/go.mod h1:wvoyMvNWdIzxMYSpH/R7y2h5h3WFkx6d+1TIsP39WGY= +cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= +cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= +cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= +cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= +cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= +cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= +cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= +cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= +cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= cuelang.org/go v0.11.1 h1:pV+49MX1mmvDm8Qh3Za3M786cty8VKPWzQ1Ho4gZRP0= cuelang.org/go v0.11.1/go.mod h1:PBY6XvPUswPPJ2inpvUozP9mebDVTXaeehQikhZPBz0= dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= +git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 h1:g0EZJwz7xkXQiZAI5xi9f3WWFYBlX1CPTrR+NDToRkQ= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0/go.mod h1:XCW7KnZet0Opnr7HccfUw1PLc4CjHqpcaxW8DHklNkQ= @@ -48,9 +653,21 @@ github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2/go.mod h1:wP83 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.2 h1:DBjmt6/otSdULyJdVg2BlG0qGZO5tKL4VzOs0jpvw5Q= +github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.2/go.mod h1:dppbR7CwXD4pgtV9t3wD1812RaLDcBjtblcDF5f1vI0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 h1:3c8yed4lgqTt+oTQ+JNMDo+F4xprBf+O/il4ZC0nRLw= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0/go.mod h1:obipzmGjfSjam60XLwGfqUkJsfiheAl+TUjG+4yzyPM= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0 h1:o90wcURuxekmXrtxmYWTyNla0+ZEHhud6DI1ZTxd1vI= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0/go.mod h1:6fTWu4m3jocfUZLYF5KsZC1TUfRvEjs7lM4crme/irw= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.49.0 h1:jJKWl98inONJAr/IZrdFQUWcwUO95DLY1XMD1ZIut+g= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.49.0/go.mod h1:l2fIqmwB+FKSfvn3bAD/0i+AXAxhIZjTK2svT/mgUXs= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0 h1:GYUJLfvd++4DMuMhCFLgLXvFwofIxh/qOwoGuS/LTew= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0/go.mod h1:wRbFgBQUVm1YXrvWKofAEmq9HNJTDphbAaJSSX01KUI= github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= +github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= @@ -61,23 +678,33 @@ github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f h1:HR5nRmUQgXrwqZOwZ2DAc/aCi3Bu3xENpspW935vxu0= github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f/go.mod h1:f3HiCrHjHBdcm6E83vGaXh1KomZMA2P6aeo3hKx/wg0= +github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= +github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0= github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/arrow-go/v18 v18.0.1-0.20241212180703-82be143d7c30 h1:hXVi7QKuCQ0E8Yujfu9b0f0RnzZ72efpWvPnZgnJPrE= github.com/apache/arrow-go/v18 v18.0.1-0.20241212180703-82be143d7c30/go.mod h1:RNuWDIiGjq5nndL2PyQrndUy9nMLwheA3uWaAV7fe4U= +github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= +github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= github.com/apache/thrift v0.21.0 h1:tdPmh/ptjE1IJnhbhrcl2++TauVjy242rkV/UzJChnE= github.com/apache/thrift v0.21.0/go.mod h1:W1H8aR/QRtYNvrPeFXBtobyRkd0/YVhTc6i07XIAgDw= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= @@ -138,6 +765,8 @@ github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCS github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 h1:N7oVaKyGp8bttX0bfZGmcGkjz7DLQXhAn3DNd3T0ous= github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= @@ -147,20 +776,41 @@ github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= github.com/chromedp/cdproto v0.0.0-20240810084448-b931b754e476 h1:VnjHsRXCRti7Av7E+j4DCha3kf68echfDzQ+wD11SBU= github.com/chromedp/cdproto v0.0.0-20240810084448-b931b754e476/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 h1:QVw89YDxXxEe+l8gU8ETbOasdwEV+avkR75ZzsVV9WI= +github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= @@ -173,6 +823,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cznic/b v0.0.0-20180115125044-35e9bbe41f07/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8= github.com/cznic/fileutil v0.0.0-20180108211300-6a051e75936f/go.mod h1:8S58EK26zhXSxzv7NQFpnliaOQsmDUxvoQO3rt154Vg= github.com/cznic/golex v0.0.0-20170803123110-4ab7c5e190e4/go.mod h1:+bmmJDNmKlhWNG+gwWCkaBoTy39Fs+bzRxVBzoTQbIc= @@ -202,6 +853,7 @@ github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5Xh github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2 h1:u3PMzfF8RkKd3lB9pZ2bfn0qEG+1Gms9599cr0REMww= github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2/go.mod h1:mIEZOHnFx4ZMQeawhw9rhsj+0zwQj7adVsnBX7t+eKY= github.com/dolthub/go-icu-regex v0.0.0-20241215010122-db690dd53c90 h1:Sni8jrP0sy/w9ZYXoff4g/ixe+7bFCZlfCqXKJSU+zM= @@ -212,6 +864,7 @@ github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 h1:bMGS25NWAGTE github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71/go.mod h1:2/2zjLQ/JOOSbbSboojeg+cAwcRV0fDLzIiWch/lhqI= github.com/dolthub/vitess v0.0.0-20250123002143-3b45b8cacbfa h1:kyoPzxViSXAyqfO0Mab7Qo1UogFIrxZKKyBU6kBOl+E= github.com/dolthub/vitess v0.0.0-20250123002143-3b45b8cacbfa/go.mod h1:1gQZs/byeHLMSul3Lvl3MzioMtOW1je79QYGyi2fd70= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= @@ -223,13 +876,29 @@ github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRr github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q= +github.com/envoyproxy/go-control-plane v0.13.1 h1:vPfJZCkob6yTMEgS+0TwfTUfbHjfy/6vOJ8hUWX/uXE= +github.com/envoyproxy/go-control-plane v0.13.1/go.mod h1:X45hY0mufo6Fd0KW3rqsGvQMw58jvjymeCzBU3mWyHw= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= +github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= +github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= @@ -242,14 +911,25 @@ github.com/gchaincl/sqlhooks v1.3.0 h1:yKPXxW9a5CjXaVf2HkQn6wn7TZARvbAOAelr3H8vK github.com/gchaincl/sqlhooks v1.3.0/go.mod h1:9BypXnereMT0+Ys8WGWHqzgkkOfHIhyeUCqXC24ra34= github.com/getkin/kin-openapi v0.129.0 h1:QGYTNcmyP5X0AtFQ2Dkou9DGBJsUETeLH9rFrJXZh30= github.com/getkin/kin-openapi v0.129.0/go.mod h1:gmWI+b/J45xqpyK5wJmRRZse5wefA5H0RDMK46kLUtI= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= +github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= +github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY= github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= +github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= github.com/go-ldap/ldap/v3 v3.4.4 h1:qPjipEpt+qDa6SI/h1fzuGWoRUY+qqQ9sOZq67/PYUs= github.com/go-ldap/ldap/v3 v3.4.4/go.mod h1:fe1MsuN5eJJ1FeLT/LEBVdWfNWKh459R7aXgXtJC+aI= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -282,6 +962,8 @@ github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+Gr github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58= github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ= +github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -297,6 +979,7 @@ github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM= github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0= @@ -319,17 +1002,32 @@ github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17w github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-migrate/migrate/v4 v4.7.0 h1:gONcHxHApDTKXDyLH/H97gEHmpu1zcnnbAaq2zgrPrs= github.com/golang-migrate/migrate/v4 v4.7.0/go.mod h1:Qvut3N4xKWjoH3sokBccML6WyHSnggXm/DvMMnTsQIc= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U= github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -339,16 +1037,22 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI= github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= @@ -357,9 +1061,16 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= @@ -375,22 +1086,59 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= -github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= +github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI= github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= +github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= +github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= +github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q= github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= @@ -426,6 +1174,9 @@ github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpS github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0 h1:kQ0NI7W1B3HwiN5gAYtY+XFItDPbLBwYRxAqbFTyDes= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0/go.mod h1:zrT2dxOAjNFPRGjTUe2Xmb4q4YdUwVvQFV6xiCSf+z0= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg= github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= @@ -466,6 +1217,9 @@ github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbg github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= @@ -496,13 +1250,17 @@ github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 h1:SwcnSwBR7X/5EHJQlXBockkJVIMRVt5yKaesBPMtyZQ= github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6/go.mod h1:WrYiIuiXUMIvTDAQw97C+9l0CnBmCcvosPjN3XDqS/o= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs= github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= @@ -510,14 +1268,19 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4= github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -533,6 +1296,9 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= @@ -553,6 +1319,7 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -628,15 +1395,24 @@ github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaR github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= +github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= +github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -653,6 +1429,7 @@ github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1: github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -673,9 +1450,14 @@ github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoG github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E= github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= @@ -683,6 +1465,8 @@ github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= +github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -703,6 +1487,10 @@ github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PX github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c h1:Ho+uVpkel/udgjbwB5Lktg9BtvJSh2DT0Hi6LPSyI2w= github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= @@ -719,11 +1507,13 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= @@ -757,8 +1547,12 @@ github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcY github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= @@ -772,10 +1566,18 @@ go.mongodb.org/mongo-driver v1.16.1 h1:rIVLL3q0IHM39dvE+z2ulZLp9ENZKThVfuvN/IiN4 go.mongodb.org/mongo-driver v1.16.1/go.mod h1:oB6AhJQvFQL4LEHyXi6aJzQJtBiTQHiAd83l0GdFaiw= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/detectors/gcp v1.33.0 h1:FVPoXEoILwgbZUu4X7YSgsESsAmGRgoYcnXkzgQPhP4= +go.opentelemetry.io/contrib/detectors/gcp v1.33.0/go.mod h1:ZHrLmr4ikK2AwRj9QL+c9s2SOlgoSRyMpNVzUj2fZqI= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 h1:rgMkmiGfix9vFJDcDi1PK8WEQP4FLQwLDfhp5ZLpFeE= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.59.0 h1:iQZYNQ7WwIcYXzOPR46FQv9O0dS1PW16RjvR0TjDOe8= @@ -795,6 +1597,8 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glB go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 h1:tgJ0uaNS4c98WRNUEx5U3aDlrDOI5Rs+1Vifcw4DJ8U= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0/go.mod h1:U7HYyW0zt/a9x5J1Kjs+r1f/d4ZHnYFclhYY2+YbeoE= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0 h1:WDdP9acbMYjbKIyJUhTvtzj601sVJOqgWdUxSdR/Ysc= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0/go.mod h1:BLbf7zbNIONBLPwvFnwNHGj4zge8uTCM/UPIVW1Mq2I= go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= @@ -806,6 +1610,9 @@ go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRY go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= @@ -818,26 +1625,79 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= @@ -854,16 +1714,59 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= @@ -873,6 +1776,33 @@ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAG golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= +golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= +golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -881,8 +1811,15 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= @@ -895,29 +1832,88 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190426135247-a129542de9ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191020152052-9984515f0562/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= @@ -927,19 +1923,33 @@ golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= @@ -947,24 +1957,80 @@ golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190424220101-1e8e1cfdf96b/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425222832-ad9eeb80039a/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE= @@ -973,44 +2039,278 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= +gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= +gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= gonum.org/v1/gonum v0.15.1 h1:FNy7N6OUZVUaWG9pTiD+jlhdQ3lMP+/LcTpJ6+a8sQ0= gonum.org/v1/gonum v0.15.1/go.mod h1:eZTZuRFrzu5pcyjN5wJhcIhnUdNijYxX1T2IcrOGY0o= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= +gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.216.0 h1:xnEHy+xWFrtYInWPy8OdGFsyIfWJjtVnO39g7pz2BFY= -google.golang.org/api v0.216.0/go.mod h1:K9wzQMvWi47Z9IU7OgdOofvZuw75Ge3PPITImZR/UyI= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= +google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= +google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= +google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= +google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= +google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= +google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= +google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= +google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= +google.golang.org/api v0.220.0 h1:3oMI4gdBgB72WFVwE1nerDD8W3HUOS4kypK6rRLbGns= +google.golang.org/api v0.220.0/go.mod h1:26ZAlY6aN/8WgpCzjPNy18QpYaz7Zgg1h0qe1GkZEmY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU= -google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4= -google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f h1:gap6+3Gk41EItBuyi4XX/bp4oqJ3UwuIMl25yGinuAA= -google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:Ic02D47M+zbarjYYUlK57y316f2MoN0gjAwI3f2S95o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= +google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= +google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= +google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= +google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA= +google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= +google.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= +google.golang.org/genproto v0.0.0-20230303212802-e74f57abe488/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4 h1:Pw6WnI9W/LIdRxqK7T6XGugGbHIRl5Q7q3BssH6xk4s= +google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4/go.mod h1:qbZzneIOXSq+KFAFut9krLfRLZiFLzZL5u2t8SV83EE= +google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 h1:5iw9XJTD4thFidQmFVvx0wi4g5yOHk76rNRUxz1ZG5g= +google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47/go.mod h1:AfA77qWLcidQWywD0YgqfpJzf50w2VjzBml3TybHeJU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 h1:2duwAxN2+k0xLNpjnHTXoMUgnv6VPSp5fiqTuwSxjmI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= +google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1019,9 +2319,15 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= @@ -1032,6 +2338,7 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify/fsnotify.v1 v1.4.7 h1:XNNYLJHt73EyYiCZi6+xjupS9CpvmiDgjPTAjrBlQbo= gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE= @@ -1046,6 +2353,7 @@ gopkg.in/src-d/go-errors.v1 v1.0.0/go.mod h1:q1cBlomlw2FnDBDNGlnh6X0jPihy+QxZfMM gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1058,7 +2366,12 @@ gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81 honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= k8s.io/api v0.32.1 h1:f562zw9cy+GvXzXf0CKlVQ7yHJVYzLfL6JAS4kOAaOc= k8s.io/api v0.32.1/go.mod h1:/Yi/BqkuueW1BgpoePYBRdDYfjPF5sgTr5+YqDZra5k= k8s.io/apimachinery v0.32.1 h1:683ENpaCBjma4CYqsmZyhEzrGz6cjn1MY/X2jB2hkZs= @@ -1073,6 +2386,44 @@ k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJ k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= +modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= +modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= +modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= +modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= +modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= +modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= +modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= +modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= +modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= +modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= +modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= +modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= +modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= +modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= +modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= sigs.k8s.io/structured-merge-diff/v4 v4.5.0 h1:nbCitCK2hfnhyiKo6uf2HxUPTCodY6Qaf85SbDIaMBk= diff --git a/pkg/util/xorm/dialect_spanner.go b/pkg/util/xorm/dialect_spanner.go new file mode 100644 index 00000000000..cc766dbb012 --- /dev/null +++ b/pkg/util/xorm/dialect_spanner.go @@ -0,0 +1,284 @@ +//go:build enterprise || pro + +package xorm + +import ( + "strings" + + _ "github.com/googleapis/go-sql-spanner" + "xorm.io/core" +) + +func init() { + core.RegisterDriver("spanner", &spannerDriver{}) + core.RegisterDialect("spanner", func() core.Dialect { return &spanner{} }) +} + +// https://cloud.google.com/spanner/docs/reference/standard-sql/lexical#reserved_keywords +var spannerReservedKeywords = map[string]struct{}{ + "ALL": {}, + "AND": {}, + "ANY": {}, + "ARRAY": {}, + "AS": {}, + "ASC": {}, + "ASSERT_ROWS_MODIFIED": {}, + "AT": {}, + "BETWEEN": {}, + "BY": {}, + "CASE": {}, + "CAST": {}, + "COLLATE": {}, + "CONTAINS": {}, + "CREATE": {}, + "CROSS": {}, + "CUBE": {}, + "CURRENT": {}, + "DEFAULT": {}, + "DEFINE": {}, + "DESC": {}, + "DISTINCT": {}, + "ELSE": {}, + "END": {}, + "ENUM": {}, + "ESCAPE": {}, + "EXCEPT": {}, + "EXCLUDE": {}, + "EXISTS": {}, + "EXTRACT": {}, + "FALSE": {}, + "FETCH": {}, + "FOLLOWING": {}, + "FOR": {}, + "FROM": {}, + "FULL": {}, + "GROUP": {}, + "GROUPING": {}, + "GROUPS": {}, + "HASH": {}, + "HAVING": {}, + "IF": {}, + "IGNORE": {}, + "IN": {}, + "INNER": {}, + "INTERSECT": {}, + "INTERVAL": {}, + "INTO": {}, + "IS": {}, + "JOIN": {}, + "LATERAL": {}, + "LEFT": {}, + "LIKE": {}, + "LIMIT": {}, + "LOOKUP": {}, + "MERGE": {}, + "NATURAL": {}, + "NEW": {}, + "NO": {}, + "NOT": {}, + "NULL": {}, + "NULLS": {}, + "OF": {}, + "ON": {}, + "OR": {}, + "ORDER": {}, + "OUTER": {}, + "OVER": {}, + "PARTITION": {}, + "PRECEDING": {}, + "PROTO": {}, + "RANGE": {}, + "RECURSIVE": {}, + "RESPECT": {}, + "RIGHT": {}, + "ROLLUP": {}, + "ROWS": {}, + "SELECT": {}, + "SET": {}, + "SOME": {}, + "STRUCT": {}, + "TABLESAMPLE": {}, + "THEN": {}, + "TO": {}, + "TREAT": {}, + "TRUE": {}, + "UNBOUNDED": {}, + "UNION": {}, + "UNNEST": {}, + "USING": {}, + "WHEN": {}, + "WHERE": {}, + "WINDOW": {}, + "WITH": {}, + "WITHIN": {}, +} + +type spannerDriver struct{} + +func (d *spannerDriver) Parse(_driverName, datasourceName string) (*core.Uri, error) { + return &core.Uri{DbType: "spanner", DbName: datasourceName}, nil +} + +type spanner struct { + core.Base +} + +func (s *spanner) Init(db *core.DB, uri *core.Uri, driverName string, datasourceName string) error { + return s.Base.Init(db, s, uri, driverName, datasourceName) +} +func (s *spanner) Filters() []core.Filter { return []core.Filter{&core.IdFilter{}} } +func (s *spanner) IsReserved(name string) bool { + _, exists := spannerReservedKeywords[name] + return exists +} +func (s *spanner) AndStr() string { return "AND" } +func (s *spanner) OrStr() string { return "OR" } +func (s *spanner) EqStr() string { return "=" } +func (s *spanner) RollBackStr() string { return "ROLL BACK" } +func (s *spanner) AutoIncrStr() string { return "" } // Spanner does not support auto-increment +func (s *spanner) SupportInsertMany() bool { return false } // Needs manual transaction batching +func (s *spanner) SupportEngine() bool { return false } // No support for engine selection +func (s *spanner) SupportCharset() bool { return false } // ...or charsets +func (s *spanner) SupportDropIfExists() bool { return false } // Drop should be handled differently +func (s *spanner) IndexOnTable() bool { return false } +func (s *spanner) ShowCreateNull() bool { return false } +func (s *spanner) Quote(name string) string { return "`" + name + "`" } +func (s *spanner) SqlType(col *core.Column) string { + switch col.SQLType.Name { + case core.Int, core.BigInt: + return "INT64" + case core.Varchar, core.Text: + return "STRING(MAX)" + case core.Bool: + return "BOOL" + case core.Float, core.Double: + return "FLOAT64" + case core.Bytea: + return "BYTES(MAX)" + case core.DateTime, core.TimeStamp: + return "TIMESTAMP" + default: + return "STRING(MAX)" // XXX: more types to add + } +} + +func (s *spanner) GetColumns(tableName string) ([]string, map[string]*core.Column, error) { + query := `SELECT COLUMN_NAME, SPANNER_TYPE, IS_NULLABLE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @tableName` + rows, err := s.DB().Query(query, map[string]any{"tableName": tableName}) + if err != nil { + return nil, nil, err + } + defer rows.Close() + + columns := make(map[string]*core.Column) + var colNames []string + + var name, sqlType, isNullable string + for rows.Next() { + if err := rows.Scan(&name, &sqlType, &isNullable); err != nil { + return nil, nil, err + } + + col := &core.Column{ + Name: name, + SQLType: core.SQLType{Name: sqlType}, + Nullable: isNullable == "YES", + } + columns[name] = col + colNames = append(colNames, name) + } + + return colNames, columns, nil +} + +func (s *spanner) CreateTableSql(table *core.Table, tableName, _, charset string) string { + sql := "CREATE TABLE " + s.Quote(tableName) + " (" + + for i, col := range table.Columns() { + if i > 0 { + sql += ", " + } + sql += s.Quote(col.Name) + " " + s.SqlType(col) + if col.IsPrimaryKey { + sql += " PRIMARY KEY" + } + } + + sql += ") PRIMARY KEY (" + strings.Join(table.PrimaryKeys, ",") + ")" + return sql +} + +func (s *spanner) CreateIndexSql(tableName string, index *core.Index) string { + sql := "CREATE " + if index.Type == core.UniqueType { + sql += "UNIQUE NULL_FILTERED " + } + sql += "INDEX " + s.Quote(index.XName(tableName)) + " ON " + s.Quote(tableName) + " (" + strings.Join(index.Cols, ", ") + ")" + return sql +} + +func (s *spanner) IndexCheckSql(tableName, indexName string) (string, []any) { + return `SELECT index_name FROM information_schema.indexes + WHERE table_name = ? AND table_schema = "" AND index_name = ?`, + []any{tableName, indexName} +} + +func (s *spanner) TableCheckSql(tableName string) (string, []any) { + return `SELECT table_name FROM information_schema.tables + WHERE table_name = ? AND table_schema = ""`, + []any{tableName} +} + +func (s *spanner) GetTables() ([]*core.Table, error) { + res, err := s.DB().Query(` + SELECT table_name FROM information_schema.tables + WHERE table_schema = "" + `) + if err != nil { + return nil, err + } + defer res.Close() + + tables := []*core.Table{} + for res.Next() { + var name string + if err := res.Scan(&name); err != nil { + return nil, err + } + t := core.NewEmptyTable() + t.Name = name + tables = append(tables, t) + } + return tables, nil +} + +func (s *spanner) GetIndexes(tableName string) (map[string]*core.Index, error) { + res, err := s.DB().Query(` + SELECT index_name, index_type, is_unique FROM information_schema.tables + WHERE table_name = ? AND table_schema = "" + `, []any{tableName}) + if err != nil { + return nil, err + } + defer res.Close() + + indices := map[string]*core.Index{} + for res.Next() { + index := struct { + Name string `xorm:"index_name"` + Type string `xorm:"index_type"` + IsUnqiue bool `xorm:"is_unique"` + }{} + err := res.Scan(&index) + if err != nil { + return nil, err + } + switch { + case index.Type == "INDEX": + indices[index.Name] = core.NewIndex(index.Name, core.IndexType) + case index.Type == "PRIMARY_KEY", index.IsUnqiue: + indices[index.Name] = core.NewIndex(index.Name, core.UniqueType) + } + } + return indices, nil +} diff --git a/pkg/util/xorm/go.mod b/pkg/util/xorm/go.mod index b923d8e7ea9..1d642bc0a4a 100644 --- a/pkg/util/xorm/go.mod +++ b/pkg/util/xorm/go.mod @@ -1,10 +1,11 @@ module github.com/grafana/grafana/pkg/util/xorm -go 1.22 +go 1.23.0 -toolchain go1.23.1 +toolchain go1.24.0 require ( + github.com/googleapis/go-sql-spanner v1.11.1 github.com/mattn/go-sqlite3 v1.14.22 github.com/stretchr/testify v1.10.0 xorm.io/builder v0.3.6 @@ -12,11 +13,56 @@ require ( ) require ( + cel.dev/expr v0.19.0 // indirect + cloud.google.com/go v0.118.2 // indirect + cloud.google.com/go/auth v0.14.1 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.7 // indirect + cloud.google.com/go/compute/metadata v0.6.0 // indirect + cloud.google.com/go/iam v1.3.1 // indirect + cloud.google.com/go/longrunning v0.6.4 // indirect + cloud.google.com/go/monitoring v1.23.0 // indirect + cloud.google.com/go/spanner v1.75.0 // indirect + github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.2 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/envoyproxy/go-control-plane/envoy v1.32.3 // indirect + github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/go-sql-driver/mysql v1.8.1 // indirect - github.com/kr/pretty v0.3.1 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/google/go-cmp v0.7.0 // indirect + github.com/google/s2a-go v0.1.9 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect + github.com/googleapis/gax-go/v2 v2.14.1 // indirect + github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/rogpeppe/go-internal v1.13.1 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/detectors/gcp v1.33.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect + go.opentelemetry.io/otel v1.34.0 // indirect + go.opentelemetry.io/otel/metric v1.34.0 // indirect + go.opentelemetry.io/otel/sdk v1.34.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.34.0 // indirect + golang.org/x/crypto v0.35.0 // indirect + golang.org/x/net v0.35.0 // indirect + golang.org/x/oauth2 v0.27.0 // indirect + golang.org/x/sync v0.11.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.22.0 // indirect + golang.org/x/time v0.9.0 // indirect + google.golang.org/api v0.220.0 // indirect + google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 // indirect + google.golang.org/grpc v1.70.0 // indirect + google.golang.org/protobuf v1.36.5 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/pkg/util/xorm/go.sum b/pkg/util/xorm/go.sum index c1d214d6716..9836c572b87 100644 --- a/pkg/util/xorm/go.sum +++ b/pkg/util/xorm/go.sum @@ -1,46 +1,1661 @@ +cel.dev/expr v0.19.0 h1:lXuo+nDhpyJSpWxpPVi5cPUwzKb+dsdOiw6IreM5yt0= +cel.dev/expr v0.19.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= +cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go v0.118.2 h1:bKXO7RXMFDkniAAvvuMrAPtQ/VHrs9e7J5UT3yrGdTY= +cloud.google.com/go v0.118.2/go.mod h1:CFO4UPEPi8oV21xoezZCrd3d81K4fFkDTEJu4R8K+9M= +cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= +cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= +cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/accesscontextmanager v1.7.0/go.mod h1:CEGLewx8dwa33aDAZQujl7Dx+uYhS0eay198wB/VumQ= +cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= +cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= +cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/aiplatform v1.36.1/go.mod h1:WTm12vJRPARNvJ+v6P52RDHCNe4AhvjcIZ/9/RRHy/k= +cloud.google.com/go/aiplatform v1.37.0/go.mod h1:IU2Cv29Lv9oCn/9LkFiiuKfwrRTq+QQMbW+hPCxJGZw= +cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= +cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= +cloud.google.com/go/analytics v0.17.0/go.mod h1:WXFa3WSym4IZ+JiKmavYdJwGG/CvpqiqczmL59bTD9M= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/analytics v0.19.0/go.mod h1:k8liqf5/HCnOUkbawNtrWWc+UAzyDlW89doe8TtoDsE= +cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= +cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= +cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apigeeregistry v0.6.0/go.mod h1:BFNzW7yQVLZ3yj0TKcwzb8n25CFBri51GVGOEUcgQsc= +cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/apikeys v0.6.0/go.mod h1:kbpXu5upyiAlGkKrJgQl8A0rKNNJ7dQ377pdroRSSi8= +cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= +cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/appengine v1.7.0/go.mod h1:eZqpbHFCqRGa2aCdope7eC0SWLV1j0neb/QnMJVWx6A= +cloud.google.com/go/appengine v1.7.1/go.mod h1:IHLToyb/3fKutRysUlFO0BPt5j7RiQ45nrzEJmKTo6E= +cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= +cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= +cloud.google.com/go/area120 v0.7.0/go.mod h1:a3+8EUD1SX5RUcCs3MY5YasiO1z6yLiNLRiFrykbynY= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= +cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= +cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= +cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= +cloud.google.com/go/artifactregistry v1.11.1/go.mod h1:lLYghw+Itq9SONbCa1YWBoWs1nOucMH0pwXN1rOBZFI= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/artifactregistry v1.12.0/go.mod h1:o6P3MIvtzTOnmvGagO9v/rOjjA0HmhJ+/6KAXrmYDCI= +cloud.google.com/go/artifactregistry v1.13.0/go.mod h1:uy/LNfoOIivepGhooAUpL1i30Hgee3Cu0l4VTWHUC08= +cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= +cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= +cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= +cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= +cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/asset v1.12.0/go.mod h1:h9/sFOa4eDIyKmH6QMpm4eUK3pDojWnUhTgJlk762Hg= +cloud.google.com/go/asset v1.13.0/go.mod h1:WQAMyYek/b7NBpYq/K4KJWcRqzoalEsxz/t/dTk4THw= +cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= +cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= +cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= +cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= +cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/auth v0.14.1 h1:AwoJbzUdxA/whv1qj3TLKwh3XX5sikny2fc40wUl+h0= +cloud.google.com/go/auth v0.14.1/go.mod h1:4JHUxlGXisL0AW8kXPtUF6ztuOksyfUQNFjfsOCXkPM= +cloud.google.com/go/auth/oauth2adapt v0.2.7 h1:/Lc7xODdqcEw8IrZ9SvwnlLX6j9FHQM74z6cBk9Rw6M= +cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc= +cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= +cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= +cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= +cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= +cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= +cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= +cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/beyondcorp v0.5.0/go.mod h1:uFqj9X+dSfrheVp7ssLTaRHd2EHqSL4QZmH4e8WXGGU= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= +cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= +cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= +cloud.google.com/go/bigquery v1.47.0/go.mod h1:sA9XOgy0A8vQK9+MWhEQTY6Tix87M/ZurWFIxmF9I/E= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/bigquery v1.49.0/go.mod h1:Sv8hMmTFFYBlt/ftw2uN6dFdQPzBlREY9yBh7Oy7/4Q= +cloud.google.com/go/bigquery v1.50.0/go.mod h1:YrleYEh2pSEbgTBZYMJ5SuSr0ML3ypjRB1zgf7pvQLU= +cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= +cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= +cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= +cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/billing v1.13.0/go.mod h1:7kB2W9Xf98hP9Sr12KfECgfGclsH3CQR0R08tnRlRbc= +cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= +cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= +cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= +cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= +cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= +cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/channel v1.12.0/go.mod h1:VkxCGKASi4Cq7TbXxlaBezonAYpp1GCnKMY6tnMQnLU= +cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= +cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= +cloud.google.com/go/cloudbuild v1.6.0/go.mod h1:UIbc/w9QCbH12xX+ezUsgblrWv+Cv4Tw83GiSMHOn9M= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/cloudbuild v1.9.0/go.mod h1:qK1d7s4QlO0VwfYn5YuClDGg2hfmLZEb4wQGAbIgL1s= +cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= +cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= +cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= +cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= +cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/cloudtasks v1.10.0/go.mod h1:NDSoTLkZ3+vExFEWu2UJV1arUyzVDAiZtdWcsUyNwBs= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= +cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= +cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= +cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= +cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= +cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= +cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= +cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= +cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= +cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/container v1.14.0/go.mod h1:3AoJMPhHfLDxLvrlVWaK57IXzaPnLaZq63WX59aQBfM= +cloud.google.com/go/container v1.15.0/go.mod h1:ft+9S0WGjAyjDggg5S06DXj+fHJICWg8L7isCQe9pQA= +cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= +cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/containeranalysis v0.9.0/go.mod h1:orbOANbwk5Ejoom+s+DUCTTJ7IBdBQJDcSylAx/on9s= +cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= +cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= +cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= +cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= +cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= +cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/datacatalog v1.13.0/go.mod h1:E4Rj9a5ZtAxcQJlEBTLgMTphfP11/lNaAshpoBgemX8= +cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= +cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= +cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= +cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/dataform v0.7.0/go.mod h1:7NulqnVozfHvWUBpMDfKMUESr+85aJsC/2O0o3jWPDE= +cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= +cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= +cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= +cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataplex v1.6.0/go.mod h1:bMsomC/aEJOSpHXdFKFGQ1b0TDPIeL28nJObeO1ppRs= +cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= +cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= +cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastore v1.11.0/go.mod h1:TvGxBIHCS50u8jzG+AW/ppf87v1of8nwzFNgEZU1D3c= +cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= +cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= +cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= +cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/datastream v1.7.0/go.mod h1:uxVRMm2elUSPuh65IbZpzJNMbuzkcvu5CjMqVIUHrww= +cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= +cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/deploy v1.8.0/go.mod h1:z3myEJnA/2wnB4sgjqdMfgxCA0EqC3RBTNcVPs93mtQ= +cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= +cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= +cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= +cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= +cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= +cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dialogflow v1.32.0/go.mod h1:jG9TRJl8CKrDhMEcvfcfFkkpp8ZhgPz3sBGmAUYJ2qE= +cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= +cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= +cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= +cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= +cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/documentai v1.18.0/go.mod h1:F6CK6iUH8J81FehpskRmhLq/3VlwQvb7TvwOceQ2tbs= +cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= +cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= +cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/edgecontainer v1.0.0/go.mod h1:cttArqZpBB2q58W/upSG++ooo6EsblxDIolxa3jSjbY= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= +cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= +cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/eventarc v1.11.0/go.mod h1:PyUjsUKPWoRBCHeOxZd/lbOOjahV41icXyUY5kSTvVY= +cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= +cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/filestore v1.6.0/go.mod h1:di5unNuss/qfZTw2U9nhFqo8/ZDSc466dre85Kydllg= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= +cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= +cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= +cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/functions v1.12.0/go.mod h1:AXWGrF3e2C/5ehvwYo/GH6O5s09tOPksiKhz+hH8WkA= +cloud.google.com/go/functions v1.13.0/go.mod h1:EU4O007sQm6Ef/PwRsI8N2umygGqPBS/IZQKBQBcJ3c= +cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= +cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= +cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= +cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= +cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= +cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= +cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkehub v0.12.0/go.mod h1:djiIwwzTTBrF5NaXCGv3mf7klpEMcST17VBTVVDcuaw= +cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= +cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= +cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= +cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= +cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= +cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= +cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= +cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= +cloud.google.com/go/iam v1.3.1 h1:KFf8SaT71yYq+sQtRISn90Gyhyf4X8RGgeAVC8XGf3E= +cloud.google.com/go/iam v1.3.1/go.mod h1:3wMtuyT4NcbnYNPLMBzYRFiEfjKfJlLVLrisE7bwm34= +cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= +cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/iap v1.7.0/go.mod h1:beqQx56T9O1G1yNPph+spKpNibDlYIiIixiqsQXxLIo= +cloud.google.com/go/iap v1.7.1/go.mod h1:WapEwPc7ZxGt2jFGB/C/bm+hP0Y6NXzOYGjpPnmMS74= +cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= +cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= +cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/iot v1.6.0/go.mod h1:IqdAsmE2cTYYNO1Fvjfzo9po179rAtJeVGUvkLN3rLE= +cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= +cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= +cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= +cloud.google.com/go/kms v1.8.0/go.mod h1:4xFEhYFqvW+4VMELtZyxomGSYtSQKzM178ylFW4jMAg= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24= +cloud.google.com/go/kms v1.10.1/go.mod h1:rIWk/TryCkR59GMC3YtHtXeLzd634lBbKenvyySAyYI= +cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= +cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= +cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= +cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= +cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= +cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/longrunning v0.6.4 h1:3tyw9rO3E2XVXzSApn1gyEEnH2K9SynNQjMlBi3uHLg= +cloud.google.com/go/longrunning v0.6.4/go.mod h1:ttZpLCe6e7EXvn9OxpBRx7kZEB0efv8yBO6YnVMfhJs= +cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= +cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/maps v0.7.0/go.mod h1:3GnvVl3cqeSvgMcpRlQidXsPYuDGQ8naBis7MVzpXsY= +cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= +cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= +cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= +cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= +cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= +cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= +cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= +cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= +cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw= +cloud.google.com/go/monitoring v1.23.0 h1:M3nXww2gn9oZ/qWN2bZ35CjolnVHM3qnSbu6srCPgjk= +cloud.google.com/go/monitoring v1.23.0/go.mod h1:034NnlQPDzrQ64G2Gavhl0LUHZs9H3rRmhtnp7jiJgg= +cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= +cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= +cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= +cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkconnectivity v1.11.0/go.mod h1:iWmDD4QF16VCDLXUqvyspJjIEtBR/4zq5hwnY2X3scM= +cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= +cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= +cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/networksecurity v0.8.0/go.mod h1:B78DkqsxFG5zRSVuwYFRZ9Xz8IcQ5iECsNrPn74hKHU= +cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= +cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= +cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= +cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/notebooks v1.8.0/go.mod h1:Lq6dYKOYOWUCTvw5t2q1gp1lAp0zxAxRycayS0iJcqQ= +cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= +cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= +cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= +cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= +cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= +cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= +cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= +cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= +cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= +cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= +cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= +cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/policytroubleshooter v1.6.0/go.mod h1:zYqaPTsmfvpjm5ULxAyD/lINQxJ0DDsnWOP/GZ7xzBc= +cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= +cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/privatecatalog v0.8.0/go.mod h1:nQ6pfaegeDAq/Q5lrfCQzQLhubPiZhSaNhIgfJlnIXs= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= +cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsub v1.30.0/go.mod h1:qWi1OPS0B+b5L+Sg6Gmc9zD1Y+HaM0MdUr7LsupY1P4= +cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/pubsublite v1.7.0/go.mod h1:8hVMwRXfDfvGm3fahVbtDbiLePT3gpoiJYJY+vxWxVM= +cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= +cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= +cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= +cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= +cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= +cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recaptchaenterprise/v2 v2.7.0/go.mod h1:19wVj/fs5RtYtynAPJdDTb69oW0vNHYDBTbB4NvMD9c= +cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= +cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= +cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= +cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= +cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= +cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= +cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= +cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= +cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcemanager v1.6.0/go.mod h1:YcpXGRs8fDzcUl1Xw8uOVmI8JEadvhRIkoXXUNVYcVo= +cloud.google.com/go/resourcemanager v1.7.0/go.mod h1:HlD3m6+bwhzj9XCouqmeiGuni95NTrExfhoSrkC/3EI= +cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= +cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= +cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= +cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= +cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= +cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/run v0.9.0/go.mod h1:Wwu+/vvg8Y+JUApMwEDfVfhetv30hCG4ZwDR/IXl2Qg= +cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= +cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= +cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= +cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/scheduler v1.9.0/go.mod h1:yexg5t+KSmqu+njTIh3b7oYPheFtBWGcbVUYF1GGMIc= +cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= +cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= +cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= +cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= +cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= +cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= +cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/security v1.13.0/go.mod h1:Q1Nvxl1PAgmeW0y3HTt54JYIvUdtcpYKVfIB8AOMZ+0= +cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= +cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= +cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= +cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/securitycenter v1.19.0/go.mod h1:LVLmSg8ZkkyaNy4u7HCIshAngSQ8EcIRREP3xBnyfag= +cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= +cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= +cloud.google.com/go/servicecontrol v1.10.0/go.mod h1:pQvyvSRh7YzUF2efw7H87V92mxU8FnFDawMClGCNuAA= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicecontrol v1.11.1/go.mod h1:aSnNNlwEFBY+PWGQ2DoM0JJ/QUXqV5/ZD9DOLB7SnUk= +cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= +cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= +cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= +cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicedirectory v1.9.0/go.mod h1:29je5JjiygNYlmsGz8k6o+OZ8vd4f//bQLtvzkPPT/s= +cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= +cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/servicemanagement v1.8.0/go.mod h1:MSS2TDlIEQD/fzsSGfCdJItQveu9NXnUniTrq/L8LK4= +cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= +cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/serviceusage v1.6.0/go.mod h1:R5wwQcbOWsyuOfbP9tGdAnCAc6B9DRwPG1xtWMDeuPA= +cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= +cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M= +cloud.google.com/go/spanner v1.75.0 h1:2zrltTJv/4P3pCgpYgde4Eb1vN8Cgy1fNy7pbTnOovg= +cloud.google.com/go/spanner v1.75.0/go.mod h1:TLFZBvPQmx3We7sGh12eTk9lLsRLczzZaiweqfMpR80= +cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= +cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= +cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= +cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/speech v1.15.0/go.mod h1:y6oH7GhqCaZANH7+Oe0BhgIogsNInLlz542tg3VqeYI= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= +cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= +cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= +cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= +cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= +cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/storagetransfer v1.8.0/go.mod h1:JpegsHHU1eXg7lMHkvf+KE5XDJ7EQu0GwNJbbVGanEw= +cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= +cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= +cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= +cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= +cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= +cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= +cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk= +cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= +cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= +cloud.google.com/go/translate v1.5.0/go.mod h1:29YDSYveqqpA1CQFD7NQuP49xymq17RXNaUDdc0mNu0= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/translate v1.7.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= +cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= +cloud.google.com/go/video v1.12.0/go.mod h1:MLQew95eTuaNDEGriQdcYn0dTwf9oWiA4uYebxM5kdg= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/video v1.14.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= +cloud.google.com/go/video v1.15.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= +cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= +cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= +cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= +cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= +cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= +cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= +cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= +cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vision/v2 v2.7.0/go.mod h1:H89VysHy21avemp6xcf9b9JvZHVehWbET0uT/bcuY/0= +cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= +cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmmigration v1.6.0/go.mod h1:bopQ/g4z+8qXzichC7GW1w2MjbErL54rk3/C843CjfY= +cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vmwareengine v0.3.0/go.mod h1:wvoyMvNWdIzxMYSpH/R7y2h5h3WFkx6d+1TIsP39WGY= +cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= +cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= +cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= +cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= +cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= +cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= +cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= +cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= +cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= +git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.2 h1:DBjmt6/otSdULyJdVg2BlG0qGZO5tKL4VzOs0jpvw5Q= +github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.2/go.mod h1:dppbR7CwXD4pgtV9t3wD1812RaLDcBjtblcDF5f1vI0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 h1:3c8yed4lgqTt+oTQ+JNMDo+F4xprBf+O/il4ZC0nRLw= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0/go.mod h1:obipzmGjfSjam60XLwGfqUkJsfiheAl+TUjG+4yzyPM= +github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= +github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= +github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI= +github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= +github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 h1:QVw89YDxXxEe+l8gU8ETbOasdwEV+avkR75ZzsVV9WI= +github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q= +github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= +github.com/envoyproxy/go-control-plane v0.13.4/go.mod h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA= +github.com/envoyproxy/go-control-plane/envoy v1.32.3 h1:hVEaommgvzTjTd4xCaFd+kEQ2iYBtGxP6luyLrx6uOk= +github.com/envoyproxy/go-control-plane/envoy v1.32.3/go.mod h1:F6hWupPfh75TBXGKA++MCT/CZHFq5r9/uwt/kQYkZfE= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= +github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= +github.com/envoyproxy/go-control-plane/envoy v1.32.3 h1:hVEaommgvzTjTd4xCaFd+kEQ2iYBtGxP6luyLrx6uOk= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= +github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= +github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= +github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= +github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= +github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= +github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U= +github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= +github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= +github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= +github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= +github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= +github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q= +github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA= +github.com/googleapis/go-sql-spanner v1.11.1 h1:z3ThtKV5HFvaNv9UGc26+ggS+lS0dsCAkaFduKL7vws= +github.com/googleapis/go-sql-spanner v1.11.1/go.mod h1:fuA5q4yMS3SZiVfRr5bvksPNk7zUn/irbQW62H/ffZw= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= +github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= +github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= +github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= +github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/detectors/gcp v1.33.0 h1:FVPoXEoILwgbZUu4X7YSgsESsAmGRgoYcnXkzgQPhP4= +go.opentelemetry.io/contrib/detectors/gcp v1.33.0/go.mod h1:ZHrLmr4ikK2AwRj9QL+c9s2SOlgoSRyMpNVzUj2fZqI= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 h1:rgMkmiGfix9vFJDcDi1PK8WEQP4FLQwLDfhp5ZLpFeE= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 h1:rgMkmiGfix9vFJDcDi1PK8WEQP4FLQwLDfhp5ZLpFeE= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s= +go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= +go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= +go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= +go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= +go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= +go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= +go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU= +go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= +go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= +go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= +golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= +golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= +golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= +golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= +golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= +golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= +golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= +gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= +gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= +gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= +google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= +google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= +google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= +google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= +google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= +google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= +google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= +google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= +google.golang.org/api v0.220.0 h1:3oMI4gdBgB72WFVwE1nerDD8W3HUOS4kypK6rRLbGns= +google.golang.org/api v0.220.0/go.mod h1:26ZAlY6aN/8WgpCzjPNy18QpYaz7Zgg1h0qe1GkZEmY= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= +google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= +google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= +google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= +google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA= +google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= +google.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= +google.golang.org/genproto v0.0.0-20230303212802-e74f57abe488/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4 h1:Pw6WnI9W/LIdRxqK7T6XGugGbHIRl5Q7q3BssH6xk4s= +google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4/go.mod h1:qbZzneIOXSq+KFAFut9krLfRLZiFLzZL5u2t8SV83EE= +google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47 h1:5iw9XJTD4thFidQmFVvx0wi4g5yOHk76rNRUxz1ZG5g= +google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47/go.mod h1:AfA77qWLcidQWywD0YgqfpJzf50w2VjzBml3TybHeJU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 h1:2duwAxN2+k0xLNpjnHTXoMUgnv6VPSp5fiqTuwSxjmI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= +google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= +google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= +google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= +lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= +modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= +modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= +modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= +modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= +modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= +modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= +modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= +modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= +modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= +modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= +modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= +modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= +modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= +modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= +modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8= xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU= xorm.io/core v0.7.3 h1:W8ws1PlrnkS1CZU1YWaYLMQcQilwAmQXU0BJDJon+H0= diff --git a/pkg/util/xorm/session_insert.go b/pkg/util/xorm/session_insert.go index bae3dec75e4..42a17d305dd 100644 --- a/pkg/util/xorm/session_insert.go +++ b/pkg/util/xorm/session_insert.go @@ -7,6 +7,7 @@ package xorm import ( "errors" "fmt" + "math/rand" "reflect" "sort" "strconv" @@ -345,6 +346,21 @@ func (session *Session) innerInsert(bean any) (int64, error) { return 0, err } + // XXX: hack to handle autoincrement in spanner + if len(table.AutoIncrement) > 0 && session.engine.dialect.DBType() == "spanner" { + var found bool + for _, col := range colNames { + if col == table.AutoIncrement { + found = true + break + } + } + if !found { + colNames = append(colNames, table.AutoIncrement) + args = append(args, rand.Int63n(9e15)) + } + } + exprs := session.statement.exprColumns colPlaces := strings.Repeat("?, ", len(colNames)) if exprs.Len() <= 0 && len(colPlaces) > 0 { From b7a0aeeb0dcd73434f4dd11530297da9299a7d68 Mon Sep 17 00:00:00 2001 From: linoman <2051016+linoman@users.noreply.github.com> Date: Mon, 3 Mar 2025 17:51:23 +0100 Subject: [PATCH 61/74] SCIM: Disable auto assign organization if the user has been provisioned (#101307) * Add isProvisioned field to model * Add new isProvisioned column to migration * Disable auto assignment to organization if the user is provisioned * add annotation to user model * add annotation to user models * Remove IsProvisioned field from Identity * Move new field assignenment and add default value * Update annotations for user query results * Remove isProvisioned from identity * Add new column to test * Resolve user from identity at SyncOrgHook --- pkg/services/authn/authnimpl/sync/org_sync.go | 10 ++++++++++ pkg/services/sqlstore/migrations/user_mig.go | 6 ++++++ pkg/services/user/model.go | 8 +++++++- pkg/services/user/userimpl/user.go | 3 ++- pkg/services/user/userimpl/user_test.go | 1 + pkg/storage/unified/sql/db/dbimpl/dbimpl_test.go | 1 + 6 files changed, 27 insertions(+), 2 deletions(-) diff --git a/pkg/services/authn/authnimpl/sync/org_sync.go b/pkg/services/authn/authnimpl/sync/org_sync.go index 8742df614ff..f87cd1c7ca0 100644 --- a/pkg/services/authn/authnimpl/sync/org_sync.go +++ b/pkg/services/authn/authnimpl/sync/org_sync.go @@ -50,6 +50,16 @@ func (s *OrgSync) SyncOrgRolesHook(ctx context.Context, id *authn.Identity, _ *a return nil } + // ignore org syncing if the user is provisioned + usr, err := s.userService.GetByID(ctx, &user.GetUserByIDQuery{ID: userID}) + if err != nil { + ctxLogger.Error("Failed to get user from provided identity", "error", err) + return nil + } + if usr.IsProvisioned { + return nil + } + ctxLogger.Debug("Syncing organization roles", "extOrgRoles", id.OrgRoles) // don't sync org roles if none is specified if len(id.OrgRoles) == 0 { diff --git a/pkg/services/sqlstore/migrations/user_mig.go b/pkg/services/sqlstore/migrations/user_mig.go index 68fe8ba9af4..10d4d710701 100644 --- a/pkg/services/sqlstore/migrations/user_mig.go +++ b/pkg/services/sqlstore/migrations/user_mig.go @@ -155,6 +155,12 @@ func addUserMigrations(mg *Migrator) { Cols: []string{"uid"}, Type: UniqueIndex, })) + // Modifies the user table to add a new column is_provisioned to indicate if the user is provisioned + // by SCIM or not. + mg.AddMigration("Add is_provisioned column to user", NewAddColumnMigration(userV2, &Column{ + Name: "is_provisioned", Type: DB_Bool, Nullable: false, Default: "0", + })) + // Service accounts login were not unique per org. this migration is part of making it unique per org // to be able to create service accounts that are unique per org mg.AddMigration(usermig.AllowSameLoginCrossOrgs, &usermig.ServiceAccountsSameLoginCrossOrgs{}) diff --git a/pkg/services/user/model.go b/pkg/services/user/model.go index 118d8d9fb1c..78d9f492e36 100644 --- a/pkg/services/user/model.go +++ b/pkg/services/user/model.go @@ -47,6 +47,8 @@ type User struct { Created time.Time Updated time.Time LastSeenAt time.Time + + IsProvisioned bool `xorm:"is_provisioned"` } type CreateUserCommand struct { @@ -64,6 +66,7 @@ type CreateUserCommand struct { SkipOrgSetup bool DefaultOrgRole string IsServiceAccount bool + IsProvisioned bool } type GetUserByLoginQuery struct { @@ -114,7 +117,8 @@ type SearchUsersQuery struct { SortOpts []model.SortOption Filters []Filter - IsDisabled *bool + IsDisabled *bool + IsProvisioned *bool } type SearchUserQueryResult struct { @@ -137,6 +141,7 @@ type UserSearchHitDTO struct { LastSeenAtAge string `json:"lastSeenAtAge"` AuthLabels []string `json:"authLabels"` AuthModule AuthModuleConversion `json:"-"` + IsProvisioned bool `json:"-" xorm:"is_provisioned"` } type GetUserProfileQuery struct { @@ -161,6 +166,7 @@ type UserProfileDTO struct { CreatedAt time.Time `json:"createdAt"` AvatarURL string `json:"avatarUrl"` AccessControl map[string]bool `json:"accessControl,omitempty"` + IsProvisioned bool `json:"-"` } // implement Conversion interface to define custom field mapping (xorm feature) diff --git a/pkg/services/user/userimpl/user.go b/pkg/services/user/userimpl/user.go index 2f108dcb7d5..68e229d2140 100644 --- a/pkg/services/user/userimpl/user.go +++ b/pkg/services/user/userimpl/user.go @@ -134,6 +134,7 @@ func (s *Service) Create(ctx context.Context, cmd *user.CreateUserCommand) (*use Updated: timeNow(), LastSeenAt: timeNow().AddDate(-10, 0, 0), IsServiceAccount: cmd.IsServiceAccount, + IsProvisioned: cmd.IsProvisioned, } salt, err := util.GetRandomString(10) @@ -164,7 +165,7 @@ func (s *Service) Create(ctx context.Context, cmd *user.CreateUserCommand) (*use } // create org user link - if !cmd.SkipOrgSetup { + if !cmd.SkipOrgSetup && !usr.IsProvisioned { orgUser := org.OrgUser{ OrgID: orgID, UserID: usr.ID, diff --git a/pkg/services/user/userimpl/user_test.go b/pkg/services/user/userimpl/user_test.go index f3e25940f0b..9e24f9c2ffd 100644 --- a/pkg/services/user/userimpl/user_test.go +++ b/pkg/services/user/userimpl/user_test.go @@ -57,6 +57,7 @@ func TestUserService(t *testing.T) { require.Equal(t, "login", u.Login) require.Equal(t, "name", u.Name) require.Equal(t, "email", u.Email) + require.False(t, u.IsProvisioned) }) t.Run("delete user store returns error", func(t *testing.T) { diff --git a/pkg/storage/unified/sql/db/dbimpl/dbimpl_test.go b/pkg/storage/unified/sql/db/dbimpl/dbimpl_test.go index b59fff9e38d..ceb5aea0eee 100644 --- a/pkg/storage/unified/sql/db/dbimpl/dbimpl_test.go +++ b/pkg/storage/unified/sql/db/dbimpl/dbimpl_test.go @@ -69,6 +69,7 @@ func setupDBForGrafana(t *testing.T, ctx context.Context, m cfgMap) { last_seen_at DATETIME NULL, is_disabled INTEGER NOT NULL DEFAULT 0, is_service_account BOOLEAN DEFAULT 0, + is_provisioned BOOLEAN DEFAULT 0, uid TEXT NULL ); CREATE TABLE org ( From c7c68322b1d10c0493463c7313b77e81d2b27d32 Mon Sep 17 00:00:00 2001 From: Alexander Akhmetov Date: Mon, 3 Mar 2025 17:59:01 +0100 Subject: [PATCH 62/74] Alerting: Allow specifying a folder for Prometheus rule import (#101406) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What is this feature? Allows the creation of alert rules with mimirtool in a specified folder. Why do we need this feature? Currently, the APIs for mimirtool create namespaces and rule groups in the root folder without the ability to set a custom folder. For example, it could be a special "Imported" folder, etc. This PR makes it possible with a special header: mimirtool ... --extra-headers="X-Grafana-Alerting-Folder-UID=123". If it's not present, the root folder is used, otherwise, the specified one is used. mimirtool does not support nested folder structures, while Grafana allows folder nesting. To keep compatibility, we return only direct child folders of the working folder (as namespaces) with rule groups and rules that are directly in these child folders as if there are no nested folders. For example, given this folder structure in Grafana: ``` grafana/ ├── production/ │ ├── service1/ │ │ └── alerts/ │ └── service2/ └── testing/ └── service3/ ``` If the working folder is "grafana": Only namespaces "production" and "testing" are returned Only rule groups directly within these folders are included If the working folder is "production": - Only namespaces "service1" and "service2" are returned Only rule groups directly within these folders are included --- .../ngalert/api/api_convert_prometheus.go | 141 +++++- .../api/api_convert_prometheus_test.go | 116 ++++- pkg/services/ngalert/api/authorization.go | 12 +- pkg/services/ngalert/api/persist.go | 6 +- pkg/services/ngalert/store/namespace.go | 36 +- pkg/services/ngalert/store/namespace_test.go | 221 ++++++++- pkg/services/ngalert/tests/fakes/rules.go | 36 +- .../alerting/api_convert_prometheus_test.go | 452 ++++++++++++++++-- pkg/tests/api/alerting/testing.go | 86 +++- 9 files changed, 997 insertions(+), 109 deletions(-) diff --git a/pkg/services/ngalert/api/api_convert_prometheus.go b/pkg/services/ngalert/api/api_convert_prometheus.go index 5dca89080a5..9f38b47db17 100644 --- a/pkg/services/ngalert/api/api_convert_prometheus.go +++ b/pkg/services/ngalert/api/api_convert_prometheus.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "net/http" + "path/filepath" "strconv" "strings" "time" @@ -27,7 +28,14 @@ import ( ) const ( - datasourceUIDHeader = "X-Grafana-Alerting-Datasource-UID" + // datasourceUIDHeader is the name of the header that specifies the UID of the datasource to be used for the rules. + datasourceUIDHeader = "X-Grafana-Alerting-Datasource-UID" + + // If the folderUIDHeader is present, namespaces and rule groups will be created in the specified folder. + // If not, the root folder will be used as the default. + folderUIDHeader = "X-Grafana-Alerting-Folder-UID" + + // These headers control the paused state of newly created rules. By default, rules are not paused. recordingRulesPausedHeader = "X-Grafana-Alerting-Recording-Rules-Paused" alertRulesPausedHeader = "X-Grafana-Alerting-Alert-Rules-Paused" ) @@ -58,6 +66,32 @@ func errInvalidHeaderValue(header string) error { // Rule groups not imported from Prometheus are excluded because their original rule definitions are unavailable. // When a rule group is converted from Prometheus to Grafana, the original definition is preserved alongside // the Grafana rule and used for reading requests here. +// +// Folder Structure Handling: +// mimirtool does not support nested folder structures, while Grafana allows folder nesting. +// To keep compatibility, this service only returns direct child folders of the working folder +// as namespaces, and rule groups and rules that are directly in these child folders. +// +// For example, given this folder structure in Grafana: +// +// grafana/ +// ├── production/ +// │ ├── service1/ +// │ │ └── alerts/ +// │ └── service2/ +// └── testing/ +// └── service3/ +// +// If the working folder is "grafana": +// - Only namespaces "production" and "testing" are returned +// - Only rule groups directly within these folders are included +// +// If the working folder is "production": +// - Only namespaces "service1" and "service2" are returned +// - Only rule groups directly within these folders are included +// +// The "working folder" is specified by the X-Grafana-Alerting-Folder-UID header, which can be set to any folder UID, +// and defaults to the root folder if not provided. type ConvertPrometheusSrv struct { cfg *setting.UnifiedAlertingSettings logger log.Logger @@ -82,8 +116,27 @@ func NewConvertPrometheusSrv(cfg *setting.UnifiedAlertingSettings, logger log.Lo func (srv *ConvertPrometheusSrv) RouteConvertPrometheusGetRules(c *contextmodel.ReqContext) response.Response { logger := srv.logger.FromContext(c.Req.Context()) + workingFolderUID := getWorkingFolderUID(c) + logger = logger.New("working_folder_uid", workingFolderUID) + + folders, err := srv.ruleStore.GetNamespaceChildren(c.Req.Context(), workingFolderUID, c.SignedInUser.GetOrgID(), c.SignedInUser) + if len(folders) == 0 || errors.Is(err, dashboards.ErrFolderNotFound) { + // If there is no such folder or no children, return empty response + // because mimirtool expects 200 OK response in this case. + return response.YAML(http.StatusOK, map[string][]apimodels.PrometheusRuleGroup{}) + } + if err != nil { + logger.Error("Failed to get folders", "error", err) + return errorToResponse(err) + } + folderUIDs := make([]string, 0, len(folders)) + for _, f := range folders { + folderUIDs = append(folderUIDs, f.UID) + } + filterOpts := &provisioning.FilterOptions{ ImportedPrometheusRule: util.Pointer(true), + NamespaceUIDs: folderUIDs, } groups, err := srv.alertRuleService.GetAlertGroupsWithFolderFullpath(c.Req.Context(), c.SignedInUser, filterOpts) if err != nil { @@ -105,8 +158,11 @@ func (srv *ConvertPrometheusSrv) RouteConvertPrometheusGetRules(c *contextmodel. func (srv *ConvertPrometheusSrv) RouteConvertPrometheusDeleteNamespace(c *contextmodel.ReqContext, namespaceTitle string) response.Response { logger := srv.logger.FromContext(c.Req.Context()) - logger.Debug("Looking up folder in the root by title", "folder_title", namespaceTitle) - namespace, err := srv.ruleStore.GetNamespaceInRootByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.GetOrgID(), c.SignedInUser) + workingFolderUID := getWorkingFolderUID(c) + logger = logger.New("working_folder_uid", workingFolderUID) + + logger.Debug("Looking up folder by title", "folder_title", namespaceTitle) + namespace, err := srv.ruleStore.GetNamespaceByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.GetOrgID(), c.SignedInUser, workingFolderUID) if err != nil { return namespaceErrorResponse(err) } @@ -117,6 +173,9 @@ func (srv *ConvertPrometheusSrv) RouteConvertPrometheusDeleteNamespace(c *contex ImportedPrometheusRule: util.Pointer(true), } err = srv.alertRuleService.DeleteRuleGroups(c.Req.Context(), c.SignedInUser, models.ProvenanceConvertedPrometheus, filterOpts) + if errors.Is(err, models.ErrAlertRuleGroupNotFound) { + return response.Empty(http.StatusNotFound) + } if err != nil { logger.Error("Failed to delete rule groups", "folder_uid", namespace.UID, "error", err) return errorToResponse(err) @@ -129,14 +188,20 @@ func (srv *ConvertPrometheusSrv) RouteConvertPrometheusDeleteNamespace(c *contex func (srv *ConvertPrometheusSrv) RouteConvertPrometheusDeleteRuleGroup(c *contextmodel.ReqContext, namespaceTitle string, group string) response.Response { logger := srv.logger.FromContext(c.Req.Context()) - logger.Debug("Looking up folder in the root by title", "folder_title", namespaceTitle) - folder, err := srv.ruleStore.GetNamespaceInRootByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.GetOrgID(), c.SignedInUser) + workingFolderUID := getWorkingFolderUID(c) + logger = logger.New("working_folder_uid", workingFolderUID) + + logger.Debug("Looking up folder by title", "folder_title", namespaceTitle) + folder, err := srv.ruleStore.GetNamespaceByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.GetOrgID(), c.SignedInUser, workingFolderUID) if err != nil { return namespaceErrorResponse(err) } logger.Info("Deleting Prometheus-imported rule group", "folder_uid", folder.UID, "folder_title", namespaceTitle, "group", group) err = srv.alertRuleService.DeleteRuleGroup(c.Req.Context(), c.SignedInUser, folder.UID, group, models.ProvenanceConvertedPrometheus) + if errors.Is(err, models.ErrAlertRuleGroupNotFound) { + return response.Empty(http.StatusNotFound) + } if err != nil { logger.Error("Failed to delete rule group", "folder_uid", folder.UID, "group", group, "error", err) return errorToResponse(err) @@ -150,8 +215,11 @@ func (srv *ConvertPrometheusSrv) RouteConvertPrometheusDeleteRuleGroup(c *contex func (srv *ConvertPrometheusSrv) RouteConvertPrometheusGetNamespace(c *contextmodel.ReqContext, namespaceTitle string) response.Response { logger := srv.logger.FromContext(c.Req.Context()) - logger.Debug("Looking up folder in the root by title", "folder_title", namespaceTitle) - namespace, err := srv.ruleStore.GetNamespaceInRootByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.GetOrgID(), c.SignedInUser) + workingFolderUID := getWorkingFolderUID(c) + logger = logger.New("working_folder_uid", workingFolderUID) + + logger.Debug("Looking up folder by title", "folder_title", namespaceTitle) + namespace, err := srv.ruleStore.GetNamespaceByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.GetOrgID(), c.SignedInUser, workingFolderUID) if err != nil { logger.Error("Failed to get folder", "error", err) return namespaceErrorResponse(err) @@ -181,12 +249,18 @@ func (srv *ConvertPrometheusSrv) RouteConvertPrometheusGetNamespace(c *contextmo func (srv *ConvertPrometheusSrv) RouteConvertPrometheusGetRuleGroup(c *contextmodel.ReqContext, namespaceTitle string, group string) response.Response { logger := srv.logger.FromContext(c.Req.Context()) - logger.Debug("Looking up folder in the root by title", "folder_title", namespaceTitle) - namespace, err := srv.ruleStore.GetNamespaceInRootByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.GetOrgID(), c.SignedInUser) + workingFolderUID := getWorkingFolderUID(c) + logger = logger.New("working_folder_uid", workingFolderUID) + + logger.Debug("Looking up folder by title", "folder_title", namespaceTitle) + namespace, err := srv.ruleStore.GetNamespaceByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.GetOrgID(), c.SignedInUser, workingFolderUID) if err != nil { logger.Error("Failed to get folder", "error", err) return namespaceErrorResponse(err) } + if namespace == nil { + return response.Error(http.StatusNotFound, "Folder not found", nil) + } filterOpts := &provisioning.FilterOptions{ ImportedPrometheusRule: util.Pointer(true), @@ -223,11 +297,13 @@ func (srv *ConvertPrometheusSrv) RouteConvertPrometheusGetRuleGroup(c *contextmo // it will not be replaced and an error will be returned. func (srv *ConvertPrometheusSrv) RouteConvertPrometheusPostRuleGroup(c *contextmodel.ReqContext, namespaceTitle string, promGroup apimodels.PrometheusRuleGroup) response.Response { logger := srv.logger.FromContext(c.Req.Context()) - logger = logger.New("folder_title", namespaceTitle, "group", promGroup.Name) + + workingFolderUID := getWorkingFolderUID(c) + logger = logger.New("folder_title", namespaceTitle, "group", promGroup.Name, "working_folder_uid", workingFolderUID) logger.Info("Converting Prometheus rule group", "rules", len(promGroup.Rules)) - ns, errResp := srv.getOrCreateNamespace(c, namespaceTitle, logger) + ns, errResp := srv.getOrCreateNamespace(c, namespaceTitle, logger, workingFolderUID) if errResp != nil { return errResp } @@ -257,18 +333,19 @@ func (srv *ConvertPrometheusSrv) RouteConvertPrometheusPostRuleGroup(c *contextm return successfulResponse() } -func (srv *ConvertPrometheusSrv) getOrCreateNamespace(c *contextmodel.ReqContext, title string, logger log.Logger) (*folder.Folder, response.Response) { +func (srv *ConvertPrometheusSrv) getOrCreateNamespace(c *contextmodel.ReqContext, title string, logger log.Logger, workingFolderUID string) (*folder.Folder, response.Response) { logger.Debug("Getting or creating a new folder") - ns, err := srv.ruleStore.GetOrCreateNamespaceInRootByTitle( + ns, err := srv.ruleStore.GetOrCreateNamespaceByTitle( c.Req.Context(), title, c.SignedInUser.GetOrgID(), c.SignedInUser, + workingFolderUID, ) if err != nil { logger.Error("Failed to get or create a new folder", "error", err) - return nil, toNamespaceErrorResponse(err) + return nil, namespaceErrorResponse(err) } logger.Debug("Using folder for the converted rules", "folder_uid", ns.UID) @@ -351,11 +428,17 @@ func grafanaNamespacesToPrometheus(groups []models.AlertRuleGroupWithFolderFullp result := map[string][]apimodels.PrometheusRuleGroup{} for _, group := range groups { + // Since the folder can be nested but mimirtool does not support nested paths, + // we need to use only the last folder in the full path. + // For example, if the current working folder is "general" and the full path is "grafana/some folder/general/production", + // we should use the "production" folder. + folder := filepath.Base(group.FolderFullpath) + promGroup, err := grafanaRuleGroupToPrometheus(group.Title, group.Rules) if err != nil { return nil, err } - result[group.FolderFullpath] = append(result[group.FolderFullpath], promGroup) + result[folder] = append(result[folder], promGroup) } return result, nil @@ -388,18 +471,26 @@ func grafanaRuleGroupToPrometheus(group string, rules []models.AlertRule) (apimo return promGroup, nil } -func namespaceErrorResponse(err error) response.Response { - if errors.Is(err, dashboards.ErrFolderAccessDenied) { - // If there is no such folder, the error is ErrFolderAccessDenied. - // We should return 404 in this case, otherwise mimirtool does not work correctly. - return response.Empty(http.StatusNotFound) - } - - return toNamespaceErrorResponse(err) -} - func successfulResponse() response.Response { return response.JSON(http.StatusAccepted, apimodels.ConvertPrometheusResponse{ Status: "success", }) } + +// getWorkingFolderUID returns the value of the folderUIDHeader +// if present. Otherwise, it returns the UID of the root folder. +func getWorkingFolderUID(c *contextmodel.ReqContext) string { + folderUID := strings.TrimSpace(c.Req.Header.Get(folderUIDHeader)) + if folderUID != "" { + return folderUID + } + return folder.RootFolderUID +} + +func namespaceErrorResponse(err error) response.Response { + if errors.Is(err, dashboards.ErrFolderNotFound) { + return response.Empty(http.StatusNotFound) + } + + return toNamespaceErrorResponse(err) +} diff --git a/pkg/services/ngalert/api/api_convert_prometheus_test.go b/pkg/services/ngalert/api/api_convert_prometheus_test.go index 51b378d437c..945a0558365 100644 --- a/pkg/services/ngalert/api/api_convert_prometheus_test.go +++ b/pkg/services/ngalert/api/api_convert_prometheus_test.go @@ -397,8 +397,8 @@ func TestRouteConvertPrometheusGetNamespace(t *testing.T) { require.NoError(t, err) require.Len(t, respNamespaces, 1) - require.Contains(t, respNamespaces, fldr.Fullpath) - require.ElementsMatch(t, respNamespaces[fldr.Fullpath], []apimodels.PrometheusRuleGroup{promGroup1, promGroup2}) + require.Contains(t, respNamespaces, fldr.Title) + require.ElementsMatch(t, respNamespaces[fldr.Title], []apimodels.PrometheusRuleGroup{promGroup1, promGroup2}) }) } @@ -442,17 +442,53 @@ func TestRouteConvertPrometheusGetRules(t *testing.T) { }, } - t.Run("with no rules should return empty response", func(t *testing.T) { - srv, _, _, _ := createConvertPrometheusSrv(t) - rc := createRequestCtx() + assertEmptyResponse := func(t *testing.T, srv *ConvertPrometheusSrv, reqCtx *contextmodel.ReqContext) { + t.Helper() - response := srv.RouteConvertPrometheusGetRules(rc) + response := srv.RouteConvertPrometheusGetRules(reqCtx) require.Equal(t, http.StatusOK, response.Status()) var respNamespaces map[string][]apimodels.PrometheusRuleGroup err := yaml.Unmarshal(response.Body(), &respNamespaces) require.NoError(t, err) require.Empty(t, respNamespaces) + } + + // testForEmptyResponses tests that RouteConvertPrometheusGetRules returns an empty response + // when there are no rules in the folder or the folder does not exist. + testForEmptyResponses := func(t *testing.T, withCustomFolderHeader bool) { + rc := createRequestCtx() + unknownFolderUID := "some unknown folder" + rootFolderUID := "" + if withCustomFolderHeader { + rootFolderUID = unknownFolderUID + rc.Context.Req.Header.Set(folderUIDHeader, unknownFolderUID) + } + + t.Run("for non-existent folder should return empty response", func(t *testing.T) { + srv, _, _, _ := createConvertPrometheusSrv(t) + assertEmptyResponse(t, srv, rc) + }) + + t.Run("for existing folder with no children should return empty response", func(t *testing.T) { + srv, _, ruleStore, folderService := createConvertPrometheusSrv(t) + + fldr := randFolder() + fldr.UID = unknownFolderUID + fldr.ParentUID = rootFolderUID + folderService.ExpectedFolders = []*folder.Folder{fldr} + ruleStore.Folders[1] = append(ruleStore.Folders[1], fldr) + + assertEmptyResponse(t, srv, rc) + }) + } + + t.Run("without custom root folder", func(t *testing.T) { + testForEmptyResponses(t, false) + }) + + t.Run("with custom root folder", func(t *testing.T) { + testForEmptyResponses(t, true) }) t.Run("with rules should return 200 with rules", func(t *testing.T) { @@ -489,8 +525,8 @@ func TestRouteConvertPrometheusGetRules(t *testing.T) { require.NoError(t, err) require.Len(t, respNamespaces, 1) - require.Contains(t, respNamespaces, fldr.Fullpath) - require.ElementsMatch(t, respNamespaces[fldr.Fullpath], []apimodels.PrometheusRuleGroup{promGroup1, promGroup2}) + require.Contains(t, respNamespaces, fldr.Title) + require.ElementsMatch(t, respNamespaces[fldr.Title], []apimodels.PrometheusRuleGroup{promGroup1, promGroup2}) }) } @@ -503,6 +539,20 @@ func TestRouteConvertPrometheusDeleteNamespace(t *testing.T) { require.Equal(t, http.StatusNotFound, response.Status()) }) + t.Run("for existing folder with no groups should return 404", func(t *testing.T) { + srv, _, ruleStore, folderService := createConvertPrometheusSrv(t) + rc := createRequestCtx() + + fldr := randFolder() + fldr.ParentUID = "" + folderService.ExpectedFolder = fldr + folderService.ExpectedFolders = []*folder.Folder{fldr} + ruleStore.Folders[1] = append(ruleStore.Folders[1], fldr) + + response := srv.RouteConvertPrometheusDeleteNamespace(rc, "non-existent") + require.Equal(t, http.StatusNotFound, response.Status()) + }) + t.Run("valid request should delete rules", func(t *testing.T) { initNamespace := func(promDefinition string, opts ...convertPrometheusSrvOptionsFunc) (*ConvertPrometheusSrv, *fakes.RuleStore, *folder.Folder, *models.AlertRule) { srv, _, ruleStore, folderService := createConvertPrometheusSrv(t, opts...) @@ -596,6 +646,20 @@ func TestRouteConvertPrometheusDeleteRuleGroup(t *testing.T) { require.Equal(t, http.StatusNotFound, response.Status()) }) + t.Run("for existing folder with no group should return 404", func(t *testing.T) { + srv, _, ruleStore, folderService := createConvertPrometheusSrv(t) + rc := createRequestCtx() + + fldr := randFolder() + fldr.ParentUID = "" + folderService.ExpectedFolder = fldr + folderService.ExpectedFolders = []*folder.Folder{fldr} + ruleStore.Folders[1] = append(ruleStore.Folders[1], fldr) + + response := srv.RouteConvertPrometheusDeleteRuleGroup(rc, fldr.Title, "test-group") + require.Equal(t, http.StatusNotFound, response.Status()) + }) + const groupName = "test-group" t.Run("valid request should delete rules", func(t *testing.T) { @@ -758,3 +822,39 @@ func createRequestCtx() *contextmodel.ReqContext { SignedInUser: &user.SignedInUser{OrgID: 1}, } } + +func TestGetWorkingFolderUID(t *testing.T) { + t.Run("should return root folder UID when header is not present", func(t *testing.T) { + rc := createRequestCtx() + rc.Req.Header.Del(folderUIDHeader) + + folderUID := getWorkingFolderUID(rc) + require.Equal(t, folder.RootFolderUID, folderUID) + }) + + t.Run("should return specified folder UID when header is present", func(t *testing.T) { + rc := createRequestCtx() + specifiedFolderUID := "specified-folder-uid" + rc.Req.Header.Set(folderUIDHeader, specifiedFolderUID) + + folderUID := getWorkingFolderUID(rc) + require.Equal(t, specifiedFolderUID, folderUID) + }) + + t.Run("should return root folder UID when header is empty", func(t *testing.T) { + rc := createRequestCtx() + rc.Req.Header.Set(folderUIDHeader, "") + + folderUID := getWorkingFolderUID(rc) + require.Equal(t, folder.RootFolderUID, folderUID) + }) + + t.Run("should trim whitespace from header value", func(t *testing.T) { + rc := createRequestCtx() + specifiedFolderUID := "specified-folder-uid" + rc.Req.Header.Set(folderUIDHeader, " "+specifiedFolderUID+" ") + + folderUID := getWorkingFolderUID(rc) + require.Equal(t, specifiedFolderUID, folderUID) + }) +} diff --git a/pkg/services/ngalert/api/authorization.go b/pkg/services/ngalert/api/authorization.go index 4dce6e33015..42d85b03a32 100644 --- a/pkg/services/ngalert/api/authorization.go +++ b/pkg/services/ngalert/api/authorization.go @@ -151,13 +151,11 @@ func (api *API) authorize(method, path string) web.Handler { http.MethodDelete + "/api/convert/api/prom/rules/{NamespaceTitle}/{Group}", http.MethodDelete + "/api/convert/prometheus/config/v1/rules/{NamespaceTitle}", http.MethodDelete + "/api/convert/api/prom/rules/{NamespaceTitle}": - eval = ac.EvalAny( - ac.EvalAll( - ac.EvalPermission(ac.ActionAlertingRuleRead), - ac.EvalPermission(dashboards.ActionFoldersRead), - ac.EvalPermission(ac.ActionAlertingRuleDelete), - ac.EvalPermission(ac.ActionAlertingProvisioningSetStatus), - ), + eval = ac.EvalAll( + ac.EvalPermission(ac.ActionAlertingRuleRead), + ac.EvalPermission(dashboards.ActionFoldersRead), + ac.EvalPermission(ac.ActionAlertingRuleDelete), + ac.EvalPermission(ac.ActionAlertingProvisioningSetStatus), ) // Alert Instances and Silences diff --git a/pkg/services/ngalert/api/persist.go b/pkg/services/ngalert/api/persist.go index 228f62cf24e..d2e81d833e2 100644 --- a/pkg/services/ngalert/api/persist.go +++ b/pkg/services/ngalert/api/persist.go @@ -15,8 +15,10 @@ type RuleStore interface { // by returning map[string]struct{} instead of map[string]*folder.Folder GetUserVisibleNamespaces(context.Context, int64, identity.Requester) (map[string]*folder.Folder, error) GetNamespaceByUID(ctx context.Context, uid string, orgID int64, user identity.Requester) (*folder.Folder, error) - GetNamespaceInRootByTitle(ctx context.Context, fullpath string, orgID int64, user identity.Requester) (*folder.Folder, error) - GetOrCreateNamespaceInRootByTitle(ctx context.Context, title string, orgID int64, user identity.Requester) (*folder.Folder, error) + GetNamespaceByTitle(ctx context.Context, fullpath string, orgID int64, user identity.Requester, parentUID string) (*folder.Folder, error) + GetOrCreateNamespaceByTitle(ctx context.Context, title string, orgID int64, user identity.Requester, parentUID string) (*folder.Folder, error) + // GetNamespaceChildren returns all children (first level) of the namespace with the given id. + GetNamespaceChildren(ctx context.Context, uid string, orgID int64, user identity.Requester) ([]*folder.Folder, error) GetAlertRuleByUID(ctx context.Context, query *ngmodels.GetAlertRuleByUIDQuery) (*ngmodels.AlertRule, error) GetAlertRulesGroupByRuleUID(ctx context.Context, query *ngmodels.GetAlertRulesGroupByRuleUIDQuery) ([]*ngmodels.AlertRule, error) diff --git a/pkg/services/ngalert/store/namespace.go b/pkg/services/ngalert/store/namespace.go index 9279ff840f9..2e00ed40371 100644 --- a/pkg/services/ngalert/store/namespace.go +++ b/pkg/services/ngalert/store/namespace.go @@ -40,10 +40,10 @@ func (st DBstore) GetNamespaceByUID(ctx context.Context, uid string, orgID int64 return f[0], nil } -// GetNamespaceInRootByTitle gets namespace by its title in the root folder. -func (st DBstore) GetNamespaceInRootByTitle(ctx context.Context, title string, orgID int64, user identity.Requester) (*folder.Folder, error) { +// GetNamespaceChildren gets namespace (folder) children (first level) by its UID. +func (st DBstore) GetNamespaceChildren(ctx context.Context, uid string, orgID int64, user identity.Requester) ([]*folder.Folder, error) { q := &folder.GetChildrenQuery{ - UID: folder.RootFolderUID, + UID: uid, OrgID: orgID, SignedInUser: user, } @@ -52,15 +52,32 @@ func (st DBstore) GetNamespaceInRootByTitle(ctx context.Context, title string, o return nil, err } + found := make([]*folder.Folder, 0, len(folders)) + for _, f := range folders { + if f.ParentUID == uid { + found = append(found, f) + } + } + + return found, nil +} + +// GetNamespaceByTitle gets namespace by its title in the specified folder. +func (st DBstore) GetNamespaceByTitle(ctx context.Context, title string, orgID int64, user identity.Requester, parentUID string) (*folder.Folder, error) { + folders, err := st.GetNamespaceChildren(ctx, parentUID, orgID, user) + if err != nil { + return nil, err + } + foundByTitle := []*folder.Folder{} for _, f := range folders { - if f.Title == title && f.ParentUID == folder.RootFolderUID { + if f.Title == title { foundByTitle = append(foundByTitle, f) } } if len(foundByTitle) == 0 { - return nil, dashboards.ErrFolderAccessDenied + return nil, dashboards.ErrFolderNotFound } // Sort by UID to return the first folder in case of multiple folders with the same title @@ -71,13 +88,13 @@ func (st DBstore) GetNamespaceInRootByTitle(ctx context.Context, title string, o return foundByTitle[0], nil } -// GetOrCreateNamespaceInRootByTitle gets or creates a namespace by title in the _root_ folder. -func (st DBstore) GetOrCreateNamespaceInRootByTitle(ctx context.Context, title string, orgID int64, user identity.Requester) (*folder.Folder, error) { +// GetOrCreateNamespaceByTitle gets or creates a namespace by title in the specified folder. +func (st DBstore) GetOrCreateNamespaceByTitle(ctx context.Context, title string, orgID int64, user identity.Requester, parentUID string) (*folder.Folder, error) { var f *folder.Folder var err error - f, err = st.GetNamespaceInRootByTitle(ctx, title, orgID, user) - if err != nil && !errors.Is(err, dashboards.ErrFolderAccessDenied) { + f, err = st.GetNamespaceByTitle(ctx, title, orgID, user, parentUID) + if err != nil && !errors.Is(err, dashboards.ErrFolderNotFound) { return nil, err } @@ -86,6 +103,7 @@ func (st DBstore) GetOrCreateNamespaceInRootByTitle(ctx context.Context, title s OrgID: orgID, Title: title, SignedInUser: user, + ParentUID: parentUID, } f, err = st.FolderService.Create(ctx, cmd) if err != nil { diff --git a/pkg/services/ngalert/store/namespace_test.go b/pkg/services/ngalert/store/namespace_test.go index 8ba163a1080..7693122cee6 100644 --- a/pkg/services/ngalert/store/namespace_test.go +++ b/pkg/services/ngalert/store/namespace_test.go @@ -13,6 +13,7 @@ import ( "github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/setting" @@ -123,7 +124,7 @@ func TestIntegration_GetNamespaceByUID(t *testing.T) { }) } -func TestIntegration_GetNamespaceInRootByTitle(t *testing.T) { +func TestIntegration_GetNamespaceByTitle(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } @@ -143,17 +144,45 @@ func TestIntegration_GetNamespaceInRootByTitle(t *testing.T) { IsGrafanaAdmin: true, } - uid := uuid.NewString() - title := "folder-title" - createFolder(t, store, uid, title, 1, "") + // Create parent folder + parentUID := uuid.NewString() + parentTitle := "parent-folder" + createFolder(t, store, parentUID, parentTitle, 1, "") - actual, err := store.GetNamespaceInRootByTitle(context.Background(), title, 1, u) - require.NoError(t, err) - require.Equal(t, title, actual.Title) - require.Equal(t, uid, actual.UID) + // Create child folder under parent + childUID := uuid.NewString() + childTitle := "child-folder" + createFolder(t, store, childUID, childTitle, 1, parentUID) + + // Create another folder with same title but under root + sameTitleInRoot := uuid.NewString() + createFolder(t, store, sameTitleInRoot, childTitle, 1, "") + + t.Run("should find folder by title and parent UID", func(t *testing.T) { + actual, err := store.GetNamespaceByTitle(context.Background(), childTitle, 1, u, parentUID) + require.NoError(t, err) + require.Equal(t, childTitle, actual.Title) + require.Equal(t, childUID, actual.UID) + require.Equal(t, parentUID, actual.ParentUID) + }) + + t.Run("should find folder by title in root", func(t *testing.T) { + actual, err := store.GetNamespaceByTitle(context.Background(), childTitle, 1, u, folder.RootFolderUID) + require.NoError(t, err) + require.Equal(t, childTitle, actual.Title) + require.Equal(t, sameTitleInRoot, actual.UID) + require.Equal(t, folder.RootFolderUID, actual.ParentUID) + }) + + t.Run("should return ErrFolderNotFound when folder with title doesn't exist under specified parent", func(t *testing.T) { + nonExistentTitle := "non-existent-folder" + f, err := store.GetNamespaceByTitle(context.Background(), nonExistentTitle, 1, u, parentUID) + require.Nil(t, f) + require.ErrorIs(t, err, dashboards.ErrFolderNotFound) + }) } -func TestIntegration_GetOrCreateNamespaceInRootByTitle(t *testing.T) { +func TestIntegration_GetOrCreateNamespaceByTitle(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } @@ -180,10 +209,11 @@ func TestIntegration_GetOrCreateNamespaceInRootByTitle(t *testing.T) { t.Run("should create folder when it does not exist", func(t *testing.T) { store := setupStore(t) - f, err := store.GetOrCreateNamespaceInRootByTitle(context.Background(), "new folder", 1, u) + f, err := store.GetOrCreateNamespaceByTitle(context.Background(), "new folder", 1, u, folder.RootFolderUID) require.NoError(t, err) require.Equal(t, "new folder", f.Title) require.NotEmpty(t, f.UID) + require.Equal(t, folder.RootFolderUID, f.ParentUID) folders, err := store.FolderService.GetFolders( context.Background(), @@ -202,7 +232,7 @@ func TestIntegration_GetOrCreateNamespaceInRootByTitle(t *testing.T) { title := "existing folder" createFolder(t, store, "", title, 1, "") - f, err := store.GetOrCreateNamespaceInRootByTitle(context.Background(), title, 1, u) + f, err := store.GetOrCreateNamespaceByTitle(context.Background(), title, 1, u, folder.RootFolderUID) require.NoError(t, err) require.Equal(t, title, f.Title) @@ -217,4 +247,173 @@ func TestIntegration_GetOrCreateNamespaceInRootByTitle(t *testing.T) { require.NoError(t, err) require.Len(t, folders, 1) }) + + t.Run("should create folder under specified parent when it does not exist", func(t *testing.T) { + store := setupStore(t) + + // Create parent folder first + parentTitle := "parent folder" + parentFolder, err := store.GetOrCreateNamespaceByTitle(context.Background(), parentTitle, 1, u, folder.RootFolderUID) + require.NoError(t, err) + + // Now create a child folder under the parent + childTitle := "child folder" + childFolder, err := store.GetOrCreateNamespaceByTitle(context.Background(), childTitle, 1, u, parentFolder.UID) + require.NoError(t, err) + + // Verify the child folder was created under the parent + folders, err := store.FolderService.GetChildren(context.Background(), &folder.GetChildrenQuery{UID: parentFolder.UID, OrgID: 1, SignedInUser: u}) + require.NoError(t, err) + require.Len(t, folders, 1) + require.Equal(t, childFolder.UID, folders[0].UID) + + folders, err = store.FolderService.GetChildren(context.Background(), &folder.GetChildrenQuery{UID: folder.RootFolderUID, OrgID: 1, SignedInUser: u}) + require.NoError(t, err) + require.Len(t, folders, 1) + require.Equal(t, parentFolder.UID, folders[0].UID) + }) + + t.Run("should get correct folder when same title exists under different parents", func(t *testing.T) { + store := setupStore(t) + + // Create first parent folder + parent1Title := "parent folder 1" + parent1, err := store.GetOrCreateNamespaceByTitle(context.Background(), parent1Title, 1, u, folder.RootFolderUID) + require.NoError(t, err) + + // Create second parent folder + parent2Title := "parent folder 2" + parent2, err := store.GetOrCreateNamespaceByTitle(context.Background(), parent2Title, 1, u, folder.RootFolderUID) + require.NoError(t, err) + + // Create folders with same title under different parents + sameTitle := "same title folder" + + // Create under first parent + folder1, err := store.GetOrCreateNamespaceByTitle(context.Background(), sameTitle, 1, u, parent1.UID) + require.NoError(t, err) + + // Create under second parent + folder2, err := store.GetOrCreateNamespaceByTitle(context.Background(), sameTitle, 1, u, parent2.UID) + require.NoError(t, err) + + // Create under root + folder3, err := store.GetOrCreateNamespaceByTitle(context.Background(), sameTitle, 1, u, folder.RootFolderUID) + require.NoError(t, err) + + // Verify we get the correct folders when specifying the parent + gotFolder1, err := store.GetOrCreateNamespaceByTitle(context.Background(), sameTitle, 1, u, parent1.UID) + require.NoError(t, err) + require.Equal(t, folder1.UID, gotFolder1.UID) + require.Equal(t, parent1.UID, gotFolder1.ParentUID) + + gotFolder2, err := store.GetOrCreateNamespaceByTitle(context.Background(), sameTitle, 1, u, parent2.UID) + require.NoError(t, err) + require.Equal(t, folder2.UID, gotFolder2.UID) + require.Equal(t, parent2.UID, gotFolder2.ParentUID) + + gotFolder3, err := store.GetOrCreateNamespaceByTitle(context.Background(), sameTitle, 1, u, folder.RootFolderUID) + require.NoError(t, err) + require.Equal(t, folder3.UID, gotFolder3.UID) + require.Equal(t, folder.RootFolderUID, gotFolder3.ParentUID) + }) +} + +func TestIntegration_GetNamespaceChildren(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test") + } + + sqlStore := db.InitTestDB(t) + cfg := setting.NewCfg() + folderService := setupFolderService(t, sqlStore, cfg, featuremgmt.WithFeatures()) + b := &fakeBus{} + logger := log.New("test-dbstore") + store := createTestStore(sqlStore, folderService, logger, cfg.UnifiedAlerting, b) + store.FolderService = setupFolderService(t, sqlStore, cfg, featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)) + + admin := &user.SignedInUser{ + UserID: 1, + OrgID: 1, + OrgRole: org.RoleAdmin, + IsGrafanaAdmin: true, + } + + // Create root folders + rootFolder1 := uuid.NewString() + rootFolder2 := uuid.NewString() + createFolder(t, store, rootFolder1, "Root Folder 1", 1, "") + createFolder(t, store, rootFolder2, "Root Folder 2", 1, "") + + // Create child folders under root folder 1 + child1 := uuid.NewString() + child2 := uuid.NewString() + createFolder(t, store, child1, "Child Folder 1", 1, rootFolder1) + createFolder(t, store, child2, "Child Folder 2", 1, rootFolder1) + + // Create nested child under child1 + nestedChild := uuid.NewString() + createFolder(t, store, nestedChild, "Nested Child", 1, child1) + + differentOrgID := int64(999) + createFolder(t, store, util.GenerateShortUID(), "Root Folder 1", differentOrgID, "") + + /* + * Folder structure: + * + * Root Folder 1 + * - Child Folder 1 + * - Nested Child + * - Child Folder 2 + * Root Folder 2 + */ + + t.Run("should return direct children of a folder", func(t *testing.T) { + children, err := store.GetNamespaceChildren(context.Background(), rootFolder1, 1, admin) + require.NoError(t, err) + require.Len(t, children, 2) + + require.ElementsMatch(t, []string{child1, child2}, []string{children[0].UID, children[1].UID}) + + // Verify parent UID + for _, child := range children { + require.Equal(t, rootFolder1, child.ParentUID) + } + }) + + t.Run("should return direct children of a nested folder", func(t *testing.T) { + children, err := store.GetNamespaceChildren(context.Background(), child1, 1, admin) + require.NoError(t, err) + require.Len(t, children, 1) + require.Equal(t, nestedChild, children[0].UID) + require.Equal(t, child1, children[0].ParentUID) + }) + + t.Run("should return nil when folder does not exist", func(t *testing.T) { + nonExistentUID := uuid.NewString() + children, err := store.GetNamespaceChildren(context.Background(), nonExistentUID, 1, admin) + require.NotNil(t, children) + require.Empty(t, children) + require.Nil(t, err) + }) + + t.Run("should return empty array for folders with no children", func(t *testing.T) { + children, err := store.GetNamespaceChildren(context.Background(), rootFolder2, 1, admin) + require.Empty(t, children) + require.NotNil(t, children) + require.Nil(t, err) + }) + + t.Run("should return no children for a different org", func(t *testing.T) { + children, err := store.GetNamespaceChildren(context.Background(), rootFolder1, differentOrgID, admin) + require.Empty(t, children) + require.Nil(t, err) + }) + + t.Run("should return children from root folder", func(t *testing.T) { + children, err := store.GetNamespaceChildren(context.Background(), "", 1, admin) + require.NoError(t, err) + require.Equal(t, len(children), 2) + require.ElementsMatch(t, []string{rootFolder1, rootFolder2}, []string{children[0].UID, children[1].UID}) + }) } diff --git a/pkg/services/ngalert/tests/fakes/rules.go b/pkg/services/ngalert/tests/fakes/rules.go index 1a3e4ce9a63..cb90d3bfb77 100644 --- a/pkg/services/ngalert/tests/fakes/rules.go +++ b/pkg/services/ngalert/tests/fakes/rules.go @@ -268,33 +268,34 @@ func (f *RuleStore) GetNamespaceByUID(_ context.Context, uid string, orgID int64 return nil, fmt.Errorf("not found") } -func (f *RuleStore) GetOrCreateNamespaceInRootByTitle(ctx context.Context, title string, orgID int64, user identity.Requester) (*folder.Folder, error) { +func (f *RuleStore) GetOrCreateNamespaceByTitle(ctx context.Context, title string, orgID int64, user identity.Requester, parentUID string) (*folder.Folder, error) { f.mtx.Lock() defer f.mtx.Unlock() for _, folder := range f.Folders[orgID] { - if folder.Title == title { + if folder.Title == title && folder.ParentUID == parentUID { return folder, nil } } newFolder := &folder.Folder{ - ID: rand.Int63(), // nolint:staticcheck - UID: util.GenerateShortUID(), - Title: title, - Fullpath: "fullpath_" + title, + ID: rand.Int63(), // nolint:staticcheck + UID: util.GenerateShortUID(), + Title: title, + ParentUID: parentUID, + Fullpath: "fullpath_" + title, } f.Folders[orgID] = append(f.Folders[orgID], newFolder) return newFolder, nil } -func (f *RuleStore) GetNamespaceInRootByTitle(ctx context.Context, title string, orgID int64, user identity.Requester) (*folder.Folder, error) { +func (f *RuleStore) GetNamespaceByTitle(ctx context.Context, title string, orgID int64, user identity.Requester, parentUID string) (*folder.Folder, error) { f.mtx.Lock() defer f.mtx.Unlock() for _, folder := range f.Folders[orgID] { - if folder.Title == title && folder.ParentUID == "" { + if folder.Title == title && folder.ParentUID == parentUID { return folder, nil } } @@ -302,6 +303,25 @@ func (f *RuleStore) GetNamespaceInRootByTitle(ctx context.Context, title string, return nil, dashboards.ErrFolderNotFound } +func (f *RuleStore) GetNamespaceChildren(ctx context.Context, uid string, orgID int64, user identity.Requester) ([]*folder.Folder, error) { + f.mtx.Lock() + defer f.mtx.Unlock() + + result := []*folder.Folder{} + + for _, folder := range f.Folders[orgID] { + if folder.ParentUID == uid { + result = append(result, folder) + } + } + + if len(result) == 0 { + return nil, dashboards.ErrFolderNotFound + } + + return result, nil +} + func (f *RuleStore) UpdateAlertRules(_ context.Context, _ *models.UserUID, q []models.UpdateRule) error { f.mtx.Lock() defer f.mtx.Unlock() diff --git a/pkg/tests/api/alerting/api_convert_prometheus_test.go b/pkg/tests/api/alerting/api_convert_prometheus_test.go index 780e11a1d15..48f09332ebb 100644 --- a/pkg/tests/api/alerting/api_convert_prometheus_test.go +++ b/pkg/tests/api/alerting/api_convert_prometheus_test.go @@ -135,14 +135,11 @@ func TestIntegrationConvertPrometheusEndpoints(t *testing.T) { ds := apiClient.CreateDatasource(t, datasources.DS_PROMETHEUS) t.Run("create rule groups and get them back", func(t *testing.T) { - _, status, body := apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup1, nil) - requireStatusCode(t, http.StatusAccepted, status, body) - _, status, body = apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup2, nil) - requireStatusCode(t, http.StatusAccepted, status, body) + apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup1, nil) + apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup2, nil) // create a third group in a different namespace - _, status, body = apiClient.ConvertPrometheusPostRuleGroup(t, namespace2, ds.Body.Datasource.UID, promGroup3, nil) - requireStatusCode(t, http.StatusAccepted, status, body) + apiClient.ConvertPrometheusPostRuleGroup(t, namespace2, ds.Body.Datasource.UID, promGroup3, nil) // And a non-provisioned rule in another namespace namespace3UID := util.GenerateShortUID() @@ -150,18 +147,18 @@ func TestIntegrationConvertPrometheusEndpoints(t *testing.T) { createRule(t, apiClient, namespace3UID) // Now get the first group - group1 := apiClient.ConvertPrometheusGetRuleGroupRules(t, namespace1, promGroup1.Name) + group1 := apiClient.ConvertPrometheusGetRuleGroupRules(t, namespace1, promGroup1.Name, nil) require.Equal(t, promGroup1, group1) // Get namespace1 - ns1 := apiClient.ConvertPrometheusGetNamespaceRules(t, namespace1) + ns1 := apiClient.ConvertPrometheusGetNamespaceRules(t, namespace1, nil) expectedNs1 := map[string][]apimodels.PrometheusRuleGroup{ namespace1: {promGroup1, promGroup2}, } require.Equal(t, expectedNs1, ns1) // Get all namespaces - namespaces := apiClient.ConvertPrometheusGetAllRules(t) + namespaces := apiClient.ConvertPrometheusGetAllRules(t, nil) expectedNamespaces := map[string][]apimodels.PrometheusRuleGroup{ namespace1: {promGroup1, promGroup2}, namespace2: {promGroup3}, @@ -170,22 +167,21 @@ func TestIntegrationConvertPrometheusEndpoints(t *testing.T) { }) t.Run("without permissions to create folders cannot create rule groups either", func(t *testing.T) { - _, status, raw := viewerClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup1, nil) + _, status, raw := viewerClient.RawConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup1, nil) requireStatusCode(t, http.StatusForbidden, status, raw) }) t.Run("delete one rule group", func(t *testing.T) { - _, status, body := apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup1, nil) - requireStatusCode(t, http.StatusAccepted, status, body) - _, status, body = apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup2, nil) - requireStatusCode(t, http.StatusAccepted, status, body) - _, status, body = apiClient.ConvertPrometheusPostRuleGroup(t, namespace2, ds.Body.Datasource.UID, promGroup3, nil) - requireStatusCode(t, http.StatusAccepted, status, body) + // Create three groups + apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup1, nil) + apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup2, nil) + apiClient.ConvertPrometheusPostRuleGroup(t, namespace2, ds.Body.Datasource.UID, promGroup3, nil) - apiClient.ConvertPrometheusDeleteRuleGroup(t, namespace1, promGroup1.Name) + // delete the first one + apiClient.ConvertPrometheusDeleteRuleGroup(t, namespace1, promGroup1.Name, nil) // Check that the promGroup2 and promGroup3 are still there - namespaces := apiClient.ConvertPrometheusGetAllRules(t) + namespaces := apiClient.ConvertPrometheusGetAllRules(t, nil) expectedNamespaces := map[string][]apimodels.PrometheusRuleGroup{ namespace1: {promGroup2}, namespace2: {promGroup3}, @@ -193,10 +189,10 @@ func TestIntegrationConvertPrometheusEndpoints(t *testing.T) { require.Equal(t, expectedNamespaces, namespaces) // Delete the second namespace - apiClient.ConvertPrometheusDeleteNamespace(t, namespace2) + apiClient.ConvertPrometheusDeleteNamespace(t, namespace2, nil) // Check that only the first namespace is left - namespaces = apiClient.ConvertPrometheusGetAllRules(t) + namespaces = apiClient.ConvertPrometheusGetAllRules(t, nil) expectedNamespaces = map[string][]apimodels.PrometheusRuleGroup{ namespace1: {promGroup2}, } @@ -268,11 +264,10 @@ func TestIntegrationConvertPrometheusEndpoints_UpdateRule(t *testing.T) { t.Run("update a rule", func(t *testing.T) { // Create the rule group - _, status, body := apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup, nil) - requireStatusCode(t, http.StatusAccepted, status, body) + apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup, nil) // Now get the group - group1 := apiClient.ConvertPrometheusGetRuleGroupRules(t, namespace1, promGroup.Name) + group1 := apiClient.ConvertPrometheusGetRuleGroupRules(t, namespace1, promGroup.Name, nil) require.Equal(t, promGroup, group1) // Update the rule group interval @@ -283,11 +278,10 @@ func TestIntegrationConvertPrometheusEndpoints_UpdateRule(t *testing.T) { promGroup.Rules[0].Labels["another-label"] = "something" promGroup.Rules[0].Annotations["another-annotation"] = "also-something" // Update the group - _, status, body = apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup, nil) - requireStatusCode(t, http.StatusAccepted, status, body) + apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup, nil) // Now get the group again and check that the rule group has been updated - group1 = apiClient.ConvertPrometheusGetRuleGroupRules(t, namespace1, promGroup.Name) + group1 = apiClient.ConvertPrometheusGetRuleGroupRules(t, namespace1, promGroup.Name, nil) require.Equal(t, promGroup, group1) }) } @@ -374,7 +368,7 @@ func TestIntegrationConvertPrometheusEndpoints_Conflict(t *testing.T) { require.Equalf(t, http.StatusOK, status, response) // Should fail to post the group - _, status, body := apiClient.ConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup1, nil) + _, status, body := apiClient.RawConvertPrometheusPostRuleGroup(t, namespace1, ds.Body.Datasource.UID, promGroup1, nil) requireStatusCode(t, http.StatusConflict, status, body) }) } @@ -410,6 +404,7 @@ func TestIntegrationConvertPrometheusEndpoints_CreatePausedRules(t *testing.T) { Login: "admin", }) apiClient := newAlertingApiClient(grafanaListedAddr, "admin", "password") + apiClient.prometheusConversionUseLokiPaths = enableLokiPaths ds := apiClient.CreateDatasource(t, datasources.DS_PROMETHEUS) @@ -499,3 +494,406 @@ func TestIntegrationConvertPrometheusEndpoints_CreatePausedRules(t *testing.T) { runTest(t, true) }) } + +func TestIntegrationConvertPrometheusEndpoints_FolderUIDHeader(t *testing.T) { + runTest := func(t *testing.T, enableLokiPaths bool) { + testinfra.SQLiteIntegrationTest(t) + + folderUIDHeader := "X-Grafana-Alerting-Folder-UID" + + // Setup Grafana and its Database + dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ + DisableLegacyAlerting: true, + EnableUnifiedAlerting: true, + DisableAnonymous: true, + AppModeProduction: true, + EnableFeatureToggles: []string{"alertingConversionAPI"}, + }) + + grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path) + + createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ + DefaultOrgRole: string(org.RoleAdmin), + Password: "password", + Login: "admin", + }) + apiClient := newAlertingApiClient(grafanaListedAddr, "admin", "password") + apiClient.prometheusConversionUseLokiPaths = enableLokiPaths + + ds := apiClient.CreateDatasource(t, datasources.DS_PROMETHEUS) + + // Create a parent folder + parentFolderUID := util.GenerateShortUID() + parentFolderTitle := "parent-folder" + apiClient.CreateFolder(t, parentFolderUID, parentFolderTitle) + + // Create a child folder inside the parent folder + childFolderUID := util.GenerateShortUID() + childFolderTitle := "child-folder" + apiClient.CreateFolder(t, childFolderUID, childFolderTitle, parentFolderUID) + + // Create another folder in root + otherFolderUID := util.GenerateShortUID() + otherFolderTitle := "other-folder" + apiClient.CreateFolder(t, otherFolderUID, otherFolderTitle) + + t.Run("create and delete rule groups with folder UID header", func(t *testing.T) { + // Post the namespace to parentFolderUID, it should create a new folder with the namespace name, + // and put the rule group in it. + headers := map[string]string{ + folderUIDHeader: parentFolderUID, + } + apiClient.ConvertPrometheusPostRuleGroup(t, childFolderTitle, ds.Body.Datasource.UID, promGroup1, headers) + + // Check that it's not visible when we get all namespaces from the root. + namespaces := apiClient.ConvertPrometheusGetAllRules(t, nil) + require.Empty(t, namespaces) + + // Post the group2 to the root, it should create a new folder with the namespace name. + apiClient.ConvertPrometheusPostRuleGroup(t, otherFolderTitle, ds.Body.Datasource.UID, promGroup2, nil) + + // Now we should have: + // - parentFolderUID/child-folder/test-group-1 + // - other-folder/test-group-2 + + // Verify the rule group was created in the child folder + // + // First try to get the group in the root folder, it should not be found + _, status, resp := apiClient.RawConvertPrometheusGetRuleGroupRules(t, childFolderTitle, promGroup1.Name, nil) + require.Equal(t, http.StatusNotFound, status, resp) + // Now try to get the group in the child folder + group1 := apiClient.ConvertPrometheusGetRuleGroupRules(t, childFolderTitle, promGroup1.Name, headers) + require.Equal(t, promGroup1, group1) + + // Verify the rule group was created in the other folder + group2 := apiClient.ConvertPrometheusGetRuleGroupRules(t, otherFolderTitle, promGroup2.Name, nil) + require.Equal(t, promGroup2, group2) + }) + + t.Run("empty folder UID header defaults to root", func(t *testing.T) { + // Create a folder at root level + rootFolderUID := util.GenerateShortUID() + rootFolderTitle := "root-folder" + apiClient.CreateFolder(t, rootFolderUID, rootFolderTitle) + + // Use empty folder UID header which should default to root + headers := map[string]string{ + folderUIDHeader: "", + } + + apiClient.ConvertPrometheusPostRuleGroup(t, rootFolderTitle, ds.Body.Datasource.UID, promGroup3, headers) + + // Verify the rule group was created + group := apiClient.ConvertPrometheusGetRuleGroupRules(t, rootFolderTitle, promGroup3.Name, headers) + require.Equal(t, promGroup3, group) + }) + } + + t.Run("with the mimirtool paths", func(t *testing.T) { + runTest(t, false) + }) + + t.Run("with the cortextool Loki paths", func(t *testing.T) { + runTest(t, true) + }) +} + +func TestIntegrationConvertPrometheusEndpoints_Delete(t *testing.T) { + runTest := func(t *testing.T, enableLokiPaths bool) { + testinfra.SQLiteIntegrationTest(t) + + // Setup Grafana and its Database + dir, gpath := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ + DisableLegacyAlerting: true, + EnableUnifiedAlerting: true, + DisableAnonymous: true, + AppModeProduction: true, + EnableFeatureToggles: []string{"alertingConversionAPI"}, + }) + + grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, gpath) + + // Create users with different permissions + createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ + DefaultOrgRole: string(org.RoleAdmin), + Password: "password", + Login: "admin", + }) + adminClient := newAlertingApiClient(grafanaListedAddr, "admin", "password") + adminClient.prometheusConversionUseLokiPaths = enableLokiPaths + + createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ + DefaultOrgRole: string(org.RoleEditor), + Password: "password", + Login: "editor", + }) + editorClient := newAlertingApiClient(grafanaListedAddr, "editor", "password") + editorClient.prometheusConversionUseLokiPaths = enableLokiPaths + + createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ + DefaultOrgRole: string(org.RoleViewer), + Password: "password", + Login: "viewer", + }) + viewerClient := newAlertingApiClient(grafanaListedAddr, "viewer", "password") + viewerClient.prometheusConversionUseLokiPaths = enableLokiPaths + + // Create a user with no access + createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ + DefaultOrgRole: string(org.RoleNone), + Password: "password", + Login: "no-role-user", + }) + noRoleClient := newAlertingApiClient(grafanaListedAddr, "no-role-user", "password") + noRoleClient.prometheusConversionUseLokiPaths = enableLokiPaths + + ds := adminClient.CreateDatasource(t, datasources.DS_PROMETHEUS) + + t.Run("delete non-existent namespace returns 404", func(t *testing.T) { + nonExistentNamespace := "non-existent-namespace-" + util.GenerateShortUID() + _, status, raw := adminClient.RawConvertPrometheusDeleteNamespace(t, nonExistentNamespace, nil) + requireStatusCode(t, http.StatusNotFound, status, raw) + }) + + t.Run("delete non-existent rule group returns not found", func(t *testing.T) { + nonExistentNamespace := "non-existent-namespace-" + util.GenerateShortUID() + nonExistentGroup := "non-existent-group-" + util.GenerateShortUID() + _, status, raw := adminClient.RawConvertPrometheusDeleteRuleGroup(t, nonExistentNamespace, nonExistentGroup, nil) + requireStatusCode(t, http.StatusNotFound, status, raw) + }) + + t.Run("delete rule group from existing namespace that has no rule groups", func(t *testing.T) { + // Create a namespace but don't add any rule groups to it + emptyNamespace := "empty-namespace-" + util.GenerateShortUID() + emptyNamespaceUID := util.GenerateShortUID() + adminClient.CreateFolder(t, emptyNamespaceUID, emptyNamespace) + + // Try to delete a non-existent rule group from that namespace + nonExistentGroup := "non-existent-group-" + util.GenerateShortUID() + _, status, raw := adminClient.RawConvertPrometheusDeleteRuleGroup(t, emptyNamespace, nonExistentGroup, nil) + requireStatusCode(t, http.StatusNotFound, status, raw) + }) + + t.Run("delete rule group then verify it's gone", func(t *testing.T) { + // Create namespace and rule group + namespace := "test-namespace-delete-" + util.GenerateShortUID() + namespaceUID := util.GenerateShortUID() + adminClient.CreateFolder(t, namespaceUID, namespace) + + // Create rule group + adminClient.ConvertPrometheusPostRuleGroup(t, namespace, ds.Body.Datasource.UID, promGroup1, nil) + + // Verify the rule group exists + group := adminClient.ConvertPrometheusGetRuleGroupRules(t, namespace, promGroup1.Name, nil) + require.Equal(t, promGroup1.Name, group.Name) + + // Delete the rule group + adminClient.ConvertPrometheusDeleteRuleGroup(t, namespace, promGroup1.Name, nil) + + // Verify the rule group is gone + _, status, _ := adminClient.RawConvertPrometheusGetRuleGroupRules(t, namespace, promGroup1.Name, nil) + require.Equal(t, http.StatusNotFound, status) + }) + + t.Run("delete namespace then verify it's empty", func(t *testing.T) { + // Create namespace with two rule groups + namespace := "test-namespace-delete-all-" + util.GenerateShortUID() + namespaceUID := util.GenerateShortUID() + adminClient.CreateFolder(t, namespaceUID, namespace) + + // Create rule groups + adminClient.ConvertPrometheusPostRuleGroup(t, namespace, ds.Body.Datasource.UID, promGroup1, nil) + adminClient.ConvertPrometheusPostRuleGroup(t, namespace, ds.Body.Datasource.UID, promGroup2, nil) + + // Verify the namespace has rule groups + groups := adminClient.ConvertPrometheusGetNamespaceRules(t, namespace, nil) + require.ElementsMatch(t, groups[namespace], []apimodels.PrometheusRuleGroup{promGroup1, promGroup2}) + + // Delete the namespace + adminClient.ConvertPrometheusDeleteNamespace(t, namespace, nil) + + // Verify the namespace is empty + namespaces := adminClient.ConvertPrometheusGetAllRules(t, nil) + _, exists := namespaces[namespace] + require.False(t, exists) + }) + + t.Run("delete specific rule group leaves other groups intact", func(t *testing.T) { + // Create namespace with two rule groups + namespace := "test-namespace-delete-one-" + util.GenerateShortUID() + namespaceUID := util.GenerateShortUID() + adminClient.CreateFolder(t, namespaceUID, namespace) + + // Create rule groups + adminClient.ConvertPrometheusPostRuleGroup(t, namespace, ds.Body.Datasource.UID, promGroup1, nil) + adminClient.ConvertPrometheusPostRuleGroup(t, namespace, ds.Body.Datasource.UID, promGroup2, nil) + + // Delete one rule group + adminClient.ConvertPrometheusDeleteRuleGroup(t, namespace, promGroup1.Name, nil) + + // Verify the other rule group still exists + groups := adminClient.ConvertPrometheusGetNamespaceRules(t, namespace, nil) + require.ElementsMatch(t, groups[namespace], []apimodels.PrometheusRuleGroup{promGroup2}) + }) + + t.Run("viewer cannot delete rule groups", func(t *testing.T) { + // Create namespace and rule group as admin + namespace := "test-namespace-viewer-" + util.GenerateShortUID() + namespaceUID := util.GenerateShortUID() + adminClient.CreateFolder(t, namespaceUID, namespace) + + adminClient.ConvertPrometheusPostRuleGroup(t, namespace, ds.Body.Datasource.UID, promGroup1, nil) + + // Try to delete as viewer - this should return 403 Forbidden + _, status, body := viewerClient.RawConvertPrometheusDeleteRuleGroup(t, namespace, promGroup1.Name, nil) + requireStatusCode(t, http.StatusForbidden, status, body) + + // Verify the rule group still exists + group := adminClient.ConvertPrometheusGetRuleGroupRules(t, namespace, promGroup1.Name, nil) + require.Equal(t, promGroup1.Name, group.Name) + }) + + t.Run("viewer cannot delete namespaces", func(t *testing.T) { + // Create namespace and rule group as admin + namespace := "test-namespace-viewer-ns-" + util.GenerateShortUID() + namespaceUID := util.GenerateShortUID() + adminClient.CreateFolder(t, namespaceUID, namespace) + + adminClient.ConvertPrometheusPostRuleGroup(t, namespace, ds.Body.Datasource.UID, promGroup1, nil) + + // Try to delete as viewer - this should return 403 Forbidden + _, status, body := viewerClient.RawConvertPrometheusDeleteNamespace(t, namespace, nil) + requireStatusCode(t, http.StatusForbidden, status, body) + + // Verify the namespace still exists + namespaces := adminClient.ConvertPrometheusGetAllRules(t, nil) + _, exists := namespaces[namespace] + require.True(t, exists) + }) + + t.Run("deleting rule group with nested folder structure using header", func(t *testing.T) { + // Create parent folder + parentFolder := "parent-folder-" + util.GenerateShortUID() + parentFolderUID := util.GenerateShortUID() + adminClient.CreateFolder(t, parentFolderUID, parentFolder) + + // Create child folder inside parent + childFolder := "child-folder-" + util.GenerateShortUID() + childFolderUID := util.GenerateShortUID() + adminClient.CreateFolder(t, childFolderUID, childFolder, parentFolderUID) + + // Create rule group in child folder + headers := map[string]string{ + "X-Grafana-Alerting-Folder-UID": parentFolderUID, + } + adminClient.ConvertPrometheusPostRuleGroup(t, childFolder, ds.Body.Datasource.UID, promGroup1, headers) + + // Verify the rule group exists + group := adminClient.ConvertPrometheusGetRuleGroupRules(t, childFolder, promGroup1.Name, headers) + require.Equal(t, promGroup1.Name, group.Name) + + // Delete the rule group + adminClient.ConvertPrometheusDeleteRuleGroup(t, childFolder, promGroup1.Name, headers) + + // Verify the rule group is gone + _, status, _ := adminClient.RawConvertPrometheusGetRuleGroupRules(t, childFolder, promGroup1.Name, headers) + require.Equal(t, http.StatusNotFound, status) + }) + + t.Run("deleting namespace with nested folder structure using header", func(t *testing.T) { + // Create parent folder + parentFolder := "parent-folder-ns-" + util.GenerateShortUID() + parentFolderUID := util.GenerateShortUID() + adminClient.CreateFolder(t, parentFolderUID, parentFolder) + + // Create child folder inside parent + childFolder := "child-folder-ns-" + util.GenerateShortUID() + childFolderUID := util.GenerateShortUID() + adminClient.CreateFolder(t, childFolderUID, childFolder, parentFolderUID) + + // Create rule groups in child folder + headers := map[string]string{ + "X-Grafana-Alerting-Folder-UID": parentFolderUID, + } + adminClient.ConvertPrometheusPostRuleGroup(t, childFolder, ds.Body.Datasource.UID, promGroup1, headers) + adminClient.ConvertPrometheusPostRuleGroup(t, childFolder, ds.Body.Datasource.UID, promGroup2, headers) + + // And a rule group in the parent folder + adminClient.ConvertPrometheusPostRuleGroup(t, parentFolder, ds.Body.Datasource.UID, promGroup3, nil) + + // Verify both namespaces have rule groups + groups := adminClient.ConvertPrometheusGetNamespaceRules(t, childFolder, headers) + require.ElementsMatch(t, groups[childFolder], []apimodels.PrometheusRuleGroup{promGroup1, promGroup2}) + require.Empty(t, groups[parentFolder]) + + parentGroups := adminClient.ConvertPrometheusGetNamespaceRules(t, parentFolder, nil) + require.Empty(t, parentGroups[childFolder]) + require.ElementsMatch(t, parentGroups[parentFolder], []apimodels.PrometheusRuleGroup{promGroup3}) + + // Delete the child namespace + adminClient.ConvertPrometheusDeleteNamespace(t, childFolder, headers) + + // Verify the namespace is empty + namespaces := adminClient.ConvertPrometheusGetAllRules(t, headers) + _, exists := namespaces[childFolder] + require.False(t, exists) + + // But the parent folder still has its rule group + parentGroups = adminClient.ConvertPrometheusGetNamespaceRules(t, parentFolder, nil) + require.ElementsMatch(t, parentGroups[parentFolder], []apimodels.PrometheusRuleGroup{promGroup3}) + }) + + t.Run("editor can delete rule group they created", func(t *testing.T) { + // Create namespace as admin + namespace := "test-namespace-editor-" + util.GenerateShortUID() + namespaceUID := util.GenerateShortUID() + adminClient.CreateFolder(t, namespaceUID, namespace) + + // Create rule group as editor + editorClient.ConvertPrometheusPostRuleGroup(t, namespace, ds.Body.Datasource.UID, promGroup1, nil) + + // Verify the rule group exists + group := editorClient.ConvertPrometheusGetRuleGroupRules(t, namespace, promGroup1.Name, nil) + require.Equal(t, promGroup1.Name, group.Name) + + // Delete as editor + editorClient.ConvertPrometheusDeleteRuleGroup(t, namespace, promGroup1.Name, nil) + + // Verify the rule group is gone + _, status, _ := editorClient.RawConvertPrometheusGetRuleGroupRules(t, namespace, promGroup1.Name, nil) + require.Equal(t, http.StatusNotFound, status) + }) + + t.Run("user with no role cannot delete rule groups", func(t *testing.T) { + // Create namespace and rule group as admin + namespace := "test-namespace-no-role-" + util.GenerateShortUID() + namespaceUID := util.GenerateShortUID() + adminClient.CreateFolder(t, namespaceUID, namespace) + + adminClient.ConvertPrometheusPostRuleGroup(t, namespace, ds.Body.Datasource.UID, promGroup1, nil) + + _, status, body := noRoleClient.RawConvertPrometheusDeleteRuleGroup(t, namespace, promGroup1.Name, nil) + requireStatusCode(t, http.StatusForbidden, status, body) + }) + + t.Run("user with no role cannot delete namespaces", func(t *testing.T) { + // Create namespace and rule group as admin + namespace := "test-namespace-no-role-ns-" + util.GenerateShortUID() + namespaceUID := util.GenerateShortUID() + adminClient.CreateFolder(t, namespaceUID, namespace) + + adminClient.ConvertPrometheusPostRuleGroup(t, namespace, ds.Body.Datasource.UID, promGroup1, nil) + + _, status, body := noRoleClient.RawConvertPrometheusDeleteNamespace(t, namespace, nil) + requireStatusCode(t, http.StatusForbidden, status, body) + }) + } + + t.Run("with the mimirtool paths", func(t *testing.T) { + runTest(t, false) + }) + + t.Run("with the cortextool Loki paths", func(t *testing.T) { + runTest(t, true) + }) +} diff --git a/pkg/tests/api/alerting/testing.go b/pkg/tests/api/alerting/testing.go index 5e1e34f63bf..f613d7a5547 100644 --- a/pkg/tests/api/alerting/testing.go +++ b/pkg/tests/api/alerting/testing.go @@ -1102,14 +1102,28 @@ func (a apiClient) GetRuleByUID(t *testing.T, ruleUID string) apimodels.Gettable return rule } -func (a apiClient) ConvertPrometheusPostRuleGroup(t *testing.T, namespaceTitle, datasourceUID string, promGroup apimodels.PrometheusRuleGroup, headers map[string]string) (apimodels.ConvertPrometheusResponse, int, string) { +func (a apiClient) ConvertPrometheusPostRuleGroup(t *testing.T, namespaceTitle, datasourceUID string, promGroup apimodels.PrometheusRuleGroup, headers map[string]string) apimodels.ConvertPrometheusResponse { t.Helper() + resp, status, body := a.RawConvertPrometheusPostRuleGroup(t, namespaceTitle, datasourceUID, promGroup, headers) + requireStatusCode(t, http.StatusAccepted, status, body) + + return resp +} + +func (a apiClient) RawConvertPrometheusPostRuleGroup(t *testing.T, namespaceTitle, datasourceUID string, promGroup apimodels.PrometheusRuleGroup, headers map[string]string) (apimodels.ConvertPrometheusResponse, int, string) { + t.Helper() + + path := "%s/api/convert/prometheus/config/v1/rules/%s" + if a.prometheusConversionUseLokiPaths { + path = "%s/api/convert/api/prom/rules/%s" + } + data, err := yaml.Marshal(promGroup) require.NoError(t, err) buf := bytes.NewReader(data) - req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/api/convert/prometheus/config/v1/rules/%s", a.url, namespaceTitle), buf) + req, err := http.NewRequest(http.MethodPost, fmt.Sprintf(path, a.url, namespaceTitle), buf) require.NoError(t, err) req.Header.Add("X-Grafana-Alerting-Datasource-UID", datasourceUID) @@ -1120,7 +1134,16 @@ func (a apiClient) ConvertPrometheusPostRuleGroup(t *testing.T, namespaceTitle, return sendRequestJSON[apimodels.ConvertPrometheusResponse](t, req, http.StatusAccepted) } -func (a apiClient) ConvertPrometheusGetRuleGroupRules(t *testing.T, namespaceTitle, groupName string) apimodels.PrometheusRuleGroup { +func (a apiClient) ConvertPrometheusGetRuleGroupRules(t *testing.T, namespaceTitle, groupName string, headers map[string]string) apimodels.PrometheusRuleGroup { + t.Helper() + + rule, status, raw := a.RawConvertPrometheusGetRuleGroupRules(t, namespaceTitle, groupName, headers) + requireStatusCode(t, http.StatusOK, status, raw) + + return rule +} + +func (a apiClient) RawConvertPrometheusGetRuleGroupRules(t *testing.T, namespaceTitle, groupName string, headers map[string]string) (apimodels.PrometheusRuleGroup, int, string) { t.Helper() path := "%s/api/convert/prometheus/config/v1/rules/%s/%s" @@ -1130,12 +1153,17 @@ func (a apiClient) ConvertPrometheusGetRuleGroupRules(t *testing.T, namespaceTit req, err := http.NewRequest(http.MethodGet, fmt.Sprintf(path, a.url, namespaceTitle, groupName), nil) require.NoError(t, err) + + for key, value := range headers { + req.Header.Add(key, value) + } + rule, status, raw := sendRequestYAML[apimodels.PrometheusRuleGroup](t, req, http.StatusOK) - requireStatusCode(t, http.StatusOK, status, raw) - return rule + + return rule, status, raw } -func (a apiClient) ConvertPrometheusGetNamespaceRules(t *testing.T, namespaceTitle string) map[string][]apimodels.PrometheusRuleGroup { +func (a apiClient) ConvertPrometheusGetNamespaceRules(t *testing.T, namespaceTitle string, headers map[string]string) map[string][]apimodels.PrometheusRuleGroup { t.Helper() path := "%s/api/convert/prometheus/config/v1/rules/%s" @@ -1145,12 +1173,18 @@ func (a apiClient) ConvertPrometheusGetNamespaceRules(t *testing.T, namespaceTit req, err := http.NewRequest(http.MethodGet, fmt.Sprintf(path, a.url, namespaceTitle), nil) require.NoError(t, err) + + for key, value := range headers { + req.Header.Add(key, value) + } + ns, status, raw := sendRequestYAML[map[string][]apimodels.PrometheusRuleGroup](t, req, http.StatusOK) requireStatusCode(t, http.StatusOK, status, raw) + return ns } -func (a apiClient) ConvertPrometheusGetAllRules(t *testing.T) map[string][]apimodels.PrometheusRuleGroup { +func (a apiClient) ConvertPrometheusGetAllRules(t *testing.T, headers map[string]string) map[string][]apimodels.PrometheusRuleGroup { t.Helper() path := "%s/api/convert/prometheus/config/v1/rules" @@ -1160,12 +1194,25 @@ func (a apiClient) ConvertPrometheusGetAllRules(t *testing.T) map[string][]apimo req, err := http.NewRequest(http.MethodGet, fmt.Sprintf(path, a.url), nil) require.NoError(t, err) + + for key, value := range headers { + req.Header.Add(key, value) + } + result, status, raw := sendRequestYAML[map[string][]apimodels.PrometheusRuleGroup](t, req, http.StatusOK) requireStatusCode(t, http.StatusOK, status, raw) + return result } -func (a apiClient) ConvertPrometheusDeleteRuleGroup(t *testing.T, namespaceTitle, groupName string) { +func (a apiClient) ConvertPrometheusDeleteRuleGroup(t *testing.T, namespaceTitle, groupName string, headers map[string]string) { + t.Helper() + + _, status, raw := a.RawConvertPrometheusDeleteRuleGroup(t, namespaceTitle, groupName, headers) + requireStatusCode(t, http.StatusAccepted, status, raw) +} + +func (a apiClient) RawConvertPrometheusDeleteRuleGroup(t *testing.T, namespaceTitle, groupName string, headers map[string]string) (apimodels.ConvertPrometheusResponse, int, string) { t.Helper() path := "%s/api/convert/prometheus/config/v1/rules/%s/%s" @@ -1175,11 +1222,22 @@ func (a apiClient) ConvertPrometheusDeleteRuleGroup(t *testing.T, namespaceTitle req, err := http.NewRequest(http.MethodDelete, fmt.Sprintf(path, a.url, namespaceTitle, groupName), nil) require.NoError(t, err) - _, status, raw := sendRequestJSON[apimodels.ConvertPrometheusResponse](t, req, http.StatusAccepted) + + for key, value := range headers { + req.Header.Add(key, value) + } + + return sendRequestJSON[apimodels.ConvertPrometheusResponse](t, req, http.StatusAccepted) +} + +func (a apiClient) ConvertPrometheusDeleteNamespace(t *testing.T, namespaceTitle string, headers map[string]string) { + t.Helper() + + _, status, raw := a.RawConvertPrometheusDeleteNamespace(t, namespaceTitle, headers) requireStatusCode(t, http.StatusAccepted, status, raw) } -func (a apiClient) ConvertPrometheusDeleteNamespace(t *testing.T, namespaceTitle string) { +func (a apiClient) RawConvertPrometheusDeleteNamespace(t *testing.T, namespaceTitle string, headers map[string]string) (apimodels.ConvertPrometheusResponse, int, string) { t.Helper() path := "%s/api/convert/prometheus/config/v1/rules/%s" @@ -1189,8 +1247,12 @@ func (a apiClient) ConvertPrometheusDeleteNamespace(t *testing.T, namespaceTitle req, err := http.NewRequest(http.MethodDelete, fmt.Sprintf(path, a.url, namespaceTitle), nil) require.NoError(t, err) - _, status, raw := sendRequestJSON[apimodels.ConvertPrometheusResponse](t, req, http.StatusAccepted) - requireStatusCode(t, http.StatusAccepted, status, raw) + + for key, value := range headers { + req.Header.Add(key, value) + } + + return sendRequestJSON[apimodels.ConvertPrometheusResponse](t, req, http.StatusAccepted) } func sendRequestRaw(t *testing.T, req *http.Request) ([]byte, int, error) { From 66279081c607f74dbd4b808225a6e7639b4d3dc5 Mon Sep 17 00:00:00 2001 From: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com> Date: Mon, 3 Mar 2025 18:14:43 +0100 Subject: [PATCH 63/74] Elasticsearch: Invalid response JSON parsing error should be downstream (#101506) * Elasticsearch: Invalid response JSON parsing error should be downstream * Add test * Update test --- pkg/tsdb/elasticsearch/client/client.go | 7 ++- pkg/tsdb/elasticsearch/client/client_test.go | 66 ++++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/pkg/tsdb/elasticsearch/client/client.go b/pkg/tsdb/elasticsearch/client/client.go index 62f9ba2ee29..868e566ddf8 100644 --- a/pkg/tsdb/elasticsearch/client/client.go +++ b/pkg/tsdb/elasticsearch/client/client.go @@ -220,6 +220,10 @@ func (c *baseClientImpl) ExecuteMultisearch(r *MultiSearchRequest) (*MultiSearch } else { dec := json.NewDecoder(res.Body) err = dec.Decode(&msr) + if err != nil { + // Invalid JSON response from Elasticsearch + err = backend.DownstreamError(err) + } } if err != nil { c.logger.Error("Failed to decode response from Elasticsearch", "error", err, "duration", time.Since(start), "improvedParsingEnabled", improvedParsingEnabled) @@ -239,7 +243,8 @@ func StreamMultiSearchResponse(body io.Reader, msr *MultiSearchResponse) error { _, err := dec.Token() // reads the `{` opening brace if err != nil { - return err + // Invalid JSON response from Elasticsearch + return backend.DownstreamError(err) } for dec.More() { diff --git a/pkg/tsdb/elasticsearch/client/client_test.go b/pkg/tsdb/elasticsearch/client/client_test.go index 447a9bb09e0..dff8b39139d 100644 --- a/pkg/tsdb/elasticsearch/client/client_test.go +++ b/pkg/tsdb/elasticsearch/client/client_test.go @@ -182,6 +182,32 @@ func TestClient_ExecuteMultisearch(t *testing.T) { require.Contains(t, bodyString, "metrics-2018.05.15") require.Contains(t, bodyString, "metrics-2018.05.17") }) + + t.Run("Should return DownstreamError when decoding response fails", func(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + rw.Header().Set("Content-Type", "application/x-ndjson") + _, err := rw.Write([]byte(`{"invalid`)) + require.NoError(t, err) + rw.WriteHeader(200) + })) + + ds := &DatasourceInfo{ + URL: ts.URL, + Database: "[metrics-]YYYY.MM.DD", + HTTPClient: ts.Client(), + } + + c, err := NewClient(context.Background(), ds, log.NewNullLogger()) + require.NoError(t, err) + + t.Cleanup(func() { + ts.Close() + }) + + _, err = c.ExecuteMultisearch(&MultiSearchRequest{}) + require.Error(t, err) + require.True(t, backend.IsDownstreamError(err)) + }) } func TestClient_Index(t *testing.T) { @@ -410,6 +436,46 @@ func TestStreamMultiSearchResponse_InvalidHitElement(t *testing.T) { } } +func TestStreamMultiSearchResponse_ErrorHandling(t *testing.T) { + t.Run("Given invalid elasticsearch responses", func(t *testing.T) { + t.Run("When response is invalid JSON", func(t *testing.T) { + msr := &MultiSearchResponse{} + err := StreamMultiSearchResponse(strings.NewReader(`abc`), msr) + + require.Error(t, err) + require.True(t, backend.IsDownstreamError(err)) + }) + }) + + t.Run("Given a client with invalid response", func(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + rw.Header().Set("Content-Type", "application/x-ndjson") + _, err := rw.Write([]byte(`{"invalid`)) + require.NoError(t, err) + rw.WriteHeader(200) + })) + + ds := &DatasourceInfo{ + URL: ts.URL, + Database: "[metrics-]YYYY.MM.DD", + HTTPClient: ts.Client(), + } + + c, err := NewClient(context.Background(), ds, log.NewNullLogger()) + require.NoError(t, err) + + t.Cleanup(func() { + ts.Close() + }) + + t.Run("When executing multi search with invalid response", func(t *testing.T) { + _, err = c.ExecuteMultisearch(&MultiSearchRequest{}) + require.Error(t, err) + require.True(t, backend.IsDownstreamError(err)) + }) + }) +} + func createMultisearchForTest(t *testing.T, c Client, timeRange backend.TimeRange) (*MultiSearchRequest, error) { t.Helper() From 22d39f585d0b70ed1bb81affa3b97a321ae10c2b Mon Sep 17 00:00:00 2001 From: Charandas <542168+charandas@users.noreply.github.com> Date: Mon, 3 Mar 2025 09:50:11 -0800 Subject: [PATCH 64/74] fix: don't double set aggregator certs (#101444) --- pkg/services/apiserver/options/kube-aggregator.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/pkg/services/apiserver/options/kube-aggregator.go b/pkg/services/apiserver/options/kube-aggregator.go index 480011091b3..abab98e175d 100644 --- a/pkg/services/apiserver/options/kube-aggregator.go +++ b/pkg/services/apiserver/options/kube-aggregator.go @@ -104,9 +104,6 @@ func (o *KubeAggregatorOptions) ApplyTo(aggregatorConfig *aggregatorapiserver.Co } genericConfig.MergedResourceConfig = mergedResourceConfig - aggregatorConfig.ExtraConfig.ProxyClientCertFile = o.ProxyClientCertFile - aggregatorConfig.ExtraConfig.ProxyClientKeyFile = o.ProxyClientKeyFile - genericConfig.PostStartHooks = map[string]genericapiserver.PostStartHookConfigEntry{} // These hooks use v1 informers, which are not available in the grafana aggregator. From 5f6b00a72f2cebc154ac5f1bbb9b4c655fb0afea Mon Sep 17 00:00:00 2001 From: Ieva Date: Mon, 3 Mar 2025 18:26:55 +0000 Subject: [PATCH 65/74] Revert "Authz: Removes setting `viewers_can_edit`" (#101528) Revert "Authz: Removes setting `viewers_can_edit` (#101265)" This reverts commit 4ce41acade70cb2c0c587f14c5f9add948a2ed61. --- pkg/api/accesscontrol.go | 4 +++ .../guardian/accesscontrol_guardian.go | 8 +++++ .../guardian/accesscontrol_guardian_test.go | 34 ++++++++++++++++--- pkg/services/queryhistory/api.go | 2 +- .../scene/NavToolbarActions.tsx | 8 +---- 5 files changed, 44 insertions(+), 12 deletions(-) diff --git a/pkg/api/accesscontrol.go b/pkg/api/accesscontrol.go index 0ad8d8eeedc..f991eec04b4 100644 --- a/pkg/api/accesscontrol.go +++ b/pkg/api/accesscontrol.go @@ -71,6 +71,10 @@ func (hs *HTTPServer) declareFixedRoles() error { Grants: []string{string(org.RoleEditor)}, } + if hs.Cfg.ViewersCanEdit { + datasourcesExplorerRole.Grants = append(datasourcesExplorerRole.Grants, string(org.RoleViewer)) + } + datasourcesReaderRole := ac.RoleRegistration{ Role: ac.RoleDTO{ Name: "fixed:datasources:reader", diff --git a/pkg/services/guardian/accesscontrol_guardian.go b/pkg/services/guardian/accesscontrol_guardian.go index 88d29ec72b1..4282ac4e29e 100644 --- a/pkg/services/guardian/accesscontrol_guardian.go +++ b/pkg/services/guardian/accesscontrol_guardian.go @@ -221,6 +221,10 @@ func (a *accessControlDashboardGuardian) CanEdit() (bool, error) { return false, ErrGuardianDashboardNotFound.Errorf("failed to check edit permissions for dashboard") } + if a.cfg.ViewersCanEdit { + return a.CanView() + } + return a.evaluate( accesscontrol.EvalPermission(dashboards.ActionDashboardsWrite, dashboards.ScopeDashboardsProvider.GetResourceScopeUID(a.dashboard.UID)), ) @@ -231,6 +235,10 @@ func (a *accessControlFolderGuardian) CanEdit() (bool, error) { return false, ErrGuardianFolderNotFound.Errorf("failed to check edit permissions for folder") } + if a.cfg.ViewersCanEdit { + return a.CanView() + } + return a.evaluate(accesscontrol.EvalPermission(dashboards.ActionFoldersWrite, dashboards.ScopeFoldersProvider.GetResourceScopeUID(a.folder.UID))) } diff --git a/pkg/services/guardian/accesscontrol_guardian_test.go b/pkg/services/guardian/accesscontrol_guardian_test.go index 2171d2bbbac..5de4e91da24 100644 --- a/pkg/services/guardian/accesscontrol_guardian_test.go +++ b/pkg/services/guardian/accesscontrol_guardian_test.go @@ -36,10 +36,11 @@ var ( ) type accessControlGuardianTestCase struct { - desc string - dashboard *dashboards.Dashboard - permissions []accesscontrol.Permission - expected bool + desc string + dashboard *dashboards.Dashboard + permissions []accesscontrol.Permission + viewersCanEdit bool + expected bool } func TestAccessControlDashboardGuardian_CanSave(t *testing.T) { @@ -256,6 +257,18 @@ func TestAccessControlDashboardGuardian_CanEdit(t *testing.T) { }, expected: false, }, + { + desc: "should be able to edit dashboard with read action when viewer_can_edit is true", + dashboard: dashboard, + permissions: []accesscontrol.Permission{ + { + Action: dashboards.ActionDashboardsRead, + Scope: "dashboards:uid:1", + }, + }, + viewersCanEdit: true, + expected: true, + }, { desc: "should not be able to edit folder with folder write and dashboard wildcard scope", dashboard: fldr, @@ -311,11 +324,24 @@ func TestAccessControlDashboardGuardian_CanEdit(t *testing.T) { }, expected: false, }, + { + desc: "should be able to edit folder with folder read action when viewer_can_edit is true", + dashboard: fldr, + permissions: []accesscontrol.Permission{ + { + Action: dashboards.ActionFoldersRead, + Scope: folderUIDScope, + }, + }, + viewersCanEdit: true, + expected: true, + }, } for _, tt := range tests { t.Run(tt.desc, func(t *testing.T) { cfg := setting.NewCfg() + cfg.ViewersCanEdit = tt.viewersCanEdit guardian := setupAccessControlGuardianTest(t, tt.dashboard, tt.permissions, cfg) can, err := guardian.CanEdit() diff --git a/pkg/services/queryhistory/api.go b/pkg/services/queryhistory/api.go index 0b39e4c9f30..ef8ca98ad4d 100644 --- a/pkg/services/queryhistory/api.go +++ b/pkg/services/queryhistory/api.go @@ -30,7 +30,7 @@ type CallbackHandler func(c *contextmodel.ReqContext) response.Response func (s *QueryHistoryService) permissionsMiddleware(handler CallbackHandler, errorMessage string) CallbackHandler { return func(c *contextmodel.ReqContext) response.Response { hasAccess := ac.HasAccess(s.accessControl, c) - if c.GetOrgRole() == org.RoleViewer && !hasAccess(ac.EvalPermission(ac.ActionDatasourcesExplore)) { + if c.GetOrgRole() == org.RoleViewer && !s.Cfg.ViewersCanEdit && !hasAccess(ac.EvalPermission(ac.ActionDatasourcesExplore)) { return response.Error(http.StatusUnauthorized, errorMessage, nil) } return handler(c) diff --git a/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx b/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx index b3c4c75afe8..d5564aa2814 100644 --- a/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx +++ b/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx @@ -20,7 +20,6 @@ import { } from '@grafana/ui'; import { AppChromeUpdate } from 'app/core/components/AppChrome/AppChromeUpdate'; import { NavToolbarSeparator } from 'app/core/components/AppChrome/NavToolbar/NavToolbarSeparator'; -import grafanaConfig from 'app/core/config'; import { LS_PANEL_COPY_KEY } from 'app/core/constants'; import { contextSrv } from 'app/core/core'; import { Trans, t } from 'app/core/internationalization'; @@ -79,11 +78,6 @@ export function ToolbarActions({ dashboard }: Props) { const showScopesSelector = config.featureToggles.scopeFilters && !isEditing; const dashboardNewLayouts = config.featureToggles.dashboardNewLayouts; - // Internal only; - // allows viewer editing without ability to save - // used for grafana play - const canEdit = grafanaConfig.viewersCanEdit; - if (!isEditingPanel) { // This adds the presence indicators in enterprise addDynamicActions(toolbarActions, dynamicDashNavActions.left, 'left-actions'); @@ -360,7 +354,7 @@ export function ToolbarActions({ dashboard }: Props) { toolbarActions.push({ group: 'main-buttons', - condition: !isEditing && (dashboard.canEditDashboard() || canEdit) && !isViewingPanel && !isPlaying && editable, + condition: !isEditing && dashboard.canEditDashboard() && !isViewingPanel && !isPlaying && editable, render: () => (