diff --git a/docs/index.md b/docs/index.md index e8c0acbd7..504130513 100644 --- a/docs/index.md +++ b/docs/index.md @@ -355,6 +355,22 @@ resource "grafana_cloud_provider_aws_cloudwatch_scrape_job" "test" { ### Managing Connections +#### Obtaining Connections access token + +Before using the Terraform Provider to manage Grafana Connections resources, such as metrics endpoint scrape jobs, you need to create an access policy token on the Grafana Cloud Portal. This token is used to authenticate the provider to the Grafana Connections API. +[These docs](https://grafana.com/docs/grafana-cloud/account-management/authentication-and-permissions/access-policies/authorize-services/#create-an-access-policy-for-a-stack) will guide you on how to create +an access policy. The required permissions, or scopes, are `integration-management:read`, `integration-management:write` and `stacks:read`. + +Also, by default the Access Policies UI will not show those scopes, instead, search for it using the `Add Scope` textbox, as shown in the following image: + + + +1. Use the `Add Scope` textbox to search for the permissions you need to add to the access policy: `integration-management:read`, `integration-management:write` and `stacks:read`. +1. Once done, you should see the scopes selected with checkboxes. + +Having created an Access Policy, you can now create a token that will be used to authenticate the provider to the Connections API. You can do so just after creating the access policy, following +the in-screen instructions, of following [this guide](https://grafana.com/docs/grafana-cloud/account-management/authentication-and-permissions/access-policies/authorize-services/#create-one-or-more-access-policy-tokens). + #### Obtaining Connections API hostname Having created the token, we can find the correct Connections API hostname by running the following script, that requires `curl` and [`jq`](https://jqlang.github.io/jq/) installed: @@ -377,22 +393,6 @@ For example, in the following response, the correct hostname for the `examplesta ] ``` -#### Obtaining Connections access token - -Before using the Terraform Provider to manage Grafana Connections resources, such as metrics endpoint scrape jobs, you need to create an access policy token on the Grafana Cloud Portal. This token is used to authenticate the provider to the Grafana Connections API. -[These docs](https://grafana.com/docs/grafana-cloud/account-management/authentication-and-permissions/access-policies/authorize-services/#create-an-access-policy-for-a-stack) will guide you on how to create -an access policy. The required permissions, or scopes, are `integration-management:read`, `integration-management:write` and `stacks:read`. - -Also, by default the Access Policies UI will not show those scopes, instead, search for it using the `Add Scope` textbox, as shown in the following image: - - - -1. Use the `Add Scope` textbox (1) to search for the permissions you need to add to the access policy. -1. Make sure that you configure the three required scopes. Once done, you'll see the selected scopes as in (2). - -Having created an Access Policy, you can now create a token that will be used to authenticate the provider to the Connections API. You can do so just after creating the access policy, following -the in-screen instructions, of following [this guide](https://grafana.com/docs/grafana-cloud/account-management/authentication-and-permissions/access-policies/authorize-services/#create-one-or-more-access-policy-tokens). - #### Configuring the Provider to use the Connections API Once you have the token and Connections API hostname, you can configure the provider as follows: @@ -436,4 +436,4 @@ To create one, follow the instructions in the [obtaining cloud provider access t An access policy token created on the [Grafana Cloud Portal](https://grafana.com/docs/grafana-cloud/account-management/authentication-and-permissions/access-policies/authorize-services/) to manage connections resources, such as Metrics Endpoint jobs. -For guidance on creating one, see section [obtaining connections access token](#obtaining-connections-access-token) +For guidance on creating one, see section [obtaining connections access token](#obtaining-connections-access-token). diff --git a/docs/resources/machine_learning_job.md b/docs/resources/machine_learning_job.md index b9ad6c5f8..006970e4f 100644 --- a/docs/resources/machine_learning_job.md +++ b/docs/resources/machine_learning_job.md @@ -4,12 +4,17 @@ page_title: "grafana_machine_learning_job Resource - terraform-provider-grafana" subcategory: "Machine Learning" description: |- A job defines the queries and model parameters for a machine learning task. + See the Grafana Cloud docs https://grafana.com/docs/grafana-cloud/alerting-and-irm/machine-learning/forecasts/models/ for more information + on available hyperparameters for use in the hyper_params field. --- # grafana_machine_learning_job (Resource) A job defines the queries and model parameters for a machine learning task. +See [the Grafana Cloud docs](https://grafana.com/docs/grafana-cloud/alerting-and-irm/machine-learning/forecasts/models/) for more information +on available hyperparameters for use in the `hyper_params` field. + ## Example Usage ### Basic Forecast diff --git a/docs/resources/rule_group.md b/docs/resources/rule_group.md index e48bc8b97..7a5454a1c 100644 --- a/docs/resources/rule_group.md +++ b/docs/resources/rule_group.md @@ -144,7 +144,8 @@ Optional: - `is_paused` (Boolean) Sets whether the alert should be paused or not. Defaults to `false`. - `labels` (Map of String) Key-value pairs to attach to the alert rule that can be used in matching, grouping, and routing. Defaults to `map[]`. - `no_data_state` (String) Describes what state to enter when the rule's query returns No Data. Options are OK, NoData, KeepLast, and Alerting. Defaults to `NoData`. -- `notification_settings` (Block List, Max: 1) Notification settings for the rule. If specified, it overrides the notification policies. Available since Grafana 10.4, requires feature flag 'alertingSimplifiedRouting' enabled. (see [below for nested schema](#nestedblock--rule--notification_settings)) +- `notification_settings` (Block List, Max: 1) Notification settings for the rule. If specified, it overrides the notification policies. Available since Grafana 10.4, requires feature flag 'alertingSimplifiedRouting' to be enabled. (see [below for nested schema](#nestedblock--rule--notification_settings)) +- `record` (Block List, Max: 1) Settings for a recording rule. Available since Grafana 11.2, requires feature flag 'grafanaManagedRecordingRules' to be enabled. (see [below for nested schema](#nestedblock--rule--record)) Read-Only: @@ -189,6 +190,15 @@ Optional: - `mute_timings` (List of String) A list of mute timing names to apply to alerts that match this policy. - `repeat_interval` (String) Minimum time interval for re-sending a notification if an alert is still firing. Default is 4 hours. + + +### Nested Schema for `rule.record` + +Required: + +- `from` (String) The ref id of the query node in the data field to use as the source of the metric. +- `metric` (String) The name of the metric to write to. + ## Import Import is supported using the following syntax: diff --git a/go.mod b/go.mod index 944cdef25..eb838560f 100644 --- a/go.mod +++ b/go.mod @@ -11,10 +11,10 @@ require ( github.com/go-openapi/strfmt v0.23.0 github.com/grafana/amixr-api-go-client v0.0.16 // main branch github.com/grafana/grafana-com-public-clients/go/gcom v0.0.0-20240807172819-ac10800522a3 - github.com/grafana/grafana-openapi-client-go v0.0.0-20240723170622-ae2c94b7c9a3 + github.com/grafana/grafana-openapi-client-go v0.0.0-20241113095943-9cb2bbfeb8a3 github.com/grafana/machine-learning-go-client v0.8.2 github.com/grafana/slo-openapi-client/go/slo v0.0.0-20240807172758-1b7d00838fc7 - github.com/grafana/synthetic-monitoring-agent v0.29.3 + github.com/grafana/synthetic-monitoring-agent v0.29.5 github.com/grafana/synthetic-monitoring-api-go-client v0.8.0 github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 github.com/hashicorp/go-retryablehttp v0.7.7 @@ -35,8 +35,8 @@ require ( github.com/tmccombs/hcl2json v0.6.4 github.com/urfave/cli/v2 v2.27.5 github.com/zclconf/go-cty v1.15.0 - golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6 - golang.org/x/text v0.19.0 + golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c + golang.org/x/text v0.20.0 gopkg.in/yaml.v2 v2.4.0 ) @@ -160,18 +160,18 @@ require ( go.opentelemetry.io/otel/sdk v1.29.0 // indirect go.opentelemetry.io/otel/trace v1.29.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect - golang.org/x/crypto v0.28.0 // indirect + golang.org/x/crypto v0.29.0 // indirect golang.org/x/mod v0.21.0 // indirect - golang.org/x/net v0.30.0 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.26.0 // indirect + golang.org/x/net v0.31.0 // indirect + golang.org/x/sync v0.9.0 // indirect + golang.org/x/sys v0.27.0 // indirect golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect golang.org/x/tools v0.26.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect - google.golang.org/grpc v1.67.1 // indirect + google.golang.org/grpc v1.68.0 // indirect google.golang.org/protobuf v1.35.1 // indirect gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect gopkg.in/validator.v2 v2.0.1 // indirect diff --git a/go.sum b/go.sum index 5d93b532e..6d336db1d 100644 --- a/go.sum +++ b/go.sum @@ -140,6 +140,8 @@ github.com/grafana/amixr-api-go-client v0.0.16 h1:CXdqnLKjvo6QoNPBKxmZ2kGKCcUoAl github.com/grafana/amixr-api-go-client v0.0.16/go.mod h1:N6x26XUrM5zGtK5zL5vNJnAn2JFMxLFPPLTw/6pDkFE= github.com/grafana/grafana-com-public-clients/go/gcom v0.0.0-20240807172819-ac10800522a3 h1:CVLTffnWgBGvVaXfUUcSgFrZbiMzvj0/Hpi909zdeG0= github.com/grafana/grafana-com-public-clients/go/gcom v0.0.0-20240807172819-ac10800522a3/go.mod h1:u9d0BESoKlztYm93CpoRleQjMbYBcZ+JOLHHP2nN6Wg= +github.com/grafana/grafana-openapi-client-go v0.0.0-20241113095943-9cb2bbfeb8a3 h1:poKxGlUaEYVp2DMofC/I2GHw/vvtHAZ20c48I8rFB6M= +github.com/grafana/grafana-openapi-client-go v0.0.0-20241113095943-9cb2bbfeb8a3/go.mod h1:hiZnMmXc9KXNUlvkV2BKFsiWuIFF/fF4wGgYWEjBitI= github.com/grafana/grafana-plugin-sdk-go v0.250.0 h1:9EBucp9jLqMx2b8NTlOXH+4OuQWUh6L85c6EJUN8Jdo= github.com/grafana/grafana-plugin-sdk-go v0.250.0/go.mod h1:gCGN9kHY3KeX4qyni3+Kead38Q+85pYOrsDcxZp6AIk= github.com/grafana/machine-learning-go-client v0.8.2 h1:TvU4e+Kgg4GhwBNYTMjBUNq4tbhcxe0L8w1eo/UfV2M= @@ -150,8 +152,8 @@ github.com/grafana/pyroscope-go/godeltaprof v0.1.8 h1:iwOtYXeeVSAeYefJNaxDytgjKt github.com/grafana/pyroscope-go/godeltaprof v0.1.8/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU= github.com/grafana/slo-openapi-client/go/slo v0.0.0-20240807172758-1b7d00838fc7 h1:t7zAFX0rMu868n85zRHLgmAjLJgWbkxUekGquZmovjA= github.com/grafana/slo-openapi-client/go/slo v0.0.0-20240807172758-1b7d00838fc7/go.mod h1:MVsmQi3lkhNnRExmke6Ug6HFG4Dycd+oRgzC3Rz+vOs= -github.com/grafana/synthetic-monitoring-agent v0.29.3 h1:0ntBIZ2IIEMwmvVBDL8iGMsIlIoqsglGCHUHqMw3aMw= -github.com/grafana/synthetic-monitoring-agent v0.29.3/go.mod h1:DN0cvbYzC8VucI8XRvCMPcsRa5IeDTmQhTUhLjHyWbA= +github.com/grafana/synthetic-monitoring-agent v0.29.5 h1:rg/N2/iJGTwg7oXRHfBYFg6e2Vfs/C0/mwO7zLzRL08= +github.com/grafana/synthetic-monitoring-agent v0.29.5/go.mod h1:XuYl/hkih7ML4daqEBL2Vy07ne4KE2sss5UUvyIIqbg= github.com/grafana/synthetic-monitoring-api-go-client v0.8.0 h1:Tm4MtwwYmPNInGfnj66l6j6KOshMkNV4emIVKJdlXMg= github.com/grafana/synthetic-monitoring-api-go-client v0.8.0/go.mod h1:TGaywTdL2Z+PJhpWzJEmJFRF5K55vKz2f39mWY/GvV8= github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA= @@ -433,10 +435,10 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= -golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6 h1:1wqE9dj9NpSm04INVsJhhEUzhuDVjbcyKH91sVyPATw= -golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= +golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY= +golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -449,15 +451,15 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= -golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191020152052-9984515f0562/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -476,21 +478,21 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= -golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= +golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= +golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= -golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -511,12 +513,12 @@ gonum.org/v1/gonum v0.12.0/go.mod h1:73TDxJfAAHeA8Mk9mf8NlIppyhQNo5GLTcYeqgo2lvY google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= -google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd h1:BBOTEWLuuEGQy9n1y9MhVJ9Qt0BDu21X8qZs71/uPZo= -google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:fO8wJzT2zbQbAjbIoos1285VfEIYKDDY+Dt+WpTkh6g= +google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc= +google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= -google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= +google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0= +google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= diff --git a/internal/resources/grafana/common_check_exists_test.go b/internal/resources/grafana/common_check_exists_test.go index df1e48316..f4066c1b7 100644 --- a/internal/resources/grafana/common_check_exists_test.go +++ b/internal/resources/grafana/common_check_exists_test.go @@ -2,6 +2,7 @@ package grafana_test import ( "fmt" + "net/http" "os" "strconv" "strings" @@ -41,7 +42,7 @@ var ( alertingMessageTemplateCheckExists = newCheckExistsHelper( func(t *models.NotificationTemplate) string { return t.Name }, func(client *goapi.GrafanaHTTPAPI, id string) (*models.NotificationTemplate, error) { - resp, err := client.Provisioning.GetTemplate(id) + resp, err := client.Provisioning.GetTemplate(id, grafana.ContentTypeNegotiator(http.DefaultTransport)) return payloadOrError(resp, err) }, ) diff --git a/internal/resources/grafana/content_type_round_tripper.go b/internal/resources/grafana/content_type_round_tripper.go new file mode 100644 index 000000000..68a1d3ba5 --- /dev/null +++ b/internal/resources/grafana/content_type_round_tripper.go @@ -0,0 +1,36 @@ +package grafana + +import ( + "net/http" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/runtime/middleware" +) + +func ContentTypeNegotiator(tripper http.RoundTripper) func(operation *runtime.ClientOperation) { + return func(operation *runtime.ClientOperation) { + operation.Client = &http.Client{Transport: newContentTypeRoundTripperTest(tripper)} + } +} + +// contentTypeRoundTripperTest identifies unexpected "text/pain" responses when "application/json" is expected. +// It could happen when something fails related to an "implementation bug". +type contentTypeRoundTripperTest struct { + originalRoundTripper http.RoundTripper +} + +func newContentTypeRoundTripperTest(originalRoundTripper http.RoundTripper) http.RoundTripper { + return &contentTypeRoundTripperTest{originalRoundTripper: originalRoundTripper} +} + +func (r *contentTypeRoundTripperTest) RoundTrip(req *http.Request) (*http.Response, error) { + resp, err := r.originalRoundTripper.RoundTrip(req) + if err != nil { + return nil, err + } + + mid := middleware.NegotiateContentType(req, []string{"application/json", "application/text"}, "application/text") + resp.Header.Set("Content-Type", mid) + + return resp, nil +} diff --git a/internal/resources/grafana/resource_alerting_rule_group.go b/internal/resources/grafana/resource_alerting_rule_group.go index 02f914947..d665e5412 100644 --- a/internal/resources/grafana/resource_alerting_rule_group.go +++ b/internal/resources/grafana/resource_alerting_rule_group.go @@ -202,7 +202,7 @@ This resource requires Grafana 9.1.0 or later. Type: schema.TypeList, MaxItems: 1, Optional: true, - Description: "Notification settings for the rule. If specified, it overrides the notification policies. Available since Grafana 10.4, requires feature flag 'alertingSimplifiedRouting' enabled.", + Description: "Notification settings for the rule. If specified, it overrides the notification policies. Available since Grafana 10.4, requires feature flag 'alertingSimplifiedRouting' to be enabled.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "contact_point": { @@ -244,6 +244,26 @@ This resource requires Grafana 9.1.0 or later. }, }, }, + "record": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "Settings for a recording rule. Available since Grafana 11.2, requires feature flag 'grafanaManagedRecordingRules' to be enabled.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "metric": { + Type: schema.TypeString, + Required: true, + Description: "The name of the metric to write to.", + }, + "from": { + Type: schema.TypeString, + Required: true, + Description: "The ref id of the query node in the data field to use as the source of the metric.", + }, + }, + }, + }, }, }, }, @@ -477,6 +497,12 @@ func packAlertRule(r *models.ProvisionedAlertRule) (interface{}, error) { if ns != nil { json["notification_settings"] = ns } + + record := packRecord(r.Record) + if record != nil { + json["record"] = record + } + return json, nil } @@ -516,6 +542,7 @@ func unpackAlertRule(raw interface{}, groupName string, folderUID string, orgID Annotations: unpackMap(json["annotations"]), IsPaused: json["is_paused"].(bool), NotificationSettings: ns, + Record: unpackRecord(json["record"]), } return &rule, nil @@ -706,3 +733,36 @@ func unpackNotificationSettings(p interface{}) (*models.AlertRuleNotificationSet } return &result, nil } + +func packRecord(r *models.Record) interface{} { + if r == nil { + return nil + } + res := map[string]interface{}{} + if r.Metric != nil { + res["metric"] = *r.Metric + } + if r.From != nil { + res["from"] = *r.From + } + return []interface{}{res} +} + +func unpackRecord(p interface{}) *models.Record { + if p == nil { + return nil + } + list, ok := p.([]interface{}) + if !ok || len(list) == 0 { + return nil + } + jsonData := list[0].(map[string]interface{}) + res := &models.Record{} + if v, ok := jsonData["metric"]; ok && v != nil { + res.Metric = common.Ref(v.(string)) + } + if v, ok := jsonData["from"]; ok && v != nil { + res.From = common.Ref(v.(string)) + } + return res +} diff --git a/internal/resources/grafana/resource_alerting_rule_group_test.go b/internal/resources/grafana/resource_alerting_rule_group_test.go index 4a5edf8b6..5052e8f4a 100644 --- a/internal/resources/grafana/resource_alerting_rule_group_test.go +++ b/internal/resources/grafana/resource_alerting_rule_group_test.go @@ -675,6 +675,38 @@ func TestAccAlertRule_NotificationSettings(t *testing.T) { }) } +func TestAccRecordingRule(t *testing.T) { + testutils.CheckCloudInstanceTestsEnabled(t) // TODO: change to 11.3.1 when available + + var group models.AlertRuleGroup + var name = acctest.RandString(10) + var metric = "valid_metric" + + resource.ParallelTest(t, resource.TestCase{ + ProtoV5ProviderFactories: testutils.ProtoV5ProviderFactories, + CheckDestroy: alertingRuleGroupCheckExists.destroyed(&group, nil), + Steps: []resource.TestStep{ + { + Config: testAccRecordingRule(name, metric, "A"), + Check: resource.ComposeTestCheckFunc( + alertingRuleGroupCheckExists.exists("grafana_rule_group.my_rule_group", &group), + resource.TestCheckResourceAttr("grafana_rule_group.my_rule_group", "name", name), + resource.TestCheckResourceAttr("grafana_rule_group.my_rule_group", "rule.#", "1"), + resource.TestCheckResourceAttr("grafana_rule_group.my_rule_group", "rule.0.name", "My Random Walk Alert"), + resource.TestCheckResourceAttr("grafana_rule_group.my_rule_group", "rule.0.data.0.model", "{\"refId\":\"A\"}"), + resource.TestCheckResourceAttr("grafana_rule_group.my_rule_group", "rule.0.record.0.metric", metric), + resource.TestCheckResourceAttr("grafana_rule_group.my_rule_group", "rule.0.record.0.from", "A"), + // ensure fields are cleared as expected + resource.TestCheckResourceAttr("grafana_rule_group.my_rule_group", "rule.0.for", "2m0s"), + resource.TestCheckResourceAttr("grafana_rule_group.my_rule_group", "rule.0.condition", "A"), + resource.TestCheckResourceAttr("grafana_rule_group.my_rule_group", "rule.0.no_data_state", "NoData"), + resource.TestCheckResourceAttr("grafana_rule_group.my_rule_group", "rule.0.exec_err_state", "Alerting"), + ), + }, + }, + }) +} + func testAccAlertRuleGroupInOrgConfig(name string, interval int, disableProvenance bool) string { return fmt.Sprintf(` resource "grafana_organization" "test" { @@ -825,3 +857,50 @@ resource "grafana_rule_group" "my_rule_group" { } }`, name, gr) } + +func testAccRecordingRule(name string, metric string, refID string) string { + return fmt.Sprintf(` +resource "grafana_folder" "rule_folder" { + title = "%[1]s" +} + +resource "grafana_data_source" "testdata_datasource" { + name = "%[1]s" + type = "grafana-testdata-datasource" + url = "http://localhost:3333" +} + +resource "grafana_rule_group" "my_rule_group" { + name = "%[1]s" + folder_uid = grafana_folder.rule_folder.uid + interval_seconds = 60 + + rule { + name = "My Random Walk Alert" + // following should be cleared by Grafana + condition = "A" + no_data_state = "NoData" + exec_err_state = "Alerting" + for = "2m" + + // Query the datasource. + data { + ref_id = "A" + relative_time_range { + from = 600 + to = 0 + } + datasource_uid = grafana_data_source.testdata_datasource.uid + model = jsonencode({ + intervalMs = 1000 + maxDataPoints = 43200 + refId = "A" + }) + } + record { + metric = "%[2]s" + from = "%[3]s" + } + } +}`, name, metric, refID) +} diff --git a/internal/resources/machinelearning/resource_job.go b/internal/resources/machinelearning/resource_job.go index 46bc3c6ba..e4a1aba90 100644 --- a/internal/resources/machinelearning/resource_job.go +++ b/internal/resources/machinelearning/resource_job.go @@ -18,7 +18,9 @@ func resourceJob() *common.Resource { Description: ` A job defines the queries and model parameters for a machine learning task. -`, + +See [the Grafana Cloud docs](https://grafana.com/docs/grafana-cloud/alerting-and-irm/machine-learning/forecasts/models/) for more information +on available hyperparameters for use in the ` + "`hyper_params`" + ` field.`, CreateContext: checkClient(resourceJobCreate), ReadContext: checkClient(resourceJobRead), @@ -77,7 +79,7 @@ A job defines the queries and model parameters for a machine learning task. Default: 300, }, "hyper_params": { - Description: "The hyperparameters used to fine tune the algorithm. See https://grafana.com/docs/grafana-cloud/machine-learning/models/ for the full list of available hyperparameters.", + Description: "The hyperparameters used to fine tune the algorithm. See https://grafana.com/docs/grafana-cloud/alerting-and-irm/machine-learning/forecasts/models/ for the full list of available hyperparameters.", Type: schema.TypeMap, Optional: true, Default: map[string]interface{}{}, diff --git a/templates/index.md.tmpl b/templates/index.md.tmpl index 56e08637f..7a9889e2f 100644 --- a/templates/index.md.tmpl +++ b/templates/index.md.tmpl @@ -89,6 +89,22 @@ The following are examples on how the *Account* and *Scrape Job* resources can b ### Managing Connections +#### Obtaining Connections access token + +Before using the Terraform Provider to manage Grafana Connections resources, such as metrics endpoint scrape jobs, you need to create an access policy token on the Grafana Cloud Portal. This token is used to authenticate the provider to the Grafana Connections API. +[These docs](https://grafana.com/docs/grafana-cloud/account-management/authentication-and-permissions/access-policies/authorize-services/#create-an-access-policy-for-a-stack) will guide you on how to create +an access policy. The required permissions, or scopes, are `integration-management:read`, `integration-management:write` and `stacks:read`. + +Also, by default the Access Policies UI will not show those scopes, instead, search for it using the `Add Scope` textbox, as shown in the following image: + + + +1. Use the `Add Scope` textbox to search for the permissions you need to add to the access policy: `integration-management:read`, `integration-management:write` and `stacks:read`. +1. Once done, you should see the scopes selected with checkboxes. + +Having created an Access Policy, you can now create a token that will be used to authenticate the provider to the Connections API. You can do so just after creating the access policy, following +the in-screen instructions, of following [this guide](https://grafana.com/docs/grafana-cloud/account-management/authentication-and-permissions/access-policies/authorize-services/#create-one-or-more-access-policy-tokens). + #### Obtaining Connections API hostname Having created the token, we can find the correct Connections API hostname by running the following script, that requires `curl` and [`jq`](https://jqlang.github.io/jq/) installed: @@ -111,22 +127,6 @@ For example, in the following response, the correct hostname for the `examplesta ] ``` -#### Obtaining Connections access token - -Before using the Terraform Provider to manage Grafana Connections resources, such as metrics endpoint scrape jobs, you need to create an access policy token on the Grafana Cloud Portal. This token is used to authenticate the provider to the Grafana Connections API. -[These docs](https://grafana.com/docs/grafana-cloud/account-management/authentication-and-permissions/access-policies/authorize-services/#create-an-access-policy-for-a-stack) will guide you on how to create -an access policy. The required permissions, or scopes, are `integration-management:read`, `integration-management:write` and `stacks:read`. - -Also, by default the Access Policies UI will not show those scopes, instead, search for it using the `Add Scope` textbox, as shown in the following image: - - - -1. Use the `Add Scope` textbox (1) to search for the permissions you need to add to the access policy. -1. Make sure that you configure the three required scopes. Once done, you'll see the selected scopes as in (2). - -Having created an Access Policy, you can now create a token that will be used to authenticate the provider to the Connections API. You can do so just after creating the access policy, following -the in-screen instructions, of following [this guide](https://grafana.com/docs/grafana-cloud/account-management/authentication-and-permissions/access-policies/authorize-services/#create-one-or-more-access-policy-tokens). - #### Configuring the Provider to use the Connections API Once you have the token and Connections API hostname, you can configure the provider as follows: @@ -170,4 +170,4 @@ To create one, follow the instructions in the [obtaining cloud provider access t An access policy token created on the [Grafana Cloud Portal](https://grafana.com/docs/grafana-cloud/account-management/authentication-and-permissions/access-policies/authorize-services/) to manage connections resources, such as Metrics Endpoint jobs. -For guidance on creating one, see section [obtaining connections access token](#obtaining-connections-access-token) +For guidance on creating one, see section [obtaining connections access token](#obtaining-connections-access-token).