merge main
This commit is contained in:
commit
bf5427e24c
97 files changed
+7549
-511
No files matched your search
@@ -785,6 +785,7 @@ embed.go @grafana/grafana-as-code
|
||||
/.github/workflows/issue-opened.yml @grafana/grafana-community-support
|
||||
/.github/workflows/metrics-collector.yml @torkelo
|
||||
/.github/workflows/milestone.yml @tolzhabayev
|
||||
/.github/workflows/pr-backend-code-checks.yml @grafana/grafana-backend-group
|
||||
/.github/workflows/pr-checks.yml @tolzhabayev
|
||||
/.github/workflows/pr-codeql-analysis-go.yml @DanCech
|
||||
/.github/workflows/pr-codeql-analysis-javascript.yml @DanCech
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
name: Backend Code Checks
|
||||
description: Validate go.mod and OpenAPI specifications
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '*.md'
|
||||
- 'docs/**'
|
||||
- 'latest.json'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
validate-configs:
|
||||
name: Validate Backend Configs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23.5'
|
||||
cache: true
|
||||
|
||||
- name: Validate go.mod
|
||||
run: go run scripts/modowners/modowners.go check go.mod
|
||||
|
||||
- name: Generate and Validate OpenAPI Specs
|
||||
run: |
|
||||
make swagger-gen
|
||||
@@ -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
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -944,6 +944,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]
|
||||
|
||||
@@ -914,6 +914,7 @@
|
||||
;allow_assign_grafana_admin = false
|
||||
;skip_org_role_sync = false
|
||||
;signout_redirect_url =
|
||||
;tls_skip_verify_insecure = false
|
||||
|
||||
#################################### Auth LDAP ##########################
|
||||
[auth.ldap]
|
||||
|
||||
@@ -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
|
||||
@@ -50,7 +50,7 @@ require (
|
||||
github.com/getkin/kin-openapi v0.129.0 // @grafana/grafana-app-platform-squad
|
||||
github.com/go-git/go-billy/v5 v5.6.2 // @grafana/grafana-app-platform-squad
|
||||
github.com/go-git/go-git/v5 v5.13.2 // @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
|
||||
@@ -182,7 +182,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
|
||||
@@ -225,13 +225,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
|
||||
@@ -247,8 +247,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/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/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0 // indirect
|
||||
github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect
|
||||
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
@@ -313,7 +315,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
|
||||
@@ -341,7 +342,7 @@ 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/go-control-plane/envoy v1.32.3 // 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
|
||||
@@ -373,8 +374,9 @@ require (
|
||||
github.com/google/cel-go v0.22.1 // indirect
|
||||
github.com/google/flatbuffers v24.3.25+incompatible // indirect
|
||||
github.com/google/gnostic-models v0.6.8 // indirect
|
||||
github.com/google/go-github/v64 v64.0.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/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
|
||||
@@ -529,9 +531,9 @@ require (
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.16 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.16 // indirect
|
||||
go.mongodb.org/mongo-driver v1.16.1 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opencensus.io v0.24.0 // @grafana/grafana-backend-group
|
||||
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
|
||||
@@ -544,9 +546,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
|
||||
@@ -569,8 +571,6 @@ require (
|
||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||
)
|
||||
|
||||
require github.com/google/go-github/v64 v64.0.0 // 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
|
||||
|
||||
|
||||
@@ -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=
|
||||
@@ -965,7 +975,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=
|
||||
@@ -1118,8 +1127,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=
|
||||
@@ -1188,8 +1201,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=
|
||||
@@ -1484,8 +1497,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=
|
||||
@@ -2493,8 +2506,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=
|
||||
@@ -2520,6 +2533,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=
|
||||
@@ -3148,8 +3163,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=
|
||||
@@ -3301,21 +3316,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=
|
||||
|
||||
+322
@@ -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=
|
||||
@@ -399,6 +652,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=
|
||||
@@ -503,6 +757,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=
|
||||
@@ -594,10 +849,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=
|
||||
@@ -628,6 +890,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=
|
||||
@@ -895,6 +1158,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=
|
||||
@@ -1051,12 +1315,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=
|
||||
@@ -1064,6 +1334,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=
|
||||
@@ -1085,12 +1357,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=
|
||||
@@ -1123,6 +1403,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=
|
||||
@@ -1131,6 +1412,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=
|
||||
@@ -1142,8 +1425,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=
|
||||
@@ -1152,7 +1437,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=
|
||||
@@ -1163,26 +1450,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=
|
||||
@@ -1191,6 +1512,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=
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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=
|
||||
@@ -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=
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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=
|
||||
|
||||
+22
-12
@@ -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
|
||||
|
||||
+56
-34
@@ -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=
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -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
|
||||
|
||||
+18
-12
@@ -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=
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
@@ -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())
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
@@ -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)))
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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})
|
||||
})
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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{})
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
@@ -12,6 +12,7 @@ const (
|
||||
SQLite = "sqlite3"
|
||||
MySQL = "mysql"
|
||||
MSSQL = "mssql"
|
||||
Spanner = "spanner"
|
||||
)
|
||||
|
||||
type Migration interface {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
@@ -118,6 +124,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
|
||||
@@ -136,6 +143,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
|
||||
@@ -145,7 +153,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
|
||||
@@ -185,7 +193,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
|
||||
@@ -299,6 +307,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
|
||||
@@ -348,6 +357,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
|
||||
@@ -359,6 +369,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
|
||||
@@ -377,10 +388,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
|
||||
|
||||
+1130
-25
File diff suppressed because it is too large.
Load diff
@@ -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,19 +83,23 @@ 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
|
||||
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
|
||||
@@ -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
|
||||
|
||||
+1377
-26
File diff suppressed because it is too large.
Load diff
@@ -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 (
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -7,12 +7,14 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.opencensus.io/stats/view"
|
||||
"go.uber.org/goleak"
|
||||
|
||||
"github.com/grafana/grafana/pkg/util/testutil/mocks"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
view.Stop()
|
||||
// make sure we don't leak goroutines after tests in this package have
|
||||
// finished, which means we haven't leaked contexts either
|
||||
goleak.VerifyTestMain(m)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
+51
-5
@@ -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
|
||||
)
|
||||
File diff suppressed because it is too large.
Load diff
@@ -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 {
|
||||
|
||||
+1
@@ -102,6 +102,7 @@ export class GrafanaJavascriptAgentBackend
|
||||
? instrumentations
|
||||
: [...getWebInstrumentations(), new TracingInstrumentation()],
|
||||
consoleInstrumentation: consoleInstrumentationOptions,
|
||||
trackWebVitalsAttribution: options.webVitalsInstrumentalizationEnabled || options.allInstrumentationsEnabled,
|
||||
transports,
|
||||
ignoreErrors: [
|
||||
'ResizeObserver loop limit exceeded',
|
||||
|
||||
@@ -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 <FRONTENT_PAGE_SIZE> 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
|
||||
|
||||
@@ -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)),
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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 <DashboardTitleInput dashboard={dashboard} />;
|
||||
},
|
||||
render: () => <DashboardTitleInput dashboard={dashboard} />,
|
||||
})
|
||||
)
|
||||
.addItem(
|
||||
new OptionsPaneItemDescriptor({
|
||||
title: t('dashboard.options.description', 'Description'),
|
||||
render: function renderTitle() {
|
||||
return <DashboardDescriptionInput dashboard={dashboard} />;
|
||||
},
|
||||
render: () => <DashboardDescriptionInput dashboard={dashboard} />,
|
||||
})
|
||||
)
|
||||
.addItem(
|
||||
new OptionsPaneItemDescriptor({
|
||||
title: t('dashboard.layout.common.layout', 'Layout'),
|
||||
render: () => <DashboardLayoutSelector layoutManager={body} />,
|
||||
})
|
||||
);
|
||||
}, [dashboard]);
|
||||
}, [body, dashboard]);
|
||||
|
||||
const layoutCategory = useLayoutCategory(body);
|
||||
|
||||
return [dashboardOptions, layoutCategory];
|
||||
return [dashboardOptions];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 (
|
||||
<Stack justifyContent="space-between" alignItems="center" width="100%">
|
||||
<span>{title}</span>
|
||||
<Stack alignItems="center">
|
||||
{addCopyOrDuplicate ? (
|
||||
<Dropdown overlay={<MenuItems onCopy={onCopy} onDuplicate={onDuplicate} />}>
|
||||
<Button
|
||||
tooltip={t('dashboard.layout.common.copy-or-duplicate', 'Copy or Duplicate')}
|
||||
tooltipPlacement="bottom"
|
||||
variant="secondary"
|
||||
fill="text"
|
||||
size="md"
|
||||
>
|
||||
<Icon name="copy" /> <Icon name="angle-down" />
|
||||
</Button>
|
||||
</Dropdown>
|
||||
) : null}
|
||||
|
||||
<IconButton
|
||||
size="md"
|
||||
variant="secondary"
|
||||
onClick={onDelete}
|
||||
name="trash-alt"
|
||||
tooltip={t('dashboard.layout.common.delete', 'Delete')}
|
||||
/>
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
type MenuItemsProps = {
|
||||
onCopy?: () => void;
|
||||
onDuplicate?: () => void;
|
||||
};
|
||||
|
||||
const MenuItems = ({ onCopy, onDuplicate }: MenuItemsProps) => {
|
||||
return (
|
||||
<Menu>
|
||||
{onCopy ? <Menu.Item label={t('dashboard.layout.common.copy', 'Copy')} onClick={onCopy} /> : null}
|
||||
{onDuplicate ? (
|
||||
<Menu.Item label={t('dashboard.layout.common.duplicate', 'Duplicate')} onClick={onDuplicate} />
|
||||
) : null}
|
||||
</Menu>
|
||||
);
|
||||
};
|
||||
@@ -24,6 +24,8 @@ export function ElementEditPane({ element }: Props) {
|
||||
title={elementInfo.name}
|
||||
isOpenDefault={true}
|
||||
className={styles.noBorderTop}
|
||||
renderTitle={element.renderTitle}
|
||||
isOpenable={element.isOpenable}
|
||||
>
|
||||
<div className={styles.actionsBox}>{element.renderActions()}</div>
|
||||
</OptionsPaneCategory>
|
||||
|
||||
+20
-20
@@ -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 (
|
||||
<Stack direction="column">
|
||||
<Text>
|
||||
<Trans
|
||||
i18nKey="dashboard.edit-pane.panels.multi-select.selection-number"
|
||||
values={{ length: this._panels.length }}
|
||||
>
|
||||
No. of panels selected: {{ length }}
|
||||
</Trans>
|
||||
</Text>
|
||||
<Stack direction="row">
|
||||
<Button size="sm" variant="secondary" icon="copy" />
|
||||
<Button size="sm" variant="destructive" fill="outline" onClick={() => this.onDelete()} icon="trash-alt" />
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
public useEditPaneOptions(): OptionsPaneCategoryDescriptor[] {
|
||||
const header = new OptionsPaneCategoryDescriptor({
|
||||
title: ``,
|
||||
id: 'panel-header',
|
||||
isOpenable: false,
|
||||
renderTitle: () => (
|
||||
<EditPaneHeader
|
||||
title={t('dashboard.layout.common.panels-title', '{{length}} Panels Selected', {
|
||||
length: this._panels.length,
|
||||
})}
|
||||
onDelete={() => this.onDelete()}
|
||||
/>
|
||||
),
|
||||
});
|
||||
|
||||
return [header];
|
||||
}
|
||||
|
||||
public onDelete() {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { ReactNode, useMemo } from 'react';
|
||||
import { css, cx } from '@emotion/css';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { GrafanaTheme2, textUtil } from '@grafana/data';
|
||||
import { sceneGraph, VizPanel } from '@grafana/scenes';
|
||||
import { Button } from '@grafana/ui';
|
||||
import { t, Trans } from 'app/core/internationalization';
|
||||
import { useStyles2, Text, Icon, Stack, Tooltip } from '@grafana/ui';
|
||||
import { t } from 'app/core/internationalization';
|
||||
import { OptionsPaneCategoryDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor';
|
||||
import { OptionsPaneItemDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor';
|
||||
import { getVisualizationOptions2 } from 'app/features/dashboard/components/PanelEditor/getVisualizationOptions';
|
||||
|
||||
import {
|
||||
PanelBackgroundSwitch,
|
||||
@@ -16,11 +17,16 @@ import { BulkActionElement } from '../scene/types/BulkActionElement';
|
||||
import { isDashboardLayoutItem } from '../scene/types/DashboardLayoutItem';
|
||||
import { EditableDashboardElement, EditableDashboardElementInfo } from '../scene/types/EditableDashboardElement';
|
||||
import { dashboardSceneGraph } from '../utils/dashboardSceneGraph';
|
||||
import { getEditPanelUrl } from '../utils/urlBuilders';
|
||||
import { getPanelIdForVizPanel } from '../utils/utils';
|
||||
|
||||
import { EditPaneHeader } from './EditPaneHeader';
|
||||
|
||||
export class VizPanelEditableElement implements EditableDashboardElement, BulkActionElement {
|
||||
public readonly isEditableDashboardElement = true;
|
||||
public readonly typeName = 'Panel';
|
||||
|
||||
public constructor(private panel: VizPanel) {}
|
||||
public constructor(public panel: VizPanel) {}
|
||||
|
||||
public getEditableElementInfo(): EditableDashboardElementInfo {
|
||||
return {
|
||||
@@ -36,35 +42,38 @@ export class VizPanelEditableElement implements EditableDashboardElement, BulkAc
|
||||
|
||||
const panelOptions = useMemo(() => {
|
||||
return new OptionsPaneCategoryDescriptor({
|
||||
title: t('dashboard.viz-panel.options.title', 'Panel options'),
|
||||
id: 'panel-options',
|
||||
isOpenDefault: true,
|
||||
title: ``,
|
||||
id: 'panel-header',
|
||||
isOpenable: false,
|
||||
renderTitle: () => (
|
||||
<EditPaneHeader title={t('dashboard.viz-panel.options.title', 'Panel')} onDelete={() => this.onDelete()} />
|
||||
),
|
||||
})
|
||||
.addItem(
|
||||
new OptionsPaneItemDescriptor({
|
||||
title: '',
|
||||
render: () => <OpenPanelEditViz panel={this.panel} />,
|
||||
})
|
||||
)
|
||||
.addItem(
|
||||
new OptionsPaneItemDescriptor({
|
||||
title: t('dashboard.viz-panel.options.title-option', 'Title'),
|
||||
value: panel.state.title,
|
||||
popularRank: 1,
|
||||
render: function renderTitle() {
|
||||
return <PanelFrameTitleInput panel={panel} />;
|
||||
},
|
||||
render: () => <PanelFrameTitleInput panel={panel} />,
|
||||
})
|
||||
)
|
||||
.addItem(
|
||||
new OptionsPaneItemDescriptor({
|
||||
title: t('dashboard.viz-panel.options.description', 'Description'),
|
||||
value: panel.state.description,
|
||||
render: function renderDescription() {
|
||||
return <PanelDescriptionTextArea panel={panel} />;
|
||||
},
|
||||
render: () => <PanelDescriptionTextArea panel={panel} />,
|
||||
})
|
||||
)
|
||||
.addItem(
|
||||
new OptionsPaneItemDescriptor({
|
||||
title: t('dashboard.viz-panel.options.transparent-background', 'Transparent background'),
|
||||
render: function renderTransparent() {
|
||||
return <PanelBackgroundSwitch panel={panel} />;
|
||||
},
|
||||
render: () => <PanelBackgroundSwitch panel={panel} />,
|
||||
})
|
||||
);
|
||||
}, [panel]);
|
||||
@@ -76,50 +85,73 @@ export class VizPanelEditableElement implements EditableDashboardElement, BulkAc
|
||||
return undefined;
|
||||
}, [layoutElement]);
|
||||
|
||||
const { options, fieldConfig, _pluginInstanceState } = panel.useState();
|
||||
const dataProvider = sceneGraph.getData(panel);
|
||||
const { data } = dataProvider.useState();
|
||||
|
||||
const visualizationOptions = useMemo(() => {
|
||||
const plugin = panel.getPlugin();
|
||||
if (!plugin) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return getVisualizationOptions2({
|
||||
panel,
|
||||
data,
|
||||
plugin: plugin,
|
||||
eventBus: panel.getPanelContext().eventBus,
|
||||
instanceState: _pluginInstanceState,
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [data, panel, options, fieldConfig, _pluginInstanceState]);
|
||||
|
||||
const categories = [panelOptions];
|
||||
if (layoutCategory) {
|
||||
categories.push(layoutCategory);
|
||||
}
|
||||
|
||||
categories.push(...visualizationOptions);
|
||||
|
||||
return categories;
|
||||
}
|
||||
|
||||
public onDelete = () => {
|
||||
public onDelete() {
|
||||
const layout = dashboardSceneGraph.getLayoutManagerFor(this.panel);
|
||||
layout.removePanel?.(this.panel);
|
||||
};
|
||||
|
||||
public renderActions(): ReactNode {
|
||||
return (
|
||||
<>
|
||||
<Button size="sm" variant="secondary">
|
||||
<Trans i18nKey="panel.header-menu.edit">Edit</Trans>
|
||||
</Button>
|
||||
<Button size="sm" variant="secondary" icon="copy" />
|
||||
<Button size="sm" variant="destructive" fill="outline" onClick={this.onDelete} icon="trash-alt" />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
type OpenPanelEditVizProps = {
|
||||
panel: VizPanel;
|
||||
};
|
||||
|
||||
const OpenPanelEditViz = ({ panel }: OpenPanelEditVizProps) => {
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
const plugin = panel.getPlugin();
|
||||
const imgSrc = plugin?.meta.info.logos.small;
|
||||
|
||||
return (
|
||||
<Stack alignItems="center" width="100%">
|
||||
{plugin ? (
|
||||
<Tooltip content={t('dashboard.viz-panel.options.open-edit', 'Open Panel Edit')}>
|
||||
<a
|
||||
href={textUtil.sanitizeUrl(getEditPanelUrl(getPanelIdForVizPanel(panel)))}
|
||||
className={cx(styles.pluginDescriptionWrapper)}
|
||||
>
|
||||
<img
|
||||
className={styles.panelVizImg}
|
||||
src={imgSrc}
|
||||
alt={t('dashboard.viz-panel.options.plugin-type-image', 'Image of plugin type')}
|
||||
/>
|
||||
<Text truncate>{plugin.meta.name}</Text>
|
||||
<Icon className={styles.panelVizIcon} name="sliders-v-alt" />
|
||||
</a>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => ({
|
||||
pluginDescriptionWrapper: css({
|
||||
display: 'flex',
|
||||
flexWrap: 'nowrap',
|
||||
alignItems: 'center',
|
||||
columnGap: theme.spacing(1),
|
||||
rowGap: theme.spacing(0.5),
|
||||
minHeight: theme.spacing(4),
|
||||
backgroundColor: theme.components.input.background,
|
||||
border: `1px solid ${theme.colors.border.strong}`,
|
||||
borderRadius: theme.shape.radius.default,
|
||||
paddingInline: theme.spacing(1),
|
||||
paddingBlock: theme.spacing(0.5),
|
||||
flexGrow: 1,
|
||||
}),
|
||||
panelVizImg: css({
|
||||
width: '16px',
|
||||
height: '16px',
|
||||
marginRight: theme.spacing(1),
|
||||
}),
|
||||
panelVizIcon: css({
|
||||
marginLeft: 'auto',
|
||||
}),
|
||||
});
|
||||
@@ -56,6 +56,7 @@ export function SaveDashboardAsForm({ dashboard, changeInfo }: Props) {
|
||||
const result = await onSaveDashboard(dashboard, {
|
||||
overwrite,
|
||||
folderUid: data.folder.uid,
|
||||
rawDashboardJSON: changedSaveModel,
|
||||
|
||||
// save as config
|
||||
saveAsCopy: true,
|
||||
|
||||
@@ -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<SaveDashboardOptions>({
|
||||
@@ -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?.();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
) => {
|
||||
{
|
||||
|
||||
@@ -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';
|
||||
@@ -83,11 +82,6 @@ export function ToolbarActions({ dashboard }: Props) {
|
||||
const folderRepo = useSelector((state) => selectFolderRepository(state, meta.folderUid));
|
||||
const isProvisionedNG = Boolean(dashboard.isProvisioned() || folderRepo);
|
||||
|
||||
// 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');
|
||||
@@ -376,7 +370,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: () => (
|
||||
<Button
|
||||
onClick={() => {
|
||||
|
||||
+3
-4
@@ -1,6 +1,7 @@
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { Select } from '@grafana/ui';
|
||||
import { t } from 'app/core/internationalization';
|
||||
import { OptionsPaneCategoryDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor';
|
||||
import { OptionsPaneItemDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor';
|
||||
|
||||
@@ -55,10 +56,8 @@ export function useLayoutCategory(layoutManager: DashboardLayoutManager) {
|
||||
|
||||
layoutCategory.addItem(
|
||||
new OptionsPaneItemDescriptor({
|
||||
title: 'Type',
|
||||
render: function renderTitle() {
|
||||
return <DashboardLayoutSelector layoutManager={layoutManager} />;
|
||||
},
|
||||
title: t('dashboard.layout.common.layout', 'Layout'),
|
||||
render: () => <DashboardLayoutSelector layoutManager={layoutManager} />,
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
@@ -32,6 +32,16 @@ export interface EditableDashboardElement {
|
||||
* creates a new multi-selection element from a list of selected items
|
||||
*/
|
||||
createMultiSelectedElement?(items: SceneObject[]): MultiSelectedEditableDashboardElement;
|
||||
|
||||
/**
|
||||
* Return custom title for the edit panel header
|
||||
*/
|
||||
renderTitle?(): ReactNode;
|
||||
|
||||
/**
|
||||
* determines if first edit panel header can be collapsed
|
||||
*/
|
||||
isOpenable?: Readonly<boolean>;
|
||||
}
|
||||
|
||||
export interface EditableDashboardElementInfo {
|
||||
|
||||
+10
@@ -27,6 +27,16 @@ export interface MultiSelectedEditableDashboardElement {
|
||||
* Panel Actions
|
||||
**/
|
||||
renderActions?(): ReactNode;
|
||||
|
||||
/**
|
||||
* Return custom title for the edit panel header
|
||||
*/
|
||||
renderTitle?(): ReactNode;
|
||||
|
||||
/**
|
||||
* determines if first edit panel header can be collapsed
|
||||
*/
|
||||
isOpenable?: Readonly<boolean>;
|
||||
}
|
||||
|
||||
export function isMultiSelectedEditableDashboardElement(obj: object): obj is MultiSelectedEditableDashboardElement {
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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)));
|
||||
|
||||
@@ -21,6 +21,7 @@ export interface OptionsPaneCategoryProps {
|
||||
isNested?: boolean;
|
||||
children: ReactNode;
|
||||
sandboxId?: string;
|
||||
isOpenable?: boolean;
|
||||
}
|
||||
|
||||
const CATEGORY_PARAM_NAME = 'showCategory' as const;
|
||||
@@ -37,12 +38,13 @@ export const OptionsPaneCategory = React.memo(
|
||||
itemsCount,
|
||||
isNested = false,
|
||||
sandboxId,
|
||||
isOpenable = true,
|
||||
}: OptionsPaneCategoryProps) => {
|
||||
const [savedState, setSavedState] = useLocalStorage(getOptionGroupStorageKey(id), {
|
||||
isExpanded: isOpenDefault,
|
||||
});
|
||||
|
||||
const [isExpanded, setIsExpanded] = useState(savedState?.isExpanded ?? isOpenDefault);
|
||||
const [isExpanded, setIsExpanded] = useState(!isOpenable || (savedState?.isExpanded ?? isOpenDefault));
|
||||
const manualClickTime = useRef(0);
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const [queryParams, updateQueryParams] = useQueryParams();
|
||||
@@ -66,6 +68,9 @@ export const OptionsPaneCategory = React.memo(
|
||||
}, [forceOpen, isExpanded, isOpenFromUrl]);
|
||||
|
||||
const onToggle = useCallback(() => {
|
||||
if (!isOpenable) {
|
||||
return;
|
||||
}
|
||||
manualClickTime.current = Date.now();
|
||||
updateQueryParams(
|
||||
{
|
||||
@@ -75,7 +80,7 @@ export const OptionsPaneCategory = React.memo(
|
||||
);
|
||||
setSavedState({ isExpanded: !isExpanded });
|
||||
setIsExpanded(!isExpanded);
|
||||
}, [setSavedState, setIsExpanded, updateQueryParams, isExpanded, id]);
|
||||
}, [isOpenable, updateQueryParams, isExpanded, id, setSavedState]);
|
||||
|
||||
if (!renderTitle) {
|
||||
renderTitle = function defaultTitle(isExpanded: boolean) {
|
||||
@@ -101,6 +106,7 @@ export const OptionsPaneCategory = React.memo(
|
||||
);
|
||||
|
||||
const headerStyles = cx(styles.header, {
|
||||
[styles.headerHover]: isOpenable,
|
||||
[styles.headerExpanded]: isExpanded,
|
||||
[styles.headerNested]: isNested,
|
||||
});
|
||||
@@ -123,17 +129,19 @@ export const OptionsPaneCategory = React.memo(
|
||||
<h6 id={`button-${id}`} className={styles.title}>
|
||||
{renderTitle(isExpanded)}
|
||||
</h6>
|
||||
<Button
|
||||
data-testid={selectors.components.OptionsGroup.toggle(id)}
|
||||
type="button"
|
||||
fill="text"
|
||||
size="md"
|
||||
variant="secondary"
|
||||
aria-expanded={isExpanded}
|
||||
className={styles.toggleButton}
|
||||
icon={isExpanded ? 'angle-up' : 'angle-down'}
|
||||
onClick={onToggle}
|
||||
/>
|
||||
{isOpenable ? (
|
||||
<Button
|
||||
data-testid={selectors.components.OptionsGroup.toggle(id)}
|
||||
type="button"
|
||||
fill="text"
|
||||
size="md"
|
||||
variant="secondary"
|
||||
aria-expanded={isExpanded}
|
||||
className={styles.toggleButton}
|
||||
icon={isExpanded ? 'angle-up' : 'angle-down'}
|
||||
onClick={onToggle}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
{isExpanded && (
|
||||
<div className={bodyStyles} id={id} aria-labelledby={`button-${id}`}>
|
||||
@@ -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),
|
||||
},
|
||||
|
||||
@@ -16,6 +16,7 @@ export interface OptionsPaneCategoryDescriptorProps {
|
||||
itemsCount?: number;
|
||||
customRender?: () => React.ReactNode;
|
||||
sandboxId?: string;
|
||||
isOpenable?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { Container, Text } from '@grafana/ui';
|
||||
import { Step } from './types';
|
||||
|
||||
import { CodeBlock } from '../components/CodeBlock';
|
||||
|
||||
import { Step } from './types';
|
||||
|
||||
export interface Props {
|
||||
step: Step;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { IconButton, Text, Stack, Card } from '@grafana/ui';
|
||||
import { css } from '@emotion/css';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { IconButton, Text, Stack, Card } from '@grafana/ui';
|
||||
|
||||
export interface Props {
|
||||
step: string;
|
||||
@@ -16,8 +17,12 @@ export const SidebarItem = ({ step, index, currentStep, onStepClick, styles }: P
|
||||
const isPending = index > currentStep;
|
||||
|
||||
const getStepStatus = () => {
|
||||
if (isCompleted) return { icon: 'check-circle' as const, color: 'success', label: 'Completed step' };
|
||||
if (isCurrent) return { icon: 'circle' as const, color: 'primary', label: 'Current step' };
|
||||
if (isCompleted) {
|
||||
return { icon: 'check-circle' as const, color: 'success', label: 'Completed step' };
|
||||
}
|
||||
if (isCurrent) {
|
||||
return { icon: 'circle' as const, color: 'primary', label: 'Current step' };
|
||||
}
|
||||
return { icon: 'circle' as const, color: 'secondary', label: 'Pending step' };
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { config } from '@grafana/runtime';
|
||||
|
||||
import { requiredFeatureToggles } from './types';
|
||||
|
||||
/**
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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đ"
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user