terraform-provider-grafana icon indicating copy to clipboard operation
terraform-provider-grafana copied to clipboard

Resource: Add LBAC for datasources `data_source_lbac_rules`

Open eleijonmarck opened this issue 1 year ago • 2 comments

why/what We have seen that users would love to provision their lbac rules using terraform. this implements a experimental feature that will be highly developed. this is the first part of LBAC rules resource for terraform.

we have: updated swagger doc and swagger definitions in LBAC for datasources

  • https://github.com/grafana/grafana-enterprise/pull/7117 ✅
  • https://github.com/grafana/grafana/pull/92594 ✅

ability to run terraform plan, terraform apply and terraform destroy of the rules resource

Example terraform:

resource "grafana_data_source" "test" {
  type = "loki"
  name = "loki"
  url  = "http://localhost:3100"
  basic_auth_enabled  = true
  basic_auth_username = "username"

  lifecycle {
    ignore_changes = [json_data_encoded, http_headers]
  }
}

resource "grafana_team" "test" {
	name = "test"
}

resource "grafana_data_source_config_lbac_rules" "test" {
    datasource_uid = grafana_data_source.test.uid
	org_id = grafana_team.test.org_id
    rules = jsonencode({
        "${grafana_team.test.id}" = [
            "{ foo != \"bar\", foo !~ \"baz\" }",
            "{ foo = \"qux\" }"
        ]
    })
}

proposals and thought process

there is no ID for the json field teamHttpHeaders

  • so the state is only “stored” in the datasource as a whole, therefore leaning on copying the data_source_config resource more this is a resource that will be heavily used
  • i would like to have the internal state for terraform (some customers create about 500 rules and more), which clogs the datasource, i would like to copy the setup from grafana_data_source_permission_item for this. as it suits well for how we would like to setup this resource
  • instead we make use of the api as it is. it is bulk update anyway. so we assume that all of the teams will be provided in the resource of resource_data_source_config_lbac_rules

proposal of all rules combined into one resource

benefits

  • one api call to grafana
  • mimicing the get/update apis

tradeoffs

  • clonky json encoding (could be fixed)
  • not ideal for teams managing their own set of rules
resource "grafana_data_source_config_lbac_rules" "test" {
    datasource_uid = grafana_data_source.test.uid
	org_id = grafana_team.test.org_id
    rules = jsonencode({
        "${grafana_team.test.id}" = [
            "{ foo != \"bar\", foo !~ \"baz\" }",
            "{ foo = \"qux\" }"
        ]
    })
}

proposal of each rule being a resource

benefits

  • each team rules, would be able to be owned by a team. this is preferred from a user perspective

tradeoffs

  • too many api calls to grafana, if we have 500 rules we would have 500 api calls to the datasource endpoint
resource "grafana_data_source_config_lbac_rule" "test" {
    datasource_uid = grafana_data_source.test.uid
    org_id = grafana_team.test.org_id
    team_id = "1"
    rules = [
            "{ foo != \"bar\", foo !~ \"baz\" }",
            "{ foo = \"qux\" }"
        ]
}

proposal of embedding it into a resource and then add it to the json

benefits:

  • easier to implement

tradeoff

  • management of lbac rules would lie inside of the json and we would not be able to move the storage of the lbac rules

It's a tradeoff of where you want the complexity to be. In Grafana with a new way to store this, or in the provider extracting it from json data, and possibly running into versioning issues.

I guess the less complex option is to leave everything as-is, isn't it? Have people manage those new fields in the existing json data? Perhaps provide a datasource helper for this, if the value is not trivial to build/represent

data "grafana_datasource_team_headers" "helper" { ... }

resource "grafana_datasource" "test" {
  ...
  json_data_encoded = jsonencode({
     teamHeaders = data.grafana_datasource_team_headers.helper.value
     otherfields
  })
}

run tests via

GRAFANA_VERSION=11.1.0 
GRAFANA_URL=http://localhost:3000 
GRAFANA_AUTH=admin:admin 
TESTARGS="-run TestAccDataSourceLBAC_inOrg" make testacc-enterprise

The teamHttpHeaders resource is a datasource json field.

epic

basically this introduced a way to add/update a datasource json field lbac-api

here is the doc for it. https://grafana.com/docs/grafana/latest/administration/data-source-management/teamlbac/


next steps

improvements:

  • [ ] API of the resource could be made so that there is no need of escaped JSON. To enforces types and schema
  1. Create a template file (logql_query.tmpl):
{f="fea", b="bajs", a="abc"}
resource "grafana_data_source_config_lbac_rules" "test" {
    datasource_uid = grafana_data_source.test.uid
    rules = jsonencode({
        "1" = [
            "{ foo != \"bar\", foo !~ \"baz\" }",
            "{ foo = \"qux\" }"
        ],
        "2" = [
            templatefile("${path.module}/logql_query.tmpl", {})
        ]
    })
}

```[tasklist]
- [ ] fix the lifecycle of the jsondata within grafana
  - [ ] make sure you cannot set teamhttpheaders from the json api (updateDatasource), ONLY through lbac/team api
  - [ ] magic diffsuprressfunc to ignore changes on json_data_encoded for the specific field teamHttpHeaders

eleijonmarck avatar Sep 09 '24 10:09 eleijonmarck