CloudWatch: Remove dependencies on grafana/pkg/setting (#81208)

This commit is contained in:
Isabella Siu
2024-02-05 13:59:32 -05:00
committed by GitHub
parent 2ab7d3c725
commit 81da3ff753
28 changed files with 440 additions and 214 deletions

View File

@@ -874,6 +874,14 @@ list_metrics_page_limit = 500
# Experimental, for use in Grafana Cloud only. Please do not set. # Experimental, for use in Grafana Cloud only. Please do not set.
external_id = external_id =
# Sets the expiry duration of an assumed role.
# This setting should be expressed as a duration. Examples: 6h (hours), 10d (days), 2w (weeks), 1M (month).
session_duration = "15m"
# Set the plugins that will receive AWS settings for each request (via plugin context)
# By default this will include all Grafana Labs owned AWS plugins, or those that make use of AWS settings (ElasticSearch, Prometheus).
forward_settings_to_plugins = cloudwatch, grafana-athena-datasource, grafana-redshift-datasource, grafana-x-ray-datasource, grafana-timestream-datasource, grafana-iot-sitewise-datasource, grafana-iot-twinmaker-app, grafana-opensearch-datasource, aws-datasource-provisioner, elasticsearch, prometheus
#################################### Azure ############################### #################################### Azure ###############################
[azure] [azure]
# Azure cloud environment where Grafana is hosted # Azure cloud environment where Grafana is hosted

View File

@@ -808,6 +808,14 @@
# Experimental, for use in Grafana Cloud only. Please do not set. # Experimental, for use in Grafana Cloud only. Please do not set.
; external_id = ; external_id =
# Sets the expiry duration of an assumed role.
# This setting should be expressed as a duration. Examples: 6h (hours), 10d (days), 2w (weeks), 1M (month).
; session_duration = "15m"
# Set the plugins that will receive AWS settings for each request (via plugin context)
# By default this will include all Grafana Labs owned AWS plugins, or those that make use of AWS settings (ElasticSearch, Prometheus).
; forward_settings_to_plugins = cloudwatch, grafana-athena-datasource, grafana-redshift-datasource, grafana-x-ray-datasource, grafana-timestream-datasource, grafana-iot-sitewise-datasource, grafana-iot-twinmaker-app, grafana-opensearch-datasource, aws-datasource-provisioner, elasticsearch, prometheus
#################################### Azure ############################### #################################### Azure ###############################
[azure] [azure]
# Azure cloud environment where Grafana is hosted # Azure cloud environment where Grafana is hosted

15
go.mod
View File

@@ -61,7 +61,7 @@ require (
github.com/gorilla/websocket v1.5.0 // @grafana/grafana-app-platform-squad github.com/gorilla/websocket v1.5.0 // @grafana/grafana-app-platform-squad
github.com/grafana/alerting v0.0.0-20240123184432-1d58deb6074c // @grafana/alerting-squad-backend github.com/grafana/alerting v0.0.0-20240123184432-1d58deb6074c // @grafana/alerting-squad-backend
github.com/grafana/cuetsy v0.1.11 // @grafana/grafana-as-code github.com/grafana/cuetsy v0.1.11 // @grafana/grafana-as-code
github.com/grafana/grafana-aws-sdk v0.19.1 // @grafana/aws-datasources github.com/grafana/grafana-aws-sdk v0.23.1 // @grafana/aws-datasources
github.com/grafana/grafana-azure-sdk-go v1.12.0 // @grafana/partner-datasources github.com/grafana/grafana-azure-sdk-go v1.12.0 // @grafana/partner-datasources
github.com/grafana/grafana-plugin-sdk-go v0.206.0 // @grafana/plugins-platform-backend github.com/grafana/grafana-plugin-sdk-go v0.206.0 // @grafana/plugins-platform-backend
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // @grafana/backend-platform github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // @grafana/backend-platform
@@ -258,7 +258,7 @@ require (
github.com/dave/dst v0.27.2 // @grafana/grafana-as-code github.com/dave/dst v0.27.2 // @grafana/grafana-as-code
github.com/go-jose/go-jose/v3 v3.0.1 // @grafana/grafana-authnz-team github.com/go-jose/go-jose/v3 v3.0.1 // @grafana/grafana-authnz-team
github.com/grafana/dataplane/examples v0.0.1 // @grafana/observability-metrics github.com/grafana/dataplane/examples v0.0.1 // @grafana/observability-metrics
github.com/grafana/dataplane/sdata v0.0.6 // @grafana/observability-metrics github.com/grafana/dataplane/sdata v0.0.7 // @grafana/observability-metrics
github.com/grafana/kindsys v0.0.0-20230508162304-452481b63482 // @grafana/grafana-as-code github.com/grafana/kindsys v0.0.0-20230508162304-452481b63482 // @grafana/grafana-as-code
github.com/grafana/tempo v1.5.1-0.20230524121406-1dc1bfe7085b // @grafana/observability-traces-and-profiling github.com/grafana/tempo v1.5.1-0.20230524121406-1dc1bfe7085b // @grafana/observability-traces-and-profiling
github.com/grafana/thema v0.0.0-20230712153715-375c1b45f3ed // @grafana/grafana-as-code github.com/grafana/thema v0.0.0-20230712153715-375c1b45f3ed // @grafana/grafana-as-code
@@ -344,7 +344,6 @@ require (
github.com/google/s2a-go v0.1.7 // indirect github.com/google/s2a-go v0.1.7 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db // indirect github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db // indirect
github.com/grafana/sqlds/v2 v2.3.10 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.2 // indirect
@@ -483,6 +482,16 @@ require (
require k8s.io/code-generator v0.29.1 // @grafana/grafana-app-platform-squad require k8s.io/code-generator v0.29.1 // @grafana/grafana-app-platform-squad
require (
github.com/grafana/sqlds/v3 v3.2.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mithrandie/csvq v1.17.10 // indirect
github.com/mithrandie/csvq-driver v1.6.8 // indirect
github.com/mithrandie/go-file/v2 v2.1.0 // indirect
github.com/mithrandie/go-text v1.5.4 // indirect
github.com/mithrandie/ternary v1.1.1 // indirect
)
// Use fork of crewjam/saml with fixes for some issues until changes get merged into upstream // 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.20231025143828-a6c0e9b86a4c replace github.com/crewjam/saml => github.com/grafana/saml v0.4.15-0.20231025143828-a6c0e9b86a4c

24
go.sum
View File

@@ -1826,14 +1826,14 @@ github.com/grafana/cuetsy v0.1.11 h1:I3IwBhF+UaQxRM79HnImtrAn8REGdb5M3+C4QrYHoWk
github.com/grafana/cuetsy v0.1.11/go.mod h1:Ix97+CPD8ws9oSSxR3/Lf4ahU1I4Np83kjJmDVnLZvc= github.com/grafana/cuetsy v0.1.11/go.mod h1:Ix97+CPD8ws9oSSxR3/Lf4ahU1I4Np83kjJmDVnLZvc=
github.com/grafana/dataplane/examples v0.0.1 h1:K9M5glueWyLoL4//H+EtTQq16lXuHLmOhb6DjSCahzA= github.com/grafana/dataplane/examples v0.0.1 h1:K9M5glueWyLoL4//H+EtTQq16lXuHLmOhb6DjSCahzA=
github.com/grafana/dataplane/examples v0.0.1/go.mod h1:h5YwY8s407/17XF5/dS8XrUtsTVV2RnuW8+m1Mp46mg= github.com/grafana/dataplane/examples v0.0.1/go.mod h1:h5YwY8s407/17XF5/dS8XrUtsTVV2RnuW8+m1Mp46mg=
github.com/grafana/dataplane/sdata v0.0.6 h1:Ejlj8d1Hvy/uDLeI4sOvL34Y8WLlVDd9iN270F+8aTw= github.com/grafana/dataplane/sdata v0.0.7 h1:CImITypIyS1jxijCR6xqKx71JnYAxcwpH9ChK0gH164=
github.com/grafana/dataplane/sdata v0.0.6/go.mod h1:Jvs5ddpGmn6vcxT7tCTWAZ1mgi4sbcdFt9utQx5uMAU= github.com/grafana/dataplane/sdata v0.0.7/go.mod h1:Jvs5ddpGmn6vcxT7tCTWAZ1mgi4sbcdFt9utQx5uMAU=
github.com/grafana/dskit v0.0.0-20240104111617-ea101a3b86eb h1:AWE6+kvtE18HP+lRWNUCyvymyrFSXs6TcS2vXIXGIuw= github.com/grafana/dskit v0.0.0-20240104111617-ea101a3b86eb h1:AWE6+kvtE18HP+lRWNUCyvymyrFSXs6TcS2vXIXGIuw=
github.com/grafana/dskit v0.0.0-20240104111617-ea101a3b86eb/go.mod h1:kkWM4WUV230bNG3urVRWPBnSJHs64y/0RmWjftnnn0c= github.com/grafana/dskit v0.0.0-20240104111617-ea101a3b86eb/go.mod h1:kkWM4WUV230bNG3urVRWPBnSJHs64y/0RmWjftnnn0c=
github.com/grafana/gofpdf v0.0.0-20231002120153-857cc45be447 h1:jxJJ5z0GxqhWFbQUsys3BHG8jnmniJ2Q74tXAG1NaDo= github.com/grafana/gofpdf v0.0.0-20231002120153-857cc45be447 h1:jxJJ5z0GxqhWFbQUsys3BHG8jnmniJ2Q74tXAG1NaDo=
github.com/grafana/gofpdf v0.0.0-20231002120153-857cc45be447/go.mod h1:IxsY6mns6Q5sAnWcrptrgUrSglTZJXH/kXr9nbpb/9I= github.com/grafana/gofpdf v0.0.0-20231002120153-857cc45be447/go.mod h1:IxsY6mns6Q5sAnWcrptrgUrSglTZJXH/kXr9nbpb/9I=
github.com/grafana/grafana-aws-sdk v0.19.1 h1:5GBiOv2AgdyjwlgAX+dtgPtXU4FgMTD9rfQUPQseEpQ= github.com/grafana/grafana-aws-sdk v0.23.1 h1:YP6DqzB36fp8fXno0r+X9BxNB3apNfJnQxu8tdhYMH8=
github.com/grafana/grafana-aws-sdk v0.19.1/go.mod h1:ntq2NDH12Y2Fkbc6fozpF8kYsJM9k6KNr+Xfo5w3/iM= github.com/grafana/grafana-aws-sdk v0.23.1/go.mod h1:iTbW395xv26qy6L17SjtZlVwxQTIZbmupBTe0sPHv7k=
github.com/grafana/grafana-azure-sdk-go v1.11.0 h1:nc6MgOZ5fIaxvBfZjYU5rSqB4zaD7rlU8BqnGcXZtWk= github.com/grafana/grafana-azure-sdk-go v1.11.0 h1:nc6MgOZ5fIaxvBfZjYU5rSqB4zaD7rlU8BqnGcXZtWk=
github.com/grafana/grafana-azure-sdk-go v1.11.0/go.mod h1:5a3FuG2lEsYNop9HDNgTO1bx4ExCgsjvrFhpuqolYAU= github.com/grafana/grafana-azure-sdk-go v1.11.0/go.mod h1:5a3FuG2lEsYNop9HDNgTO1bx4ExCgsjvrFhpuqolYAU=
github.com/grafana/grafana-azure-sdk-go v1.12.0 h1:q71M2QxMlBqRZOXc5mFAycJWuZqQ3hPTzVEo1r3CUTY= github.com/grafana/grafana-azure-sdk-go v1.12.0 h1:q71M2QxMlBqRZOXc5mFAycJWuZqQ3hPTzVEo1r3CUTY=
@@ -1842,7 +1842,6 @@ github.com/grafana/grafana-google-sdk-go v0.1.0 h1:LKGY8z2DSxKjYfr2flZsWgTRTZ6HG
github.com/grafana/grafana-google-sdk-go v0.1.0/go.mod h1:Vo2TKWfDVmNTELBUM+3lkrZvFtBws0qSZdXhQxRdJrE= github.com/grafana/grafana-google-sdk-go v0.1.0/go.mod h1:Vo2TKWfDVmNTELBUM+3lkrZvFtBws0qSZdXhQxRdJrE=
github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79 h1:r+mU5bGMzcXCRVAuOrTn54S80qbfVkvTdUJZfSfTNbs= github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79 h1:r+mU5bGMzcXCRVAuOrTn54S80qbfVkvTdUJZfSfTNbs=
github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79/go.mod h1:wc6Hbh3K2TgCUSfBC/BOzabItujtHMESZeFk5ZhdxhQ= github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79/go.mod h1:wc6Hbh3K2TgCUSfBC/BOzabItujtHMESZeFk5ZhdxhQ=
github.com/grafana/grafana-plugin-sdk-go v0.94.0/go.mod h1:3VXz4nCv6wH5SfgB3mlW39s+c+LetqSCjFj7xxPC5+M=
github.com/grafana/grafana-plugin-sdk-go v0.114.0/go.mod h1:D7x3ah+1d4phNXpbnOaxa/osSaZlwh9/ZUnGGzegRbk= github.com/grafana/grafana-plugin-sdk-go v0.114.0/go.mod h1:D7x3ah+1d4phNXpbnOaxa/osSaZlwh9/ZUnGGzegRbk=
github.com/grafana/grafana-plugin-sdk-go v0.206.0 h1:DQK2M07/q0t7wqcJBSw6O/FQJZC1tm24uzGfHbA71+A= github.com/grafana/grafana-plugin-sdk-go v0.206.0 h1:DQK2M07/q0t7wqcJBSw6O/FQJZC1tm24uzGfHbA71+A=
github.com/grafana/grafana-plugin-sdk-go v0.206.0/go.mod h1:MetVbF3bGwmUvxulWsl0SskJFUq3+ZGnyjDH0dQ4sSg= github.com/grafana/grafana-plugin-sdk-go v0.206.0/go.mod h1:MetVbF3bGwmUvxulWsl0SskJFUq3+ZGnyjDH0dQ4sSg=
@@ -1859,8 +1858,8 @@ github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db h1:7aN5cccjIqCLTzed
github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A= github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A=
github.com/grafana/saml v0.4.15-0.20231025143828-a6c0e9b86a4c h1:1pHLC1ZTz7N5QI3jzCs5sqmVvAKe+JwGnpp9lQ+iUjY= github.com/grafana/saml v0.4.15-0.20231025143828-a6c0e9b86a4c h1:1pHLC1ZTz7N5QI3jzCs5sqmVvAKe+JwGnpp9lQ+iUjY=
github.com/grafana/saml v0.4.15-0.20231025143828-a6c0e9b86a4c/go.mod h1:S4+611dxnKt8z/ulbvaJzcgSHsuhjVc1QHNTcr1R7Fw= github.com/grafana/saml v0.4.15-0.20231025143828-a6c0e9b86a4c/go.mod h1:S4+611dxnKt8z/ulbvaJzcgSHsuhjVc1QHNTcr1R7Fw=
github.com/grafana/sqlds/v2 v2.3.10 h1:HWKhE0vR6LoEiE+Is8CSZOgaB//D1yqb2ntkass9Fd4= github.com/grafana/sqlds/v3 v3.2.0 h1:WXuYEaFfiCvgm8kK2ixx44/zAEjFzCylA2+RF3GBqZA=
github.com/grafana/sqlds/v2 v2.3.10/go.mod h1:c6ibxnxRVGxV/0YkEgvy7QpQH/lyifFyV7K/14xvdIs= github.com/grafana/sqlds/v3 v3.2.0/go.mod h1:kH0WuHUR3j0Q7IEymbm2JiaPckUhRCbqjV9ajaBAnmM=
github.com/grafana/tempo v1.5.1-0.20230524121406-1dc1bfe7085b h1:mDlkqgTEJuK7vjPG44f3ZMtId5AAYLWHvBVbiGqIOOQ= github.com/grafana/tempo v1.5.1-0.20230524121406-1dc1bfe7085b h1:mDlkqgTEJuK7vjPG44f3ZMtId5AAYLWHvBVbiGqIOOQ=
github.com/grafana/tempo v1.5.1-0.20230524121406-1dc1bfe7085b/go.mod h1:UK7kTP5llPeRcGBOe5mm4QTNTd0k/mAqTVSOFdDH6AU= github.com/grafana/tempo v1.5.1-0.20230524121406-1dc1bfe7085b/go.mod h1:UK7kTP5llPeRcGBOe5mm4QTNTd0k/mAqTVSOFdDH6AU=
github.com/grafana/thema v0.0.0-20230712153715-375c1b45f3ed h1:TMtHc+B0SSNw2in6Ro1dAiBYSPRp4NzKgndFDfupt18= github.com/grafana/thema v0.0.0-20230712153715-375c1b45f3ed h1:TMtHc+B0SSNw2in6Ro1dAiBYSPRp4NzKgndFDfupt18=
@@ -2348,9 +2347,18 @@ github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/mithrandie/csvq v1.17.10 h1:ba8W6rWgB6LfIhY1ttmgXzKNcCoVtT4e6zuZTaGuAQg=
github.com/mithrandie/csvq v1.17.10/go.mod h1:ALXIPvYIbBEJvcoB41WSQhhLqOXT+2P4VommU+2DLLc=
github.com/mithrandie/csvq-driver v1.6.8 h1:0rF4yZ0ByIECznd9Ld+Ry5tIEYq/zxbb3QYuni/JWFk=
github.com/mithrandie/csvq-driver v1.6.8/go.mod h1:SrUKsCbaFKaaxKrptvLJ882CFMJD2hJAjv+Ev1HcUM8=
github.com/mithrandie/go-file/v2 v2.1.0 h1:XA5Tl+73GXMDvgwSE3Sg0uC5FkLr3hnXs8SpUas0hyg=
github.com/mithrandie/go-file/v2 v2.1.0/go.mod h1:9YtTF3Xo59GqC1Pxw6KyGVcM/qubAMlxVsqI/u9r++c=
github.com/mithrandie/go-text v1.5.4 h1:2LIASku5RuCqxa6O6eOvQwQ0k5FYWP1ID2hk9egYYGc=
github.com/mithrandie/go-text v1.5.4/go.mod h1:yaVYauF3TLf7LvjGrrQB/mffIkohXTXJpW9zQ206UL8=
github.com/mithrandie/ternary v1.1.1 h1:k/joD6UGVYxHixYmSR8EGgDFNONBMqyD373xT4QRdC4=
github.com/mithrandie/ternary v1.1.1/go.mod h1:0D9Ba3+09K2TdSZO7/bFCC0GjSXetCvYuYq0u8FY/1g=
github.com/moby/moby v23.0.4+incompatible h1:A/pe8vi9KIKhNbzR0G3wW4ACKDsMgXILBveMqiJNa8M= github.com/moby/moby v23.0.4+incompatible h1:A/pe8vi9KIKhNbzR0G3wW4ACKDsMgXILBveMqiJNa8M=
github.com/moby/moby v23.0.4+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc= github.com/moby/moby v23.0.4+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc=
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=

View File

@@ -21,9 +21,12 @@ type Cfg struct {
ForwardHostEnvVars []string ForwardHostEnvVars []string
// AWS Plugin Auth // AWS Plugin Auth
AWSAllowedAuthProviders []string AWSAllowedAuthProviders []string
AWSAssumeRoleEnabled bool AWSAssumeRoleEnabled bool
AWSExternalId string AWSExternalId string
AWSSessionDuration string
AWSListMetricsPageLimit string
AWSForwardSettingsPlugins []string
// Azure Cloud settings // Azure Cloud settings
Azure *azsettings.AzureSettings Azure *azsettings.AzureSettings
@@ -54,33 +57,36 @@ type Cfg struct {
} }
func NewCfg(devMode bool, pluginsPath string, pluginSettings setting.PluginSettings, pluginsAllowUnsigned []string, func NewCfg(devMode bool, pluginsPath string, pluginSettings setting.PluginSettings, pluginsAllowUnsigned []string,
awsAllowedAuthProviders []string, awsAssumeRoleEnabled bool, awsExternalId string, azure *azsettings.AzureSettings, secureSocksDSProxy setting.SecureSocksDSProxySettings, awsAllowedAuthProviders []string, awsAssumeRoleEnabled bool, awsExternalId string, awsSessionDuration string, awsListMetricsPageLimit string, AWSForwardSettingsPlugins []string, azure *azsettings.AzureSettings, secureSocksDSProxy setting.SecureSocksDSProxySettings,
grafanaVersion string, logDatasourceRequests bool, pluginsCDNURLTemplate string, appURL string, appSubURL string, tracing Tracing, features featuremgmt.FeatureToggles, angularSupportEnabled bool, grafanaVersion string, logDatasourceRequests bool, pluginsCDNURLTemplate string, appURL string, appSubURL string, tracing Tracing, features featuremgmt.FeatureToggles, angularSupportEnabled bool,
grafanaComURL string, disablePlugins []string, hideAngularDeprecation []string, forwardHostEnvVars []string, concurrentQueryCount int, azureAuthEnabled bool) *Cfg { grafanaComURL string, disablePlugins []string, hideAngularDeprecation []string, forwardHostEnvVars []string, concurrentQueryCount int, azureAuthEnabled bool) *Cfg {
return &Cfg{ return &Cfg{
log: log.New("plugin.cfg"), log: log.New("plugin.cfg"),
PluginsPath: pluginsPath, PluginsPath: pluginsPath,
BuildVersion: grafanaVersion, BuildVersion: grafanaVersion,
DevMode: devMode, DevMode: devMode,
PluginSettings: pluginSettings, PluginSettings: pluginSettings,
PluginsAllowUnsigned: pluginsAllowUnsigned, PluginsAllowUnsigned: pluginsAllowUnsigned,
DisablePlugins: disablePlugins, DisablePlugins: disablePlugins,
AWSAllowedAuthProviders: awsAllowedAuthProviders, AWSAllowedAuthProviders: awsAllowedAuthProviders,
AWSAssumeRoleEnabled: awsAssumeRoleEnabled, AWSAssumeRoleEnabled: awsAssumeRoleEnabled,
AWSExternalId: awsExternalId, AWSExternalId: awsExternalId,
Azure: azure, AWSSessionDuration: awsSessionDuration,
ProxySettings: secureSocksDSProxy, AWSListMetricsPageLimit: awsListMetricsPageLimit,
LogDatasourceRequests: logDatasourceRequests, AWSForwardSettingsPlugins: AWSForwardSettingsPlugins,
PluginsCDNURLTemplate: pluginsCDNURLTemplate, Azure: azure,
Tracing: tracing, ProxySettings: secureSocksDSProxy,
GrafanaComURL: grafanaComURL, LogDatasourceRequests: logDatasourceRequests,
GrafanaAppURL: appURL, PluginsCDNURLTemplate: pluginsCDNURLTemplate,
GrafanaAppSubURL: appSubURL, Tracing: tracing,
Features: features, GrafanaComURL: grafanaComURL,
AngularSupportEnabled: angularSupportEnabled, GrafanaAppURL: appURL,
HideAngularDeprecation: hideAngularDeprecation, GrafanaAppSubURL: appSubURL,
ForwardHostEnvVars: forwardHostEnvVars, Features: features,
ConcurrentQueryCount: concurrentQueryCount, AngularSupportEnabled: angularSupportEnabled,
AzureAuthEnabled: azureAuthEnabled, HideAngularDeprecation: hideAngularDeprecation,
ForwardHostEnvVars: forwardHostEnvVars,
ConcurrentQueryCount: concurrentQueryCount,
AzureAuthEnabled: azureAuthEnabled,
} }
} }

View File

@@ -129,16 +129,24 @@ func (s *Service) GetConfigMap(ctx context.Context, pluginID string, _ *auth.Ext
m[featuretoggles.EnabledFeatures] = strings.Join(features, ",") m[featuretoggles.EnabledFeatures] = strings.Join(features, ",")
} }
} }
// TODO add support via plugin SDK
// if s.cfg.AWSAssumeRoleEnabled { if slices.Contains[[]string, string](s.cfg.AWSForwardSettingsPlugins, pluginID) {
// m[awsds.AssumeRoleEnabledEnvVarKeyName] = "true" if !s.cfg.AWSAssumeRoleEnabled {
// } m[awsds.AssumeRoleEnabledEnvVarKeyName] = "false"
// if len(s.cfg.AWSAllowedAuthProviders) > 0 { }
// m[awsds.AllowedAuthProvidersEnvVarKeyName] = strings.Join(s.cfg.AWSAllowedAuthProviders, ",") if len(s.cfg.AWSAllowedAuthProviders) > 0 {
// } m[awsds.AllowedAuthProvidersEnvVarKeyName] = strings.Join(s.cfg.AWSAllowedAuthProviders, ",")
// if s.cfg.AWSExternalId != "" { }
// m[awsds.GrafanaAssumeRoleExternalIdKeyName] = s.cfg.AWSExternalId if s.cfg.AWSExternalId != "" {
// } m[awsds.GrafanaAssumeRoleExternalIdKeyName] = s.cfg.AWSExternalId
}
if s.cfg.AWSSessionDuration != "" {
m[awsds.SessionDurationEnvVarKeyName] = s.cfg.AWSSessionDuration
}
if s.cfg.AWSListMetricsPageLimit != "" {
m[awsds.ListMetricsPageLimitKeyName] = s.cfg.AWSListMetricsPageLimit
}
}
if s.cfg.ProxySettings.Enabled { if s.cfg.ProxySettings.Enabled {
m[proxy.PluginSecureSocksProxyEnabled] = "true" m[proxy.PluginSecureSocksProxyEnabled] = "true"
@@ -257,8 +265,8 @@ func (s *Service) featureToggleEnableVar(ctx context.Context) []string {
func (s *Service) awsEnvVars() []string { func (s *Service) awsEnvVars() []string {
var variables []string var variables []string
if s.cfg.AWSAssumeRoleEnabled { if !s.cfg.AWSAssumeRoleEnabled {
variables = append(variables, awsds.AssumeRoleEnabledEnvVarKeyName+"=true") variables = append(variables, awsds.AssumeRoleEnabledEnvVarKeyName+"=false")
} }
if len(s.cfg.AWSAllowedAuthProviders) > 0 { if len(s.cfg.AWSAllowedAuthProviders) > 0 {
variables = append(variables, awsds.AllowedAuthProvidersEnvVarKeyName+"="+strings.Join(s.cfg.AWSAllowedAuthProviders, ",")) variables = append(variables, awsds.AllowedAuthProvidersEnvVarKeyName+"="+strings.Join(s.cfg.AWSAllowedAuthProviders, ","))
@@ -266,6 +274,12 @@ func (s *Service) awsEnvVars() []string {
if s.cfg.AWSExternalId != "" { if s.cfg.AWSExternalId != "" {
variables = append(variables, awsds.GrafanaAssumeRoleExternalIdKeyName+"="+s.cfg.AWSExternalId) variables = append(variables, awsds.GrafanaAssumeRoleExternalIdKeyName+"="+s.cfg.AWSExternalId)
} }
if s.cfg.AWSSessionDuration != "" {
variables = append(variables, awsds.SessionDurationEnvVarKeyName+"="+s.cfg.AWSSessionDuration)
}
if s.cfg.AWSListMetricsPageLimit != "" {
variables = append(variables, awsds.ListMetricsPageLimitKeyName+"="+s.cfg.AWSListMetricsPageLimit)
}
return variables return variables
} }

View File

@@ -40,6 +40,7 @@ func TestInitializer_envVars(t *testing.T) {
"custom_env_var": "customVal", "custom_env_var": "customVal",
}, },
}, },
AWSAssumeRoleEnabled: true,
}, licensing) }, licensing)
envVars := envVarsProvider.Get(context.Background(), p) envVars := envVarsProvider.Get(context.Background(), p)
@@ -203,7 +204,8 @@ func TestInitializer_tracingEnvironmentVariables(t *testing.T) {
{ {
name: "otel not configured", name: "otel not configured",
cfg: &config.Cfg{ cfg: &config.Cfg{
Tracing: config.Tracing{}, Tracing: config.Tracing{},
AWSAssumeRoleEnabled: false,
}, },
plugin: defaultPlugin, plugin: defaultPlugin,
exp: expNoTracing, exp: expNoTracing,
@@ -257,6 +259,7 @@ func TestInitializer_tracingEnvironmentVariables(t *testing.T) {
PluginSettings: map[string]map[string]string{ PluginSettings: map[string]map[string]string{
pluginID: {"tracing": "true"}, pluginID: {"tracing": "true"},
}, },
AWSAssumeRoleEnabled: true,
}, },
plugin: defaultPlugin, plugin: defaultPlugin,
exp: func(t *testing.T, envVars []string) { exp: func(t *testing.T, envVars []string) {
@@ -288,6 +291,7 @@ func TestInitializer_tracingEnvironmentVariables(t *testing.T) {
PluginSettings: map[string]map[string]string{ PluginSettings: map[string]map[string]string{
pluginID: {"tracing": "true"}, pluginID: {"tracing": "true"},
}, },
AWSAssumeRoleEnabled: true,
}, },
plugin: defaultPlugin, plugin: defaultPlugin,
exp: func(t *testing.T, envVars []string) { exp: func(t *testing.T, envVars []string) {
@@ -337,6 +341,7 @@ func TestInitializer_tracingEnvironmentVariables(t *testing.T) {
PluginSettings: map[string]map[string]string{ PluginSettings: map[string]map[string]string{
pluginID: {"some_other_option": "true"}, pluginID: {"some_other_option": "true"},
}, },
AWSAssumeRoleEnabled: true,
}, },
plugin: defaultPlugin, plugin: defaultPlugin,
exp: expNoTracing, exp: expNoTracing,
@@ -581,12 +586,14 @@ func TestInitalizer_awsEnvVars(t *testing.T) {
t.Run("backend datasource with aws settings", func(t *testing.T) { t.Run("backend datasource with aws settings", func(t *testing.T) {
p := &plugins.Plugin{} p := &plugins.Plugin{}
envVarsProvider := NewProvider(&config.Cfg{ envVarsProvider := NewProvider(&config.Cfg{
AWSAssumeRoleEnabled: true, AWSAssumeRoleEnabled: false,
AWSAllowedAuthProviders: []string{"grafana_assume_role", "keys"}, AWSAllowedAuthProviders: []string{"grafana_assume_role", "keys"},
AWSExternalId: "mock_external_id", AWSExternalId: "mock_external_id",
AWSSessionDuration: "10m",
AWSListMetricsPageLimit: "100",
}, nil) }, nil)
envVars := envVarsProvider.Get(context.Background(), p) envVars := envVarsProvider.Get(context.Background(), p)
assert.ElementsMatch(t, []string{"GF_VERSION=", "AWS_AUTH_AssumeRoleEnabled=true", "AWS_AUTH_AllowedAuthProviders=grafana_assume_role,keys", "AWS_AUTH_EXTERNAL_ID=mock_external_id"}, envVars) assert.ElementsMatch(t, []string{"GF_VERSION=", "AWS_AUTH_AssumeRoleEnabled=false", "AWS_AUTH_AllowedAuthProviders=grafana_assume_role,keys", "AWS_AUTH_EXTERNAL_ID=mock_external_id", "AWS_AUTH_SESSION_DURATION=10m", "AWS_CW_LIST_METRICS_PAGE_LIMIT=100"}, envVars)
}) })
} }
@@ -604,7 +611,7 @@ func TestInitializer_featureToggleEnvVar(t *testing.T) {
}, nil) }, nil)
envVars := envVarsProvider.Get(context.Background(), p) envVars := envVarsProvider.Get(context.Background(), p)
assert.Equal(t, 2, len(envVars)) assert.Equal(t, 3, len(envVars))
toggleExpression := strings.Split(envVars[1], "=") toggleExpression := strings.Split(envVars[1], "=")
assert.Equal(t, 2, len(toggleExpression)) assert.Equal(t, 2, len(toggleExpression))
@@ -628,6 +635,7 @@ func TestInitalizer_azureEnvVars(t *testing.T) {
t.Run("backend datasource with azure settings", func(t *testing.T) { t.Run("backend datasource with azure settings", func(t *testing.T) {
p := &plugins.Plugin{} p := &plugins.Plugin{}
envVarsProvider := NewProvider(&config.Cfg{ envVarsProvider := NewProvider(&config.Cfg{
AWSAssumeRoleEnabled: true,
Azure: &azsettings.AzureSettings{ Azure: &azsettings.AzureSettings{
Cloud: azsettings.AzurePublic, Cloud: azsettings.AzurePublic,
ManagedIdentityEnabled: true, ManagedIdentityEnabled: true,
@@ -925,3 +933,48 @@ func TestService_GetConfigMap_azure(t *testing.T) {
}, s.GetConfigMap(context.Background(), "test-datasource", nil)) }, s.GetConfigMap(context.Background(), "test-datasource", nil))
}) })
} }
func TestService_GetConfigMap_aws(t *testing.T) {
cfg := &config.Cfg{
AWSAssumeRoleEnabled: false,
AWSAllowedAuthProviders: []string{"grafana_assume_role", "keys"},
AWSExternalId: "mock_external_id",
AWSSessionDuration: "10m",
AWSListMetricsPageLimit: "100",
AWSForwardSettingsPlugins: []string{"cloudwatch", "prometheus", "elasticsearch"},
}
t.Run("uses the aws settings for an AWS plugin", func(t *testing.T) {
s := &Service{
cfg: cfg,
}
require.Equal(t, map[string]string{
"AWS_AUTH_AssumeRoleEnabled": "false",
"AWS_AUTH_AllowedAuthProviders": "grafana_assume_role,keys",
"AWS_AUTH_EXTERNAL_ID": "mock_external_id",
"AWS_AUTH_SESSION_DURATION": "10m",
"AWS_CW_LIST_METRICS_PAGE_LIMIT": "100",
}, s.GetConfigMap(context.Background(), "cloudwatch", nil))
})
t.Run("does not use the aws settings for a non-aws plugin", func(t *testing.T) {
s := &Service{
cfg: cfg,
}
require.Equal(t, map[string]string{}, s.GetConfigMap(context.Background(), "", nil))
})
t.Run("uses the aws settings for a non-aws user-specified plugin", func(t *testing.T) {
cfg.AWSForwardSettingsPlugins = append(cfg.AWSForwardSettingsPlugins, "test-datasource")
s := &Service{
cfg: cfg,
}
require.Equal(t, map[string]string{
"AWS_AUTH_AssumeRoleEnabled": "false",
"AWS_AUTH_AllowedAuthProviders": "grafana_assume_role,keys",
"AWS_AUTH_EXTERNAL_ID": "mock_external_id",
"AWS_AUTH_SESSION_DURATION": "10m",
"AWS_CW_LIST_METRICS_PAGE_LIMIT": "100",
}, s.GetConfigMap(context.Background(), "test-datasource", nil))
})
}

View File

@@ -7,6 +7,7 @@ import (
pCfg "github.com/grafana/grafana/pkg/plugins/config" pCfg "github.com/grafana/grafana/pkg/plugins/config"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
) )
func ProvideConfig(settingProvider setting.Provider, grafanaCfg *setting.Cfg, features featuremgmt.FeatureToggles) (*pCfg.Cfg, error) { func ProvideConfig(settingProvider setting.Provider, grafanaCfg *setting.Cfg, features featuremgmt.FeatureToggles) (*pCfg.Cfg, error) {
@@ -16,11 +17,19 @@ func ProvideConfig(settingProvider setting.Provider, grafanaCfg *setting.Cfg, fe
allowedUnsigned = strings.Split(plugins.KeyValue("allow_loading_unsigned_plugins").Value(), ",") allowedUnsigned = strings.Split(plugins.KeyValue("allow_loading_unsigned_plugins").Value(), ",")
} }
// Get aws settings from settingProvider instead of grafanaCfg
aws := settingProvider.Section("aws") aws := settingProvider.Section("aws")
allowedAuth := grafanaCfg.AWSAllowedAuthProviders allowedAuth := grafanaCfg.AWSAllowedAuthProviders
if len(aws.KeyValue("allowed_auth_providers").Value()) > 0 { if len(aws.KeyValue("allowed_auth_providers").Value()) > 0 {
allowedAuth = util.SplitString(aws.KeyValue("allowed_auth_providers").Value())
}
if len(allowedAuth) > 0 {
allowedUnsigned = strings.Split(settingProvider.KeyValue("plugins", "allow_loading_unsigned_plugins").Value(), ",") allowedUnsigned = strings.Split(settingProvider.KeyValue("plugins", "allow_loading_unsigned_plugins").Value(), ",")
} }
awsForwardSettingsPlugins := grafanaCfg.AWSForwardSettingsPlugins
if len(aws.KeyValue("forward_settings_to_plugins").Value()) > 0 {
awsForwardSettingsPlugins = util.SplitString(aws.KeyValue("forward_settings_to_plugins").Value())
}
tracingCfg, err := newTracingCfg(grafanaCfg) tracingCfg, err := newTracingCfg(grafanaCfg)
if err != nil { if err != nil {
@@ -35,6 +44,9 @@ func ProvideConfig(settingProvider setting.Provider, grafanaCfg *setting.Cfg, fe
allowedAuth, allowedAuth,
aws.KeyValue("assume_role_enabled").MustBool(grafanaCfg.AWSAssumeRoleEnabled), aws.KeyValue("assume_role_enabled").MustBool(grafanaCfg.AWSAssumeRoleEnabled),
aws.KeyValue("external_id").Value(), aws.KeyValue("external_id").Value(),
aws.KeyValue("session_duration").Value(),
aws.KeyValue("list_metrics_page_limit").Value(),
awsForwardSettingsPlugins,
grafanaCfg.Azure, grafanaCfg.Azure,
grafanaCfg.SecureSocksDSProxy, grafanaCfg.SecureSocksDSProxy,
grafanaCfg.BuildVersion, grafanaCfg.BuildVersion,

View File

@@ -509,6 +509,7 @@ func TestLoader_Load_ExternalRegistration(t *testing.T) {
cfg := &config.Cfg{ cfg := &config.Cfg{
Features: featuremgmt.WithFeatures(featuremgmt.FlagExternalServiceAuth), Features: featuremgmt.WithFeatures(featuremgmt.FlagExternalServiceAuth),
PluginsAllowUnsigned: []string{"grafana-test-datasource"}, PluginsAllowUnsigned: []string{"grafana-test-datasource"},
AWSAssumeRoleEnabled: true,
} }
pluginPaths := []string{filepath.Join(testDataDir(t), "oauth-external-registration")} pluginPaths := []string{filepath.Join(testDataDir(t), "oauth-external-registration")}
expected := []*plugins.Plugin{ expected := []*plugins.Plugin{
@@ -610,6 +611,7 @@ func TestLoader_Load_ExternalRegistration(t *testing.T) {
cfg := &config.Cfg{ cfg := &config.Cfg{
Features: featuremgmt.WithFeatures(featuremgmt.FlagExternalServiceAuth), Features: featuremgmt.WithFeatures(featuremgmt.FlagExternalServiceAuth),
PluginsAllowUnsigned: []string{"grafana-test-datasource"}, PluginsAllowUnsigned: []string{"grafana-test-datasource"},
AWSAssumeRoleEnabled: true,
} }
pluginPaths := []string{filepath.Join(testDataDir(t), "external-registration")} pluginPaths := []string{filepath.Join(testDataDir(t), "external-registration")}
expected := []*plugins.Plugin{ expected := []*plugins.Plugin{

View File

@@ -71,7 +71,7 @@ func TestIntegrationPluginManager(t *testing.T) {
hcp := httpclient.NewProvider() hcp := httpclient.NewProvider()
am := azuremonitor.ProvideService(hcp) am := azuremonitor.ProvideService(hcp)
cw := cloudwatch.ProvideService(cfg, hcp) cw := cloudwatch.ProvideService(hcp)
cm := cloudmonitoring.ProvideService(hcp) cm := cloudmonitoring.ProvideService(hcp)
es := elasticsearch.ProvideService(hcp, tracer) es := elasticsearch.ProvideService(hcp, tracer)
grap := graphite.ProvideService(hcp, tracer) grap := graphite.ProvideService(hcp, tracer)

View File

@@ -240,10 +240,12 @@ type Cfg struct {
AuthConfigUIAdminAccess bool AuthConfigUIAdminAccess bool
// AWS Plugin Auth // AWS Plugin Auth
AWSAllowedAuthProviders []string AWSAllowedAuthProviders []string
AWSAssumeRoleEnabled bool AWSAssumeRoleEnabled bool
AWSListMetricsPageLimit int AWSSessionDuration string
AWSExternalId string AWSExternalId string
AWSListMetricsPageLimit int
AWSForwardSettingsPlugins []string
// Azure Cloud settings // Azure Cloud settings
Azure *azsettings.AzureSettings Azure *azsettings.AzureSettings
@@ -1325,6 +1327,10 @@ func (cfg *Cfg) handleAWSConfig() {
} }
} }
cfg.AWSListMetricsPageLimit = awsPluginSec.Key("list_metrics_page_limit").MustInt(500) cfg.AWSListMetricsPageLimit = awsPluginSec.Key("list_metrics_page_limit").MustInt(500)
cfg.AWSExternalId = awsPluginSec.Key("external_id").Value()
cfg.AWSSessionDuration = awsPluginSec.Key("session_duration").Value()
cfg.AWSForwardSettingsPlugins = util.SplitString(awsPluginSec.Key("forward_settings_to_plugins").String())
// Also set environment variables that can be used by core plugins // Also set environment variables that can be used by core plugins
err := os.Setenv(awsds.AssumeRoleEnabledEnvVarKeyName, strconv.FormatBool(cfg.AWSAssumeRoleEnabled)) err := os.Setenv(awsds.AssumeRoleEnabledEnvVarKeyName, strconv.FormatBool(cfg.AWSAssumeRoleEnabled))
if err != nil { if err != nil {
@@ -1336,11 +1342,20 @@ func (cfg *Cfg) handleAWSConfig() {
cfg.Logger.Error(fmt.Sprintf("could not set environment variable '%s'", awsds.AllowedAuthProvidersEnvVarKeyName), err) cfg.Logger.Error(fmt.Sprintf("could not set environment variable '%s'", awsds.AllowedAuthProvidersEnvVarKeyName), err)
} }
cfg.AWSExternalId = awsPluginSec.Key("external_id").Value() err = os.Setenv(awsds.ListMetricsPageLimitKeyName, strconv.Itoa(cfg.AWSListMetricsPageLimit))
if err != nil {
cfg.Logger.Error(fmt.Sprintf("could not set environment variable '%s'", awsds.ListMetricsPageLimitKeyName), err)
}
err = os.Setenv(awsds.GrafanaAssumeRoleExternalIdKeyName, cfg.AWSExternalId) err = os.Setenv(awsds.GrafanaAssumeRoleExternalIdKeyName, cfg.AWSExternalId)
if err != nil { if err != nil {
cfg.Logger.Error(fmt.Sprintf("could not set environment variable '%s'", awsds.GrafanaAssumeRoleExternalIdKeyName), err) cfg.Logger.Error(fmt.Sprintf("could not set environment variable '%s'", awsds.GrafanaAssumeRoleExternalIdKeyName), err)
} }
err = os.Setenv(awsds.SessionDurationEnvVarKeyName, cfg.AWSSessionDuration)
if err != nil {
cfg.Logger.Error(fmt.Sprintf("could not set environment variable '%s'", awsds.SessionDurationEnvVarKeyName), err)
}
} }
func (cfg *Cfg) readSessionConfig() { func (cfg *Cfg) readSessionConfig() {

View File

@@ -10,9 +10,6 @@ import (
"github.com/aws/aws-sdk-go/service/cloudwatch" "github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface" "github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface"
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -30,11 +27,9 @@ func TestQuery_AnnotationQuery(t *testing.T) {
t.Run("DescribeAlarmsForMetric is called with minimum parameters", func(t *testing.T) { t.Run("DescribeAlarmsForMetric is called with minimum parameters", func(t *testing.T) {
client = fakeCWAnnotationsClient{describeAlarmsForMetricOutput: &cloudwatch.DescribeAlarmsForMetricOutput{}} client = fakeCWAnnotationsClient{describeAlarmsForMetricOutput: &cloudwatch.DescribeAlarmsForMetricOutput{}}
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := defaultTestInstanceManager()
return DataSource{Settings: models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@@ -64,11 +59,9 @@ func TestQuery_AnnotationQuery(t *testing.T) {
t.Run("DescribeAlarms is called when prefixMatching is true", func(t *testing.T) { t.Run("DescribeAlarms is called when prefixMatching is true", func(t *testing.T) {
client = fakeCWAnnotationsClient{describeAlarmsOutput: &cloudwatch.DescribeAlarmsOutput{}} client = fakeCWAnnotationsClient{describeAlarmsOutput: &cloudwatch.DescribeAlarmsOutput{}}
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := defaultTestInstanceManager()
return DataSource{Settings: models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},

View File

@@ -6,7 +6,6 @@ import (
"github.com/aws/aws-sdk-go/aws/awsutil" "github.com/aws/aws-sdk-go/aws/awsutil"
"github.com/aws/aws-sdk-go/service/cloudwatch" "github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/grafana/grafana/pkg/infra/metrics" "github.com/grafana/grafana/pkg/infra/metrics"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources"
) )
@@ -14,11 +13,11 @@ import (
// this client wraps the CloudWatch API and handles pagination and the composition of the MetricResponse DTO // this client wraps the CloudWatch API and handles pagination and the composition of the MetricResponse DTO
type metricsClient struct { type metricsClient struct {
models.CloudWatchMetricsAPIProvider models.CloudWatchMetricsAPIProvider
config *setting.Cfg listMetricsPageLimit int
} }
func NewMetricsClient(api models.CloudWatchMetricsAPIProvider, config *setting.Cfg) *metricsClient { func NewMetricsClient(api models.CloudWatchMetricsAPIProvider, pageLimit int) *metricsClient {
return &metricsClient{CloudWatchMetricsAPIProvider: api, config: config} return &metricsClient{CloudWatchMetricsAPIProvider: api, listMetricsPageLimit: pageLimit}
} }
func (l *metricsClient) ListMetricsWithPageLimit(ctx context.Context, params *cloudwatch.ListMetricsInput) ([]resources.MetricResponse, error) { func (l *metricsClient) ListMetricsWithPageLimit(ctx context.Context, params *cloudwatch.ListMetricsInput) ([]resources.MetricResponse, error) {
@@ -37,7 +36,7 @@ func (l *metricsClient) ListMetricsWithPageLimit(ctx context.Context, params *cl
cloudWatchMetrics = append(cloudWatchMetrics, metric) cloudWatchMetrics = append(cloudWatchMetrics, metric)
} }
} }
return !lastPage && pageNum < l.config.AWSListMetricsPageLimit return !lastPage && pageNum < l.listMetricsPageLimit
}) })
return cloudWatchMetrics, err return cloudWatchMetrics, err

View File

@@ -6,7 +6,6 @@ import (
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cloudwatch" "github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -31,7 +30,7 @@ func TestMetricsClient(t *testing.T) {
t.Run("List Metrics and page limit is reached", func(t *testing.T) { t.Run("List Metrics and page limit is reached", func(t *testing.T) {
pageLimit := 3 pageLimit := 3
fakeApi := &mocks.FakeMetricsAPI{Metrics: metrics, MetricsPerPage: 2} fakeApi := &mocks.FakeMetricsAPI{Metrics: metrics, MetricsPerPage: 2}
client := NewMetricsClient(fakeApi, &setting.Cfg{AWSListMetricsPageLimit: pageLimit}) client := NewMetricsClient(fakeApi, pageLimit)
response, err := client.ListMetricsWithPageLimit(ctx, &cloudwatch.ListMetricsInput{}) response, err := client.ListMetricsWithPageLimit(ctx, &cloudwatch.ListMetricsInput{})
require.NoError(t, err) require.NoError(t, err)
@@ -42,7 +41,7 @@ func TestMetricsClient(t *testing.T) {
t.Run("List Metrics and page limit is not reached", func(t *testing.T) { t.Run("List Metrics and page limit is not reached", func(t *testing.T) {
pageLimit := 2 pageLimit := 2
fakeApi := &mocks.FakeMetricsAPI{Metrics: metrics} fakeApi := &mocks.FakeMetricsAPI{Metrics: metrics}
client := NewMetricsClient(fakeApi, &setting.Cfg{AWSListMetricsPageLimit: pageLimit}) client := NewMetricsClient(fakeApi, pageLimit)
response, err := client.ListMetricsWithPageLimit(ctx, &cloudwatch.ListMetricsInput{}) response, err := client.ListMetricsWithPageLimit(ctx, &cloudwatch.ListMetricsInput{})
require.NoError(t, err) require.NoError(t, err)
@@ -56,7 +55,7 @@ func TestMetricsClient(t *testing.T) {
{MetricName: aws.String("Test_MetricName2")}, {MetricName: aws.String("Test_MetricName2")},
{MetricName: aws.String("Test_MetricName3")}, {MetricName: aws.String("Test_MetricName3")},
}, OwningAccounts: []*string{aws.String("1234567890"), aws.String("1234567890"), aws.String("1234567895")}} }, OwningAccounts: []*string{aws.String("1234567890"), aws.String("1234567890"), aws.String("1234567895")}}
client := NewMetricsClient(fakeApi, &setting.Cfg{AWSListMetricsPageLimit: 100}) client := NewMetricsClient(fakeApi, 100)
response, err := client.ListMetricsWithPageLimit(ctx, &cloudwatch.ListMetricsInput{IncludeLinkedAccounts: aws.Bool(true)}) response, err := client.ListMetricsWithPageLimit(ctx, &cloudwatch.ListMetricsInput{IncludeLinkedAccounts: aws.Bool(true)})
require.NoError(t, err) require.NoError(t, err)
@@ -70,7 +69,7 @@ func TestMetricsClient(t *testing.T) {
t.Run("Should not return account id in case IncludeLinkedAccounts is set to false", func(t *testing.T) { t.Run("Should not return account id in case IncludeLinkedAccounts is set to false", func(t *testing.T) {
fakeApi := &mocks.FakeMetricsAPI{Metrics: []*cloudwatch.Metric{{MetricName: aws.String("Test_MetricName1")}}, OwningAccounts: []*string{aws.String("1234567890")}} fakeApi := &mocks.FakeMetricsAPI{Metrics: []*cloudwatch.Metric{{MetricName: aws.String("Test_MetricName1")}}, OwningAccounts: []*string{aws.String("1234567890")}}
client := NewMetricsClient(fakeApi, &setting.Cfg{AWSListMetricsPageLimit: 100}) client := NewMetricsClient(fakeApi, 100)
response, err := client.ListMetricsWithPageLimit(ctx, &cloudwatch.ListMetricsInput{IncludeLinkedAccounts: aws.Bool(false)}) response, err := client.ListMetricsWithPageLimit(ctx, &cloudwatch.ListMetricsInput{IncludeLinkedAccounts: aws.Bool(false)})
require.NoError(t, err) require.NoError(t, err)

View File

@@ -24,7 +24,6 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend/proxy" "github.com/grafana/grafana-plugin-sdk-go/backend/proxy"
"github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter" "github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/clients" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/clients"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/kinds/dataquery" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/kinds/dataquery"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
@@ -64,19 +63,16 @@ const (
var logger = log.New("tsdb.cloudwatch") var logger = log.New("tsdb.cloudwatch")
func ProvideService(cfg *setting.Cfg, httpClientProvider *httpclient.Provider) *CloudWatchService { func ProvideService(httpClientProvider *httpclient.Provider) *CloudWatchService {
logger.Debug("Initializing") logger.Debug("Initializing")
executor := newExecutor(datasource.NewInstanceManager(NewInstanceSettings(httpClientProvider)), cfg, awsds.NewSessionCache()) executor := newExecutor(datasource.NewInstanceManager(NewInstanceSettings(httpClientProvider)), awsds.NewSessionCache())
return &CloudWatchService{ return &CloudWatchService{
Cfg: cfg,
Executor: executor, Executor: executor,
} }
} }
type CloudWatchService struct { type CloudWatchService struct {
Cfg *setting.Cfg
Executor *cloudWatchExecutor Executor *cloudWatchExecutor
} }
@@ -84,10 +80,9 @@ type SessionCache interface {
GetSession(c awsds.SessionConfig) (*session.Session, error) GetSession(c awsds.SessionConfig) (*session.Session, error)
} }
func newExecutor(im instancemgmt.InstanceManager, cfg *setting.Cfg, sessions SessionCache) *cloudWatchExecutor { func newExecutor(im instancemgmt.InstanceManager, sessions SessionCache) *cloudWatchExecutor {
e := &cloudWatchExecutor{ e := &cloudWatchExecutor{
im: im, im: im,
cfg: cfg,
sessions: sessions, sessions: sessions,
} }
@@ -97,7 +92,7 @@ func newExecutor(im instancemgmt.InstanceManager, cfg *setting.Cfg, sessions Ses
func NewInstanceSettings(httpClientProvider *httpclient.Provider) datasource.InstanceFactoryFunc { func NewInstanceSettings(httpClientProvider *httpclient.Provider) datasource.InstanceFactoryFunc {
return func(ctx context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { return func(ctx context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
instanceSettings, err := models.LoadCloudWatchSettings(settings) instanceSettings, err := models.LoadCloudWatchSettings(ctx, settings)
if err != nil { if err != nil {
return nil, fmt.Errorf("error reading settings: %w", err) return nil, fmt.Errorf("error reading settings: %w", err)
} }
@@ -125,7 +120,6 @@ func NewInstanceSettings(httpClientProvider *httpclient.Provider) datasource.Ins
// cloudWatchExecutor executes CloudWatch requests. // cloudWatchExecutor executes CloudWatch requests.
type cloudWatchExecutor struct { type cloudWatchExecutor struct {
im instancemgmt.InstanceManager im instancemgmt.InstanceManager
cfg *setting.Cfg
sessions SessionCache sessions SessionCache
regionCache sync.Map regionCache sync.Map
@@ -154,7 +148,7 @@ func (e *cloudWatchExecutor) getRequestContext(ctx context.Context, pluginCtx ba
return models.RequestContext{ return models.RequestContext{
OAMAPIProvider: NewOAMAPI(sess), OAMAPIProvider: NewOAMAPI(sess),
MetricsClientProvider: clients.NewMetricsClient(NewMetricsAPI(sess), e.cfg), MetricsClientProvider: clients.NewMetricsClient(NewMetricsAPI(sess), instance.Settings.GrafanaSettings.ListMetricsPageLimit),
LogsAPIProvider: NewLogsAPI(sess), LogsAPIProvider: NewLogsAPI(sess),
EC2APIProvider: ec2Client, EC2APIProvider: ec2Client,
Settings: instance.Settings, Settings: instance.Settings,
@@ -236,7 +230,13 @@ func (e *cloudWatchExecutor) checkHealthMetrics(ctx context.Context, pluginCtx b
if err != nil { if err != nil {
return err return err
} }
metricClient := clients.NewMetricsClient(NewMetricsAPI(session), e.cfg)
instance, err := e.getInstance(ctx, pluginCtx)
if err != nil {
return err
}
metricClient := clients.NewMetricsClient(NewMetricsAPI(session), instance.Settings.GrafanaSettings.ListMetricsPageLimit)
_, err = metricClient.ListMetricsWithPageLimit(ctx, params) _, err = metricClient.ListMetricsWithPageLimit(ctx, params)
return err return err
} }
@@ -279,13 +279,14 @@ func (e *cloudWatchExecutor) newSession(ctx context.Context, pluginCtx backend.P
SecretKey: instance.Settings.SecretKey, SecretKey: instance.Settings.SecretKey,
}, },
UserAgentName: aws.String("Cloudwatch"), UserAgentName: aws.String("Cloudwatch"),
AuthSettings: &instance.Settings.GrafanaSettings,
}) })
if err != nil { if err != nil {
return nil, err return nil, err
} }
// work around until https://github.com/grafana/grafana/issues/39089 is implemented // work around until https://github.com/grafana/grafana/issues/39089 is implemented
if e.cfg.SecureSocksDSProxy.Enabled && instance.Settings.SecureSocksProxyEnabled { if instance.Settings.GrafanaSettings.SecureSocksDSProxyEnabled && instance.Settings.SecureSocksProxyEnabled {
// only update the transport to try to avoid the issue mentioned here https://github.com/grafana/grafana/issues/46365 // only update the transport to try to avoid the issue mentioned here https://github.com/grafana/grafana/issues/46365
// also, 'sess' is cached and reused, so the first time it might have the transport not set, the following uses it will // also, 'sess' is cached and reused, so the first time it might have the transport not set, the following uses it will
if sess.Config.HTTPClient.Transport == nil { if sess.Config.HTTPClient.Transport == nil {

View File

@@ -16,7 +16,6 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource" "github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt" "github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources"
@@ -54,16 +53,8 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
return &api return &api
} }
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{
AWSDatasourceSettings: awsds.AWSDatasourceSettings{
Region: "us-east-1",
},
}}, nil
})
t.Run("Should handle dimension value request and return values from the api", func(t *testing.T) { t.Run("Should handle dimension value request and return values from the api", func(t *testing.T) {
pageLimit := 100 im := testInstanceManager(100)
api = mocks.FakeMetricsAPI{Metrics: []*cloudwatch.Metric{ api = mocks.FakeMetricsAPI{Metrics: []*cloudwatch.Metric{
{MetricName: aws.String("Test_MetricName1"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1"), Value: aws.String("Value1")}, {Name: aws.String("Test_DimensionName2"), Value: aws.String("Value2")}}}, {MetricName: aws.String("Test_MetricName1"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1"), Value: aws.String("Value1")}, {Name: aws.String("Test_DimensionName2"), Value: aws.String("Value2")}}},
{MetricName: aws.String("Test_MetricName2"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1"), Value: aws.String("Value3")}}}, {MetricName: aws.String("Test_MetricName2"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1"), Value: aws.String("Value3")}}},
@@ -76,7 +67,7 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
{MetricName: aws.String("Test_MetricName8"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName4"), Value: aws.String("Value1")}}}, {MetricName: aws.String("Test_MetricName8"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName4"), Value: aws.String("Value1")}}},
{MetricName: aws.String("Test_MetricName9"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1"), Value: aws.String("Value2")}}}, {MetricName: aws.String("Test_MetricName9"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1"), Value: aws.String("Value2")}}},
}, MetricsPerPage: 100} }, MetricsPerPage: 100}
executor := newExecutor(im, &setting.Cfg{AWSListMetricsPageLimit: pageLimit}, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
req := &backend.CallResourceRequest{ req := &backend.CallResourceRequest{
Method: "GET", Method: "GET",
@@ -99,7 +90,7 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
}) })
t.Run("Should handle dimension key filter query and return keys from the api", func(t *testing.T) { t.Run("Should handle dimension key filter query and return keys from the api", func(t *testing.T) {
pageLimit := 3 im := testInstanceManager(3)
api = mocks.FakeMetricsAPI{Metrics: []*cloudwatch.Metric{ api = mocks.FakeMetricsAPI{Metrics: []*cloudwatch.Metric{
{MetricName: aws.String("Test_MetricName1"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1")}, {Name: aws.String("Test_DimensionName2")}}}, {MetricName: aws.String("Test_MetricName1"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1")}, {Name: aws.String("Test_DimensionName2")}}},
{MetricName: aws.String("Test_MetricName2"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1")}}}, {MetricName: aws.String("Test_MetricName2"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1")}}},
@@ -112,8 +103,7 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
{MetricName: aws.String("Test_MetricName8"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName4")}}}, {MetricName: aws.String("Test_MetricName8"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName4")}}},
{MetricName: aws.String("Test_MetricName9"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1")}}}, {MetricName: aws.String("Test_MetricName9"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1")}}},
}, MetricsPerPage: 2} }, MetricsPerPage: 2}
executor := newExecutor(im, &setting.Cfg{AWSListMetricsPageLimit: pageLimit}, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
req := &backend.CallResourceRequest{ req := &backend.CallResourceRequest{
Method: "GET", Method: "GET",
Path: `/dimension-keys?region=us-east-2&namespace=AWS/EC2&metricName=CPUUtilization&dimensionFilters={"NodeID":["Shared"],"stage":["QueryCommit"]}`, Path: `/dimension-keys?region=us-east-2&namespace=AWS/EC2&metricName=CPUUtilization&dimensionFilters={"NodeID":["Shared"],"stage":["QueryCommit"]}`,
@@ -135,8 +125,9 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
}) })
t.Run("Should handle standard dimension key query and return hard coded keys", func(t *testing.T) { t.Run("Should handle standard dimension key query and return hard coded keys", func(t *testing.T) {
im := defaultTestInstanceManager()
api = mocks.FakeMetricsAPI{} api = mocks.FakeMetricsAPI{}
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
req := &backend.CallResourceRequest{ req := &backend.CallResourceRequest{
Method: "GET", Method: "GET",
@@ -159,9 +150,9 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
}) })
t.Run("Should handle custom namespace dimension key query and return hard coded keys", func(t *testing.T) { t.Run("Should handle custom namespace dimension key query and return hard coded keys", func(t *testing.T) {
im := defaultTestInstanceManager()
api = mocks.FakeMetricsAPI{} api = mocks.FakeMetricsAPI{}
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
req := &backend.CallResourceRequest{ req := &backend.CallResourceRequest{
Method: "GET", Method: "GET",
Path: `/dimension-keys?region=us-east-2&namespace=AWS/CloudSearch&metricName=CPUUtilization`, Path: `/dimension-keys?region=us-east-2&namespace=AWS/CloudSearch&metricName=CPUUtilization`,
@@ -183,7 +174,7 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
}) })
t.Run("Should handle custom namespace metrics query and return metrics from api", func(t *testing.T) { t.Run("Should handle custom namespace metrics query and return metrics from api", func(t *testing.T) {
pageLimit := 3 im := testInstanceManager(3)
api = mocks.FakeMetricsAPI{Metrics: []*cloudwatch.Metric{ api = mocks.FakeMetricsAPI{Metrics: []*cloudwatch.Metric{
{MetricName: aws.String("Test_MetricName1"), Namespace: aws.String("AWS/EC2"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1")}, {Name: aws.String("Test_DimensionName2")}}}, {MetricName: aws.String("Test_MetricName1"), Namespace: aws.String("AWS/EC2"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1")}, {Name: aws.String("Test_DimensionName2")}}},
{MetricName: aws.String("Test_MetricName2"), Namespace: aws.String("AWS/EC2"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1")}}}, {MetricName: aws.String("Test_MetricName2"), Namespace: aws.String("AWS/EC2"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1")}}},
@@ -196,7 +187,7 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
{MetricName: aws.String("Test_MetricName8"), Namespace: aws.String("AWS/EC2"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName4")}}}, {MetricName: aws.String("Test_MetricName8"), Namespace: aws.String("AWS/EC2"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName4")}}},
{MetricName: aws.String("Test_MetricName9"), Namespace: aws.String("AWS/EC2"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1")}}}, {MetricName: aws.String("Test_MetricName9"), Namespace: aws.String("AWS/EC2"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1")}}},
}, MetricsPerPage: 2} }, MetricsPerPage: 2}
executor := newExecutor(im, &setting.Cfg{AWSListMetricsPageLimit: pageLimit}, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
req := &backend.CallResourceRequest{ req := &backend.CallResourceRequest{
Method: "GET", Method: "GET",
@@ -219,6 +210,7 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
}) })
t.Run("Should handle log group fields request", func(t *testing.T) { t.Run("Should handle log group fields request", func(t *testing.T) {
im := defaultTestInstanceManager()
logApi = mocks.LogsAPI{} logApi = mocks.LogsAPI{}
logApi.On("GetLogGroupFieldsWithContext", mock.Anything).Return(&cloudwatchlogs.GetLogGroupFieldsOutput{ logApi.On("GetLogGroupFieldsWithContext", mock.Anything).Return(&cloudwatchlogs.GetLogGroupFieldsOutput{
LogGroupFields: []*cloudwatchlogs.LogGroupField{ LogGroupFields: []*cloudwatchlogs.LogGroupField{
@@ -232,7 +224,7 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
}, },
}, },
}, nil) }, nil)
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
req := &backend.CallResourceRequest{ req := &backend.CallResourceRequest{
Method: "GET", Method: "GET",
@@ -253,7 +245,8 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
}) })
t.Run("Should handle region requests and return regions from the api", func(t *testing.T) { t.Run("Should handle region requests and return regions from the api", func(t *testing.T) {
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) im := defaultTestInstanceManager()
executor := newExecutor(im, &fakeSessionCache{})
req := &backend.CallResourceRequest{ req := &backend.CallResourceRequest{
Method: "GET", Method: "GET",
Path: `/regions`, Path: `/regions`,
@@ -275,10 +268,11 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
imWithoutDefaultRegion := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { imWithoutDefaultRegion := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{ return DataSource{Settings: models.CloudWatchSettings{
AWSDatasourceSettings: awsds.AWSDatasourceSettings{}, AWSDatasourceSettings: awsds.AWSDatasourceSettings{},
GrafanaSettings: awsds.AuthSettings{ListMetricsPageLimit: 1000},
}}, nil }}, nil
}) })
executor := newExecutor(imWithoutDefaultRegion, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(imWithoutDefaultRegion, &fakeSessionCache{})
req := &backend.CallResourceRequest{ req := &backend.CallResourceRequest{
Method: "GET", Method: "GET",
Path: `/regions`, Path: `/regions`,

View File

@@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"testing" "testing"
"time"
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
awsclient "github.com/aws/aws-sdk-go/aws/client" awsclient "github.com/aws/aws-sdk-go/aws/client"
@@ -16,6 +17,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource" "github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt" "github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
"github.com/grafana/grafana-plugin-sdk-go/backend/proxy"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/features" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/features"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
@@ -26,9 +28,11 @@ import (
) )
func TestNewInstanceSettings(t *testing.T) { func TestNewInstanceSettings(t *testing.T) {
ctxDuration := 10 * time.Minute
tests := []struct { tests := []struct {
name string name string
settings backend.DataSourceInstanceSettings settings backend.DataSourceInstanceSettings
settingCtx context.Context
expectedDS DataSource expectedDS DataSource
Err require.ErrorAssertionFunc Err require.ErrorAssertionFunc
}{ }{
@@ -49,6 +53,14 @@ func TestNewInstanceSettings(t *testing.T) {
"secretKey": "secret", "secretKey": "secret",
}, },
}, },
settingCtx: backend.WithGrafanaConfig(context.Background(), backend.NewGrafanaCfg(map[string]string{
awsds.AllowedAuthProvidersEnvVarKeyName: "foo , bar,baz",
awsds.AssumeRoleEnabledEnvVarKeyName: "false",
awsds.SessionDurationEnvVarKeyName: "10m",
awsds.GrafanaAssumeRoleExternalIdKeyName: "mock_id",
awsds.ListMetricsPageLimitKeyName: "50",
proxy.PluginSecureSocksProxyEnabled: "true",
})),
expectedDS: DataSource{ expectedDS: DataSource{
Settings: models.CloudWatchSettings{ Settings: models.CloudWatchSettings{
AWSDatasourceSettings: awsds.AWSDatasourceSettings{ AWSDatasourceSettings: awsds.AWSDatasourceSettings{
@@ -62,6 +74,14 @@ func TestNewInstanceSettings(t *testing.T) {
SecretKey: "secret", SecretKey: "secret",
}, },
Namespace: "ns", Namespace: "ns",
GrafanaSettings: awsds.AuthSettings{
AllowedAuthProviders: []string{"foo", "bar", "baz"},
AssumeRoleEnabled: false,
SessionDuration: &ctxDuration,
ExternalID: "mock_id",
ListMetricsPageLimit: 50,
SecureSocksDSProxyEnabled: true,
},
}, },
}, },
Err: require.NoError, Err: require.NoError,
@@ -71,8 +91,9 @@ func TestNewInstanceSettings(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
f := NewInstanceSettings(httpclient.NewProvider()) f := NewInstanceSettings(httpclient.NewProvider())
model, err := f(context.Background(), tt.settings) model, err := f(tt.settingCtx, tt.settings)
tt.Err(t, err) tt.Err(t, err)
assert.Equal(t, tt.expectedDS.Settings.GrafanaSettings, model.(DataSource).Settings.GrafanaSettings)
datasourceComparer := cmp.Comparer(func(d1 DataSource, d2 DataSource) bool { datasourceComparer := cmp.Comparer(func(d1 DataSource, d2 DataSource) bool {
return d1.Settings.Profile == d2.Settings.Profile && return d1.Settings.Profile == d2.Settings.Profile &&
d1.Settings.Region == d2.Settings.Region && d1.Settings.Region == d2.Settings.Region &&
@@ -109,17 +130,11 @@ func Test_CheckHealth(t *testing.T) {
NewLogsAPI = func(sess *session.Session) models.CloudWatchLogsAPIProvider { NewLogsAPI = func(sess *session.Session) models.CloudWatchLogsAPIProvider {
return client return client
} }
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := defaultTestInstanceManager()
return DataSource{Settings: models.CloudWatchSettings{
AWSDatasourceSettings: awsds.AWSDatasourceSettings{
Region: "us-east-1",
},
}}, nil
})
t.Run("successfully query metrics and logs", func(t *testing.T) { t.Run("successfully query metrics and logs", func(t *testing.T) {
client = fakeCheckHealthClient{} client = fakeCheckHealthClient{}
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
resp, err := executor.CheckHealth(context.Background(), &backend.CheckHealthRequest{ resp, err := executor.CheckHealth(context.Background(), &backend.CheckHealthRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@@ -138,7 +153,7 @@ func Test_CheckHealth(t *testing.T) {
return nil, fmt.Errorf("some logs query error") return nil, fmt.Errorf("some logs query error")
}} }}
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
resp, err := executor.CheckHealth(context.Background(), &backend.CheckHealthRequest{ resp, err := executor.CheckHealth(context.Background(), &backend.CheckHealthRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@@ -157,7 +172,7 @@ func Test_CheckHealth(t *testing.T) {
return fmt.Errorf("some list metrics error") return fmt.Errorf("some list metrics error")
}} }}
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
resp, err := executor.CheckHealth(context.Background(), &backend.CheckHealthRequest{ resp, err := executor.CheckHealth(context.Background(), &backend.CheckHealthRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@@ -173,7 +188,7 @@ func Test_CheckHealth(t *testing.T) {
t.Run("fail to get clients", func(t *testing.T) { t.Run("fail to get clients", func(t *testing.T) {
client = fakeCheckHealthClient{} client = fakeCheckHealthClient{}
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{getSession: func(c awsds.SessionConfig) (*session.Session, error) { executor := newExecutor(im, &fakeSessionCache{getSession: func(c awsds.SessionConfig) (*session.Session, error) {
return nil, fmt.Errorf("some sessions error") return nil, fmt.Errorf("some sessions error")
}}) }})
@@ -189,6 +204,37 @@ func Test_CheckHealth(t *testing.T) {
}) })
} }
func TestNewSession_passes_authSettings(t *testing.T) {
ctxDuration := 15 * time.Minute
expectedSettings := awsds.AuthSettings{
AllowedAuthProviders: []string{"foo", "bar", "baz"},
AssumeRoleEnabled: false,
SessionDuration: &ctxDuration,
ExternalID: "mock_id",
ListMetricsPageLimit: 50,
SecureSocksDSProxyEnabled: true,
}
im := datasource.NewInstanceManager((func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{
AWSDatasourceSettings: awsds.AWSDatasourceSettings{
Region: "us-east-1",
},
GrafanaSettings: expectedSettings,
}}, nil
}))
executor := newExecutor(im, &fakeSessionCache{getSession: func(c awsds.SessionConfig) (*session.Session, error) {
assert.NotNil(t, c.AuthSettings)
assert.Equal(t, expectedSettings, *c.AuthSettings)
return &session.Session{
Config: &aws.Config{},
}, nil
}})
_, err := executor.newSession(context.Background(),
backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, "us-east-1")
require.NoError(t, err)
}
func TestQuery_ResourceRequest_DescribeLogGroups_with_CrossAccountQuerying(t *testing.T) { func TestQuery_ResourceRequest_DescribeLogGroups_with_CrossAccountQuerying(t *testing.T) {
sender := &mockedCallResourceResponseSenderForOauth{} sender := &mockedCallResourceResponseSenderForOauth{}
origNewMetricsAPI := NewMetricsAPI origNewMetricsAPI := NewMetricsAPI
@@ -210,13 +256,7 @@ func TestQuery_ResourceRequest_DescribeLogGroups_with_CrossAccountQuerying(t *te
return &logsApi return &logsApi
} }
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := defaultTestInstanceManager()
return DataSource{Settings: models.CloudWatchSettings{
AWSDatasourceSettings: awsds.AWSDatasourceSettings{
Region: "us-east-1",
},
}}, nil
})
t.Run("maps log group api response to resource response of log-groups", func(t *testing.T) { t.Run("maps log group api response to resource response of log-groups", func(t *testing.T) {
logsApi = mocks.LogsAPI{} logsApi = mocks.LogsAPI{}
@@ -234,7 +274,7 @@ func TestQuery_ResourceRequest_DescribeLogGroups_with_CrossAccountQuerying(t *te
}, },
} }
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
err := executor.CallResource(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), req, sender) err := executor.CallResource(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), req, sender)
assert.NoError(t, err) assert.NoError(t, err)

View File

@@ -16,7 +16,12 @@ import (
// getDimensionValues gets the actual dimension values for dimensions with a wildcard // getDimensionValues gets the actual dimension values for dimensions with a wildcard
func (e *cloudWatchExecutor) getDimensionValuesForWildcards(ctx context.Context, pluginCtx backend.PluginContext, region string, func (e *cloudWatchExecutor) getDimensionValuesForWildcards(ctx context.Context, pluginCtx backend.PluginContext, region string,
client models.CloudWatchMetricsAPIProvider, origQueries []*models.CloudWatchQuery, tagValueCache *cache.Cache, logger log.Logger) ([]*models.CloudWatchQuery, error) { client models.CloudWatchMetricsAPIProvider, origQueries []*models.CloudWatchQuery, tagValueCache *cache.Cache, logger log.Logger) ([]*models.CloudWatchQuery, error) {
metricsClient := clients.NewMetricsClient(client, e.cfg) instance, err := e.getInstance(ctx, pluginCtx)
if err != nil {
return nil, err
}
metricsClient := clients.NewMetricsClient(client, instance.Settings.GrafanaSettings.ListMetricsPageLimit)
service := services.NewListMetricsService(metricsClient) service := services.NewListMetricsService(metricsClient)
// create copies of the original query. All the fields besides Dimensions are primitives // create copies of the original query. All the fields besides Dimensions are primitives
queries := copyQueries(origQueries) queries := copyQueries(origQueries)

View File

@@ -17,7 +17,7 @@ import (
func TestGetDimensionValuesForWildcards(t *testing.T) { func TestGetDimensionValuesForWildcards(t *testing.T) {
logger := &logtest.Fake{} logger := &logtest.Fake{}
executor := &cloudWatchExecutor{} executor := &cloudWatchExecutor{im: defaultTestInstanceManager()}
ctx := context.Background() ctx := context.Background()
pluginCtx := backend.PluginContext{ pluginCtx := backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{ID: 1, Updated: time.Now()}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{ID: 1, Updated: time.Now()},

View File

@@ -90,7 +90,7 @@ func TestQuery_handleGetLogEvents_passes_nil_start_and_end_times_to_GetLogEvents
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@@ -123,7 +123,7 @@ func TestQuery_GetLogEvents_returns_response_from_GetLogEvents_to_data_frame_fie
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
cli = &mocks.MockLogEvents{} cli = &mocks.MockLogEvents{}
cli.On("GetLogEventsWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatchlogs.GetLogEventsOutput{ cli.On("GetLogEventsWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatchlogs.GetLogEventsOutput{
@@ -208,7 +208,7 @@ func TestQuery_StartQuery(t *testing.T) {
}}, nil }}, nil
}) })
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@@ -265,7 +265,7 @@ func TestQuery_StartQuery(t *testing.T) {
}}, nil }}, nil
}) })
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
resp, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ resp, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@@ -322,7 +322,7 @@ func Test_executeStartQuery(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@@ -358,7 +358,7 @@ func Test_executeStartQuery(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@@ -384,7 +384,7 @@ func Test_executeStartQuery(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{ _, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@@ -420,7 +420,7 @@ func Test_executeStartQuery(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{ _, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@@ -456,7 +456,8 @@ func Test_executeStartQuery(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
Queries: []backend.DataQuery{ Queries: []backend.DataQuery{
@@ -491,7 +492,7 @@ func Test_executeStartQuery(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
Queries: []backend.DataQuery{ Queries: []backend.DataQuery{
@@ -525,7 +526,7 @@ func Test_executeStartQuery(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{ _, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
Queries: []backend.DataQuery{ Queries: []backend.DataQuery{
@@ -596,7 +597,7 @@ func TestQuery_StopQuery(t *testing.T) {
To: time.Unix(1584700643, 0), To: time.Unix(1584700643, 0),
} }
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
resp, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ resp, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@@ -686,7 +687,7 @@ func TestQuery_GetQueryResults(t *testing.T) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
resp, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ resp, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},

View File

@@ -40,7 +40,7 @@ func Test_executeSyncLogQuery(t *testing.T) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
sess := fakeSessionCache{} sess := fakeSessionCache{}
executor := newExecutor(im, newTestConfig(), &sess) executor := newExecutor(im, &sess)
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
Headers: map[string]string{headerFromAlert: "some value"}, Headers: map[string]string{headerFromAlert: "some value"},
@@ -67,7 +67,7 @@ func Test_executeSyncLogQuery(t *testing.T) {
}) })
sess := fakeSessionCache{} sess := fakeSessionCache{}
executor := newExecutor(im, newTestConfig(), &sess) executor := newExecutor(im, &sess)
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
Headers: map[string]string{headerFromAlert: "some value"}, Headers: map[string]string{headerFromAlert: "some value"},
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@@ -124,7 +124,7 @@ func Test_executeSyncLogQuery(t *testing.T) {
}) })
sess := fakeSessionCache{} sess := fakeSessionCache{}
executor := newExecutor(im, newTestConfig(), &sess) executor := newExecutor(im, &sess)
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
Headers: tc.headers, Headers: tc.headers,
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@@ -167,7 +167,7 @@ func Test_executeSyncLogQuery(t *testing.T) {
}) })
sess := fakeSessionCache{} sess := fakeSessionCache{}
executor := newExecutor(im, newTestConfig(), &sess) executor := newExecutor(im, &sess)
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
Queries: []backend.DataQuery{ Queries: []backend.DataQuery{
@@ -206,7 +206,7 @@ func Test_executeSyncLogQuery_handles_RefId_from_input_queries(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
res, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ res, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
Headers: map[string]string{headerFromAlert: "some value"}, Headers: map[string]string{headerFromAlert: "some value"},
@@ -235,7 +235,7 @@ func Test_executeSyncLogQuery_handles_RefId_from_input_queries(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
res, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ res, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
Headers: map[string]string{headerFromAlert: "some value"}, Headers: map[string]string{headerFromAlert: "some value"},
@@ -304,7 +304,7 @@ func Test_executeSyncLogQuery_handles_RefId_from_input_queries(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
res, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ res, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
Headers: map[string]string{headerFromAlert: "some value"}, Headers: map[string]string{headerFromAlert: "some value"},
@@ -349,8 +349,7 @@ func Test_executeSyncLogQuery_handles_RefId_from_input_queries(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{LogsTimeout: models.Duration{Duration: time.Millisecond}}}, nil return DataSource{Settings: models.CloudWatchSettings{LogsTimeout: models.Duration{Duration: time.Millisecond}}}, nil
}) })
executor := newExecutor(im, &fakeSessionCache{})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
Headers: map[string]string{headerFromAlert: "some value"}, Headers: map[string]string{headerFromAlert: "some value"},
@@ -382,7 +381,7 @@ func Test_executeSyncLogQuery_handles_RefId_from_input_queries(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
res, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ res, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
Headers: map[string]string{headerFromAlert: "some value"}, Headers: map[string]string{headerFromAlert: "some value"},

View File

@@ -26,7 +26,7 @@ func TestMetricDataInputBuilder(t *testing.T) {
for _, tc := range tests { for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{})
query := getBaseQuery() query := getBaseQuery()
query.TimezoneUTCOffset = tc.timezoneUTCOffset query.TimezoneUTCOffset = tc.timezoneUTCOffset

View File

@@ -12,7 +12,7 @@ import (
func TestMetricDataQueryBuilder(t *testing.T) { func TestMetricDataQueryBuilder(t *testing.T) {
t.Run("buildMetricDataQuery", func(t *testing.T) { t.Run("buildMetricDataQuery", func(t *testing.T) {
t.Run("should use metric stat", func(t *testing.T) { t.Run("should use metric stat", func(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{})
query := getBaseQuery() query := getBaseQuery()
query.MetricEditorMode = models.MetricEditorModeBuilder query.MetricEditorMode = models.MetricEditorModeBuilder
query.MetricQueryType = models.MetricQueryTypeSearch query.MetricQueryType = models.MetricQueryTypeSearch
@@ -24,7 +24,7 @@ func TestMetricDataQueryBuilder(t *testing.T) {
}) })
t.Run("should pass AccountId in metric stat query", func(t *testing.T) { t.Run("should pass AccountId in metric stat query", func(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{})
query := getBaseQuery() query := getBaseQuery()
query.MetricEditorMode = models.MetricEditorModeBuilder query.MetricEditorMode = models.MetricEditorModeBuilder
query.MetricQueryType = models.MetricQueryTypeSearch query.MetricQueryType = models.MetricQueryTypeSearch
@@ -35,7 +35,7 @@ func TestMetricDataQueryBuilder(t *testing.T) {
}) })
t.Run("should leave AccountId in metric stat query", func(t *testing.T) { t.Run("should leave AccountId in metric stat query", func(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{})
query := getBaseQuery() query := getBaseQuery()
query.MetricEditorMode = models.MetricEditorModeBuilder query.MetricEditorMode = models.MetricEditorModeBuilder
query.MetricQueryType = models.MetricQueryTypeSearch query.MetricQueryType = models.MetricQueryTypeSearch
@@ -45,7 +45,7 @@ func TestMetricDataQueryBuilder(t *testing.T) {
}) })
t.Run("should use custom built expression", func(t *testing.T) { t.Run("should use custom built expression", func(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{})
query := getBaseQuery() query := getBaseQuery()
query.MetricEditorMode = models.MetricEditorModeBuilder query.MetricEditorMode = models.MetricEditorModeBuilder
query.MetricQueryType = models.MetricQueryTypeSearch query.MetricQueryType = models.MetricQueryTypeSearch
@@ -57,7 +57,7 @@ func TestMetricDataQueryBuilder(t *testing.T) {
}) })
t.Run("should use sql expression", func(t *testing.T) { t.Run("should use sql expression", func(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{})
query := getBaseQuery() query := getBaseQuery()
query.MetricEditorMode = models.MetricEditorModeRaw query.MetricEditorMode = models.MetricEditorModeRaw
query.MetricQueryType = models.MetricQueryTypeQuery query.MetricQueryType = models.MetricQueryTypeQuery
@@ -69,7 +69,7 @@ func TestMetricDataQueryBuilder(t *testing.T) {
}) })
t.Run("should use user defined math expression", func(t *testing.T) { t.Run("should use user defined math expression", func(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{})
query := getBaseQuery() query := getBaseQuery()
query.MetricEditorMode = models.MetricEditorModeRaw query.MetricEditorMode = models.MetricEditorModeRaw
query.MetricQueryType = models.MetricQueryTypeSearch query.MetricQueryType = models.MetricQueryTypeSearch
@@ -81,7 +81,7 @@ func TestMetricDataQueryBuilder(t *testing.T) {
}) })
t.Run("should set period in user defined expression", func(t *testing.T) { t.Run("should set period in user defined expression", func(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{})
query := getBaseQuery() query := getBaseQuery()
query.MetricEditorMode = models.MetricEditorModeRaw query.MetricEditorMode = models.MetricEditorModeRaw
query.MetricQueryType = models.MetricQueryTypeSearch query.MetricQueryType = models.MetricQueryTypeSearch
@@ -95,7 +95,7 @@ func TestMetricDataQueryBuilder(t *testing.T) {
}) })
t.Run("should set label", func(t *testing.T) { t.Run("should set label", func(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{})
query := getBaseQuery() query := getBaseQuery()
query.Label = "some label" query.Label = "some label"
@@ -107,7 +107,7 @@ func TestMetricDataQueryBuilder(t *testing.T) {
}) })
t.Run("should not set label for empty string query label", func(t *testing.T) { t.Run("should not set label for empty string query label", func(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{})
query := getBaseQuery() query := getBaseQuery()
query.Label = "" query.Label = ""
@@ -118,7 +118,7 @@ func TestMetricDataQueryBuilder(t *testing.T) {
}) })
t.Run(`should not specify accountId when it is "all"`, func(t *testing.T) { t.Run(`should not specify accountId when it is "all"`, func(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{})
query := &models.CloudWatchQuery{ query := &models.CloudWatchQuery{
Namespace: "AWS/EC2", Namespace: "AWS/EC2",
MetricName: "CPUUtilization", MetricName: "CPUUtilization",
@@ -136,7 +136,7 @@ func TestMetricDataQueryBuilder(t *testing.T) {
}) })
t.Run("should set accountId when it is specified", func(t *testing.T) { t.Run("should set accountId when it is specified", func(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{})
query := &models.CloudWatchQuery{ query := &models.CloudWatchQuery{
Namespace: "AWS/EC2", Namespace: "AWS/EC2",
MetricName: "CPUUtilization", MetricName: "CPUUtilization",

View File

@@ -47,10 +47,13 @@ func TestQuery_Regions(t *testing.T) {
}, nil) }, nil)
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{AWSDatasourceSettings: awsds.AWSDatasourceSettings{Region: "us-east-2"}}}, nil return DataSource{Settings: models.CloudWatchSettings{
AWSDatasourceSettings: awsds.AWSDatasourceSettings{Region: "us-east-2"},
GrafanaSettings: awsds.AuthSettings{ListMetricsPageLimit: 1000},
}}, nil
}) })
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
resp, err := executor.handleGetRegions( resp, err := executor.handleGetRegions(
context.Background(), context.Background(),
backend.PluginContext{ backend.PluginContext{
@@ -104,12 +107,15 @@ func Test_handleGetRegions_regionCache(t *testing.T) {
return &cli return &cli
} }
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{AWSDatasourceSettings: awsds.AWSDatasourceSettings{Region: "us-east-2"}}}, nil return DataSource{Settings: models.CloudWatchSettings{
AWSDatasourceSettings: awsds.AWSDatasourceSettings{Region: "us-east-2"},
GrafanaSettings: awsds.AuthSettings{ListMetricsPageLimit: 1000},
}}, nil
}) })
t.Run("AWS only called once for multiple calls to handleGetRegions", func(t *testing.T) { t.Run("AWS only called once for multiple calls to handleGetRegions", func(t *testing.T) {
cli.On("DescribeRegionsWithContext", mock.Anything, mock.Anything).Return(&ec2.DescribeRegionsOutput{}, nil) cli.On("DescribeRegionsWithContext", mock.Anything, mock.Anything).Return(&ec2.DescribeRegionsOutput{}, nil)
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.handleGetRegions( _, err := executor.handleGetRegions(
context.Background(), context.Background(),
backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, nil) backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, nil)
@@ -165,7 +171,7 @@ func TestQuery_InstanceAttributes(t *testing.T) {
filterJson, err := json.Marshal(filterMap) filterJson, err := json.Marshal(filterMap)
require.NoError(t, err) require.NoError(t, err)
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
resp, err := executor.handleGetEc2InstanceAttribute( resp, err := executor.handleGetEc2InstanceAttribute(
context.Background(), context.Background(),
backend.PluginContext{ backend.PluginContext{
@@ -243,7 +249,7 @@ func TestQuery_EBSVolumeIDs(t *testing.T) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
resp, err := executor.handleGetEbsVolumeIds( resp, err := executor.handleGetEbsVolumeIds(
context.Background(), context.Background(),
backend.PluginContext{ backend.PluginContext{
@@ -310,7 +316,7 @@ func TestQuery_ResourceARNs(t *testing.T) {
tagJson, err := json.Marshal(tagMap) tagJson, err := json.Marshal(tagMap)
require.NoError(t, err) require.NoError(t, err)
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
resp, err := executor.handleGetResourceArns( resp, err := executor.handleGetResourceArns(
context.Background(), context.Background(),
backend.PluginContext{ backend.PluginContext{

View File

@@ -1,6 +1,7 @@
package models package models
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"time" "time"
@@ -17,9 +18,12 @@ type CloudWatchSettings struct {
Namespace string `json:"customMetricsNamespaces"` Namespace string `json:"customMetricsNamespaces"`
SecureSocksProxyEnabled bool `json:"enableSecureSocksProxy"` // this can be removed when https://github.com/grafana/grafana/issues/39089 is implemented SecureSocksProxyEnabled bool `json:"enableSecureSocksProxy"` // this can be removed when https://github.com/grafana/grafana/issues/39089 is implemented
LogsTimeout Duration `json:"logsTimeout"` LogsTimeout Duration `json:"logsTimeout"`
// GrafanaSettings are fetched from the GrafanaCfg in the context
GrafanaSettings awsds.AuthSettings `json:"-"`
} }
func LoadCloudWatchSettings(config backend.DataSourceInstanceSettings) (CloudWatchSettings, error) { func LoadCloudWatchSettings(ctx context.Context, config backend.DataSourceInstanceSettings) (CloudWatchSettings, error) {
instance := CloudWatchSettings{} instance := CloudWatchSettings{}
if config.JSONData != nil && len(config.JSONData) > 1 { if config.JSONData != nil && len(config.JSONData) > 1 {
if err := json.Unmarshal(config.JSONData, &instance); err != nil { if err := json.Unmarshal(config.JSONData, &instance); err != nil {
@@ -43,6 +47,7 @@ func LoadCloudWatchSettings(config backend.DataSourceInstanceSettings) (CloudWat
instance.AccessKey = config.DecryptedSecureJSONData["accessKey"] instance.AccessKey = config.DecryptedSecureJSONData["accessKey"]
instance.SecretKey = config.DecryptedSecureJSONData["secretKey"] instance.SecretKey = config.DecryptedSecureJSONData["secretKey"]
instance.GrafanaSettings = *awsds.ReadAuthSettings(ctx)
return instance, nil return instance, nil
} }

View File

@@ -1,16 +1,23 @@
package models package models
import ( import (
"context"
"testing" "testing"
"time" "time"
"github.com/grafana/grafana-aws-sdk/pkg/awsds" "github.com/grafana/grafana-aws-sdk/pkg/awsds"
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/proxy"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func Test_Settings_LoadCloudWatchSettings(t *testing.T) { func Test_Settings_LoadCloudWatchSettings(t *testing.T) {
settingCtx := backend.WithGrafanaConfig(context.Background(), backend.NewGrafanaCfg(map[string]string{
awsds.AllowedAuthProvidersEnvVarKeyName: "default,keys,credentials",
awsds.AssumeRoleEnabledEnvVarKeyName: "false",
awsds.SessionDurationEnvVarKeyName: "10m",
}))
t.Run("Should return error for invalid json", func(t *testing.T) { t.Run("Should return error for invalid json", func(t *testing.T) {
settings := backend.DataSourceInstanceSettings{ settings := backend.DataSourceInstanceSettings{
ID: 33, ID: 33,
@@ -25,7 +32,7 @@ func Test_Settings_LoadCloudWatchSettings(t *testing.T) {
}, },
} }
_, err := LoadCloudWatchSettings(settings) _, err := LoadCloudWatchSettings(settingCtx, settings)
assert.Error(t, err) assert.Error(t, err)
}) })
@@ -47,7 +54,7 @@ func Test_Settings_LoadCloudWatchSettings(t *testing.T) {
}, },
} }
s, err := LoadCloudWatchSettings(settings) s, err := LoadCloudWatchSettings(settingCtx, settings)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, awsds.AuthTypeKeys, s.AuthType) assert.Equal(t, awsds.AuthTypeKeys, s.AuthType)
assert.Equal(t, "arn:aws:iam::123456789012:role/grafana", s.AssumeRoleARN) assert.Equal(t, "arn:aws:iam::123456789012:role/grafana", s.AssumeRoleARN)
@@ -78,7 +85,7 @@ func Test_Settings_LoadCloudWatchSettings(t *testing.T) {
}, },
} }
s, err := LoadCloudWatchSettings(settings) s, err := LoadCloudWatchSettings(settingCtx, settings)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, awsds.AuthTypeDefault, s.AuthType) assert.Equal(t, awsds.AuthTypeDefault, s.AuthType)
assert.Equal(t, "arn:aws:iam::123456789012:role/grafana", s.AssumeRoleARN) assert.Equal(t, "arn:aws:iam::123456789012:role/grafana", s.AssumeRoleARN)
@@ -103,7 +110,7 @@ func Test_Settings_LoadCloudWatchSettings(t *testing.T) {
}, },
} }
s, err := LoadCloudWatchSettings(settings) s, err := LoadCloudWatchSettings(settingCtx, settings)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, time.Minute*30, s.LogsTimeout.Duration) assert.Equal(t, time.Minute*30, s.LogsTimeout.Duration)
}) })
@@ -121,7 +128,7 @@ func Test_Settings_LoadCloudWatchSettings(t *testing.T) {
}, },
} }
s, err := LoadCloudWatchSettings(settings) s, err := LoadCloudWatchSettings(settingCtx, settings)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, time.Minute*10, s.LogsTimeout.Duration) assert.Equal(t, time.Minute*10, s.LogsTimeout.Duration)
}) })
@@ -139,7 +146,7 @@ func Test_Settings_LoadCloudWatchSettings(t *testing.T) {
}, },
} }
s, err := LoadCloudWatchSettings(settings) s, err := LoadCloudWatchSettings(settingCtx, settings)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, time.Duration(1500000000), s.LogsTimeout.Duration) assert.Equal(t, time.Duration(1500000000), s.LogsTimeout.Duration)
}) })
@@ -157,7 +164,7 @@ func Test_Settings_LoadCloudWatchSettings(t *testing.T) {
}, },
} }
s, err := LoadCloudWatchSettings(settings) s, err := LoadCloudWatchSettings(settingCtx, settings)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, 1500*time.Millisecond, s.LogsTimeout.Duration) assert.Equal(t, 1500*time.Millisecond, s.LogsTimeout.Duration)
}) })
@@ -175,7 +182,7 @@ func Test_Settings_LoadCloudWatchSettings(t *testing.T) {
}, },
} }
_, err := LoadCloudWatchSettings(settings) _, err := LoadCloudWatchSettings(context.Background(), settings)
require.Error(t, err) require.Error(t, err)
}) })
t.Run("Should throw error if logsTimeout is an invalid type", func(t *testing.T) { t.Run("Should throw error if logsTimeout is an invalid type", func(t *testing.T) {
@@ -192,7 +199,42 @@ func Test_Settings_LoadCloudWatchSettings(t *testing.T) {
}, },
} }
_, err := LoadCloudWatchSettings(settings) _, err := LoadCloudWatchSettings(settingCtx, settings)
require.Error(t, err) require.Error(t, err)
}) })
t.Run("Should load settings from context", func(t *testing.T) {
settingCtx := backend.WithGrafanaConfig(context.Background(), backend.NewGrafanaCfg(map[string]string{
awsds.AllowedAuthProvidersEnvVarKeyName: "foo , bar,baz",
awsds.AssumeRoleEnabledEnvVarKeyName: "false",
awsds.SessionDurationEnvVarKeyName: "10m",
awsds.GrafanaAssumeRoleExternalIdKeyName: "mock_id",
awsds.ListMetricsPageLimitKeyName: "50",
proxy.PluginSecureSocksProxyEnabled: "true",
}))
settings := backend.DataSourceInstanceSettings{
ID: 33,
JSONData: []byte(`{
"authType": "arn",
"assumeRoleArn": "arn:aws:iam::123456789012:role/grafana"
}`),
DecryptedSecureJSONData: map[string]string{
"accessKey": "AKIAIOSFODNN7EXAMPLE",
"secretKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
},
}
s, err := LoadCloudWatchSettings(settingCtx, settings)
require.NoError(t, err)
ctxDuration := 10 * time.Minute
expectedGrafanaSettings := awsds.AuthSettings{
AllowedAuthProviders: []string{"foo", "bar", "baz"},
AssumeRoleEnabled: false,
SessionDuration: &ctxDuration,
ExternalID: "mock_id",
ListMetricsPageLimit: 50,
SecureSocksDSProxyEnabled: true,
}
assert.Equal(t, expectedGrafanaSettings, s.GrafanaSettings)
})
} }

View File

@@ -17,8 +17,10 @@ import (
"github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi/resourcegroupstaggingapiiface" "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi/resourcegroupstaggingapiiface"
"github.com/grafana/grafana-aws-sdk/pkg/awsds" "github.com/grafana/grafana-aws-sdk/pkg/awsds"
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
"github.com/grafana/grafana-plugin-sdk-go/experimental/featuretoggles" "github.com/grafana/grafana-plugin-sdk-go/experimental/featuretoggles"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
"github.com/stretchr/testify/mock" "github.com/stretchr/testify/mock"
) )
@@ -214,8 +216,19 @@ func (c fakeCheckHealthClient) GetLogGroupFieldsWithContext(ctx context.Context,
return nil, nil return nil, nil
} }
func newTestConfig() *setting.Cfg { func testInstanceManager(pageLimit int) instancemgmt.InstanceManager {
return &setting.Cfg{AWSAllowedAuthProviders: []string{"default"}, AWSAssumeRoleEnabled: true, AWSListMetricsPageLimit: 1000} return datasource.NewInstanceManager((func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{
AWSDatasourceSettings: awsds.AWSDatasourceSettings{
Region: "us-east-1",
},
GrafanaSettings: awsds.AuthSettings{ListMetricsPageLimit: pageLimit},
}}, nil
}))
}
func defaultTestInstanceManager() instancemgmt.InstanceManager {
return testInstanceManager(1000)
} }
type mockSessionCache struct { type mockSessionCache struct {

View File

@@ -26,7 +26,7 @@ import (
) )
func TestTimeSeriesQuery(t *testing.T) { func TestTimeSeriesQuery(t *testing.T) {
executor := newExecutor(nil, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{})
now := time.Now() now := time.Now()
origNewCWClient := NewCWClient origNewCWClient := NewCWClient
@@ -50,11 +50,9 @@ func TestTimeSeriesQuery(t *testing.T) {
StatusCode: aws.String("Complete"), Id: aws.String("b"), Label: aws.String("NetworkIn"), Values: []*float64{aws.Float64(1.0)}, Timestamps: []*time.Time{&now}, StatusCode: aws.String("Complete"), Id: aws.String("b"), Label: aws.String("NetworkIn"), Values: []*float64{aws.Float64(1.0)}, Timestamps: []*time.Time{&now},
}}}, nil) }}}, nil)
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := defaultTestInstanceManager()
return DataSource{Settings: models.CloudWatchSettings{}}, nil
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
resp, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ resp, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@@ -160,7 +158,7 @@ func Test_executeTimeSeriesQuery_getCWClient_is_called_once_per_region_and_GetMe
mockMetricClient = mocks.MetricsAPI{} mockMetricClient = mocks.MetricsAPI{}
mockMetricClient.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(nil, nil) mockMetricClient.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(nil, nil)
executor := newExecutor(im, newTestConfig(), mockSessionCache) executor := newExecutor(im, mockSessionCache)
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@@ -211,7 +209,7 @@ func Test_executeTimeSeriesQuery_getCWClient_is_called_once_per_region_and_GetMe
mockMetricClient = mocks.MetricsAPI{} mockMetricClient = mocks.MetricsAPI{}
mockMetricClient.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(nil, nil) mockMetricClient.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(nil, nil)
executor := newExecutor(im, newTestConfig(), sessionCache) executor := newExecutor(im, sessionCache)
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@@ -344,7 +342,7 @@ func Test_QueryData_timeSeriesQuery_GetMetricDataWithContext(t *testing.T) {
t.Run("passes query label as GetMetricData label", func(t *testing.T) { t.Run("passes query label as GetMetricData label", func(t *testing.T) {
api = mocks.MetricsAPI{} api = mocks.MetricsAPI{}
api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil) api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil)
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
query := newTestQuery(t, queryParameters{ query := newTestQuery(t, queryParameters{
Label: aws.String("${PROP('Period')} some words ${PROP('Dim.InstanceId')}"), Label: aws.String("${PROP('Period')} some words ${PROP('Dim.InstanceId')}"),
}) })
@@ -383,7 +381,7 @@ func Test_QueryData_timeSeriesQuery_GetMetricDataWithContext(t *testing.T) {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
api = mocks.MetricsAPI{} api = mocks.MetricsAPI{}
api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil) api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil)
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@@ -433,10 +431,8 @@ func Test_QueryData_response_data_frame_name_is_always_response_label(t *testing
Values: []*float64{aws.Float64(1.0)}, Timestamps: []*time.Time{{}}}, Values: []*float64{aws.Float64(1.0)}, Timestamps: []*time.Time{{}}},
}}, nil) }}, nil)
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := defaultTestInstanceManager()
return DataSource{Settings: models.CloudWatchSettings{}}, nil executor := newExecutor(im, &fakeSessionCache{})
})
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{})
t.Run("where user defines search expression", func(t *testing.T) { t.Run("where user defines search expression", func(t *testing.T) {
query := newTestQuery(t, queryParameters{ query := newTestQuery(t, queryParameters{
@@ -588,14 +584,12 @@ func TestTimeSeriesQuery_CrossAccountQuerying(t *testing.T) {
NewCWClient = func(sess *session.Session) cloudwatchiface.CloudWatchAPI { NewCWClient = func(sess *session.Session) cloudwatchiface.CloudWatchAPI {
return &api return &api
} }
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := defaultTestInstanceManager()
return DataSource{Settings: models.CloudWatchSettings{}}, nil
})
t.Run("should call GetMetricDataInput with AccountId nil when no AccountId is provided", func(t *testing.T) { t.Run("should call GetMetricDataInput with AccountId nil when no AccountId is provided", func(t *testing.T) {
api = mocks.MetricsAPI{} api = mocks.MetricsAPI{}
api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil) api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil)
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{ _, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
@@ -636,7 +630,7 @@ func TestTimeSeriesQuery_CrossAccountQuerying(t *testing.T) {
t.Run("should call GetMetricDataInput with AccountId nil when feature flag is false", func(t *testing.T) { t.Run("should call GetMetricDataInput with AccountId nil when feature flag is false", func(t *testing.T) {
api = mocks.MetricsAPI{} api = mocks.MetricsAPI{}
api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil) api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil)
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@@ -677,7 +671,7 @@ func TestTimeSeriesQuery_CrossAccountQuerying(t *testing.T) {
t.Run("should call GetMetricDataInput with AccountId in a MetricStat query", func(t *testing.T) { t.Run("should call GetMetricDataInput with AccountId in a MetricStat query", func(t *testing.T) {
api = mocks.MetricsAPI{} api = mocks.MetricsAPI{}
api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil) api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil)
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{ _, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@@ -718,7 +712,7 @@ func TestTimeSeriesQuery_CrossAccountQuerying(t *testing.T) {
t.Run("should GetMetricDataInput with AccountId in an inferred search expression query", func(t *testing.T) { t.Run("should GetMetricDataInput with AccountId in an inferred search expression query", func(t *testing.T) {
api = mocks.MetricsAPI{} api = mocks.MetricsAPI{}
api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil) api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil)
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{})
_, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{ _, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},