-
Notifications
You must be signed in to change notification settings - Fork 236
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add public dashboards support (#1026)
* Add support for public dashboards * replace golang client by a specific branch for testing * fix lint errors and add min grafana version for tests * fix lint errors * update go mod and remove optional attribute from schema description * update docs * add import test * add orgid to public dashboard resource * fix comment * fix lint * add notice about only being available in 10.2 --------- Co-authored-by: Julien Duchesne <[email protected]>
- Loading branch information
1 parent
4e8aa22
commit 633b640
Showing
7 changed files
with
389 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
--- | ||
# generated by https://github.com/hashicorp/terraform-plugin-docs | ||
page_title: "grafana_dashboard_public Resource - terraform-provider-grafana" | ||
subcategory: "Grafana OSS" | ||
description: |- | ||
Manages Grafana public dashboards. | ||
Note: This resource is available only with Grafana 10.2+. | ||
Official documentation https://grafana.com/docs/grafana/latest/dashboards/dashboard-public/HTTP API https://grafana.com/docs/grafana/next/developers/http_api/dashboard_public/ | ||
--- | ||
|
||
# grafana_dashboard_public (Resource) | ||
|
||
Manages Grafana public dashboards. | ||
|
||
**Note:** This resource is available only with Grafana 10.2+. | ||
|
||
* [Official documentation](https://grafana.com/docs/grafana/latest/dashboards/dashboard-public/) | ||
* [HTTP API](https://grafana.com/docs/grafana/next/developers/http_api/dashboard_public/) | ||
|
||
## Example Usage | ||
|
||
```terraform | ||
// Optional (On-premise, not supported in Grafana Cloud): Create an organization | ||
resource "grafana_organization" "my_org" { | ||
name = "test 1" | ||
} | ||
// Create resources (optional: within the organization) | ||
resource "grafana_folder" "my_folder" { | ||
org_id = grafana_organization.my_org.org_id | ||
title = "test Folder" | ||
} | ||
resource "grafana_dashboard" "test_dash" { | ||
org_id = grafana_organization.my_org.org_id | ||
folder = grafana_folder.my_folder.id | ||
config_json = jsonencode({ | ||
"title" : "My Terraform Dashboard", | ||
"uid" : "my-dashboard-uid" | ||
}) | ||
} | ||
resource "grafana_dashboard_public" "my_public_dashboard" { | ||
org_id = grafana_organization.my_org.org_id | ||
dashboard_uid = grafana_dashboard.test_dash.uid | ||
uid = "my-custom-public-uid" | ||
access_token = "e99e4275da6f410d83760eefa934d8d2" | ||
time_selection_enabled = true | ||
is_enabled = true | ||
annotations_enabled = true | ||
share = "public" | ||
} | ||
// Optional (On-premise, not supported in Grafana Cloud): Create an organization | ||
resource "grafana_organization" "my_org2" { | ||
name = "test 2" | ||
} | ||
resource "grafana_dashboard" "test_dash2" { | ||
org_id = grafana_organization.my_org2.org_id | ||
config_json = jsonencode({ | ||
"title" : "My Terraform Dashboard2", | ||
"uid" : "my-dashboard-uid2" | ||
}) | ||
} | ||
resource "grafana_dashboard_public" "my_public_dashboard2" { | ||
org_id = grafana_organization.my_org2.org_id | ||
dashboard_uid = grafana_dashboard.test_dash2.uid | ||
share = "public" | ||
} | ||
``` | ||
|
||
<!-- schema generated by tfplugindocs --> | ||
## Schema | ||
|
||
### Required | ||
|
||
- `dashboard_uid` (String) The unique identifier of the original dashboard. | ||
|
||
### Optional | ||
|
||
- `access_token` (String) A public unique identifier of a public dashboard. This is used to construct its URL. It's automatically generated if not provided when creating a public dashboard. | ||
- `annotations_enabled` (Boolean) Set to `true` to show annotations. The default value is `false`. | ||
- `is_enabled` (Boolean) Set to `true` to enable the public dashboard. The default value is `false`. | ||
- `org_id` (String) The Organization ID. If not set, the Org ID defined in the provider block will be used. | ||
- `share` (String) Set the share mode. The default value is `public`. | ||
- `time_selection_enabled` (Boolean) Set to `true` to enable the time picker in the public dashboard. The default value is `false`. | ||
- `uid` (String) The unique identifier of a public dashboard. It's automatically generated if not provided when creating a public dashboard. | ||
|
||
### Read-Only | ||
|
||
- `id` (String) The ID of this resource. | ||
|
||
## Import | ||
|
||
Import is supported using the following syntax: | ||
|
||
```shell | ||
terraform import grafana_dashboard_public.dashboard_name {{dashboard_uid}}:{{public_dashboard_uid}} # To use the default provider org | ||
terraform import grafana_dashboard_public.dashboard_name {org_id}}:{{dashboard_uid}}:{{public_dashboard_uid}} # When "org_id" is set on the resource | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
terraform import grafana_dashboard_public.dashboard_name {{dashboard_uid}}:{{public_dashboard_uid}} # To use the default provider org | ||
terraform import grafana_dashboard_public.dashboard_name {org_id}}:{{dashboard_uid}}:{{public_dashboard_uid}} # When "org_id" is set on the resource |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
// Optional (On-premise, not supported in Grafana Cloud): Create an organization | ||
resource "grafana_organization" "my_org" { | ||
name = "test 1" | ||
} | ||
|
||
// Create resources (optional: within the organization) | ||
resource "grafana_folder" "my_folder" { | ||
org_id = grafana_organization.my_org.org_id | ||
title = "test Folder" | ||
} | ||
|
||
resource "grafana_dashboard" "test_dash" { | ||
org_id = grafana_organization.my_org.org_id | ||
folder = grafana_folder.my_folder.id | ||
config_json = jsonencode({ | ||
"title" : "My Terraform Dashboard", | ||
"uid" : "my-dashboard-uid" | ||
}) | ||
} | ||
|
||
resource "grafana_dashboard_public" "my_public_dashboard" { | ||
org_id = grafana_organization.my_org.org_id | ||
dashboard_uid = grafana_dashboard.test_dash.uid | ||
|
||
uid = "my-custom-public-uid" | ||
access_token = "e99e4275da6f410d83760eefa934d8d2" | ||
|
||
time_selection_enabled = true | ||
is_enabled = true | ||
annotations_enabled = true | ||
share = "public" | ||
} | ||
|
||
// Optional (On-premise, not supported in Grafana Cloud): Create an organization | ||
resource "grafana_organization" "my_org2" { | ||
name = "test 2" | ||
} | ||
|
||
resource "grafana_dashboard" "test_dash2" { | ||
org_id = grafana_organization.my_org2.org_id | ||
config_json = jsonencode({ | ||
"title" : "My Terraform Dashboard2", | ||
"uid" : "my-dashboard-uid2" | ||
}) | ||
} | ||
|
||
resource "grafana_dashboard_public" "my_public_dashboard2" { | ||
org_id = grafana_organization.my_org2.org_id | ||
dashboard_uid = grafana_dashboard.test_dash2.uid | ||
|
||
share = "public" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
151 changes: 151 additions & 0 deletions
151
internal/resources/grafana/resource_dashboard_public.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
package grafana | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"strconv" | ||
"strings" | ||
|
||
gapi "github.com/grafana/grafana-api-golang-client" | ||
"github.com/grafana/terraform-provider-grafana/internal/common" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
) | ||
|
||
func ResourcePublicDashboard() *schema.Resource { | ||
return &schema.Resource{ | ||
|
||
Description: ` | ||
Manages Grafana public dashboards. | ||
**Note:** This resource is available only with Grafana 10.2+. | ||
* [Official documentation](https://grafana.com/docs/grafana/latest/dashboards/dashboard-public/) | ||
* [HTTP API](https://grafana.com/docs/grafana/next/developers/http_api/dashboard_public/) | ||
`, | ||
|
||
CreateContext: CreatePublicDashboard, | ||
ReadContext: ReadPublicDashboard, | ||
UpdateContext: UpdatePublicDashboard, | ||
DeleteContext: DeletePublicDashboard, | ||
Importer: &schema.ResourceImporter{ | ||
StateContext: schema.ImportStatePassthroughContext, | ||
}, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"org_id": orgIDAttribute(), | ||
"uid": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
Optional: true, | ||
Description: "The unique identifier of a public dashboard. " + | ||
"It's automatically generated if not provided when creating a public dashboard. ", | ||
}, | ||
"dashboard_uid": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
Description: "The unique identifier of the original dashboard.", | ||
}, | ||
"access_token": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
Optional: true, | ||
Description: "A public unique identifier of a public dashboard. This is used to construct its URL. " + | ||
"It's automatically generated if not provided when creating a public dashboard. ", | ||
}, | ||
"time_selection_enabled": { | ||
Type: schema.TypeBool, | ||
Optional: true, | ||
Description: "Set to `true` to enable the time picker in the public dashboard. The default value is `false`.", | ||
}, | ||
"is_enabled": { | ||
Type: schema.TypeBool, | ||
Optional: true, | ||
Description: "Set to `true` to enable the public dashboard. The default value is `false`.", | ||
}, | ||
"annotations_enabled": { | ||
Type: schema.TypeBool, | ||
Optional: true, | ||
Description: "Set to `true` to show annotations. The default value is `false`.", | ||
}, | ||
"share": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
Description: "Set the share mode. The default value is `public`.", | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func CreatePublicDashboard(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
client, orgID := ClientFromNewOrgResource(meta, d) | ||
dashboardUID := d.Get("dashboard_uid").(string) | ||
|
||
publicDashboardPayload := makePublicDashboard(d) | ||
pd, err := client.NewPublicDashboard(dashboardUID, publicDashboardPayload) | ||
if err != nil { | ||
return diag.FromErr(err) | ||
} | ||
|
||
d.SetId(fmt.Sprintf("%d:%s:%s", orgID, pd.DashboardUID, pd.UID)) | ||
return ReadPublicDashboard(ctx, d, meta) | ||
} | ||
func UpdatePublicDashboard(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
orgID, dashboardUID, publicDashboardUID := SplitPublicDashboardID(d.Id()) | ||
client := meta.(*common.Client).GrafanaAPI.WithOrgID(orgID) | ||
|
||
publicDashboard := makePublicDashboard(d) | ||
pd, err := client.UpdatePublicDashboard(dashboardUID, publicDashboardUID, publicDashboard) | ||
if err != nil { | ||
return diag.FromErr(err) | ||
} | ||
|
||
d.SetId(fmt.Sprintf("%d:%s:%s", orgID, pd.DashboardUID, pd.UID)) | ||
return ReadPublicDashboard(ctx, d, meta) | ||
} | ||
|
||
func DeletePublicDashboard(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
orgID, dashboardUID, publicDashboardUID := SplitPublicDashboardID(d.Id()) | ||
client := meta.(*common.Client).GrafanaAPI.WithOrgID(orgID) | ||
return diag.FromErr(client.DeletePublicDashboard(dashboardUID, publicDashboardUID)) | ||
} | ||
|
||
func makePublicDashboard(d *schema.ResourceData) gapi.PublicDashboardPayload { | ||
return gapi.PublicDashboardPayload{ | ||
UID: d.Get("uid").(string), | ||
AccessToken: d.Get("access_token").(string), | ||
TimeSelectionEnabled: d.Get("time_selection_enabled").(bool), | ||
IsEnabled: d.Get("is_enabled").(bool), | ||
AnnotationsEnabled: d.Get("annotations_enabled").(bool), | ||
Share: d.Get("share").(string), | ||
} | ||
} | ||
|
||
func ReadPublicDashboard(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
orgID, dashboardUID, _ := SplitPublicDashboardID(d.Id()) | ||
client := meta.(*common.Client).GrafanaAPI.WithOrgID(orgID) | ||
pd, err := client.PublicDashboardbyUID(dashboardUID) | ||
if err, shouldReturn := common.CheckReadError("dashboard", d, err); shouldReturn { | ||
return err | ||
} | ||
|
||
d.Set("org_id", strconv.FormatInt(orgID, 10)) | ||
|
||
d.Set("uid", pd.UID) | ||
d.Set("dashboard_uid", pd.DashboardUID) | ||
d.Set("access_token", pd.AccessToken) | ||
d.Set("time_selection_enabled", pd.TimeSelectionEnabled) | ||
d.Set("is_enabled", pd.IsEnabled) | ||
d.Set("annotations_enabled", pd.AnnotationsEnabled) | ||
d.Set("share", pd.Share) | ||
|
||
d.SetId(fmt.Sprintf("%d:%s:%s", orgID, pd.DashboardUID, pd.UID)) | ||
|
||
return nil | ||
} | ||
|
||
func SplitPublicDashboardID(id string) (int64, string, string) { | ||
ids := strings.Split(id, ":") | ||
orgID, _ := strconv.ParseInt(ids[0], 10, 64) | ||
return orgID, ids[1], ids[2] | ||
} |
77 changes: 77 additions & 0 deletions
77
internal/resources/grafana/resource_dashboard_public_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package grafana_test | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/grafana/terraform-provider-grafana/internal/common" | ||
"github.com/grafana/terraform-provider-grafana/internal/resources/grafana" | ||
"github.com/grafana/terraform-provider-grafana/internal/testutils" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform" | ||
) | ||
|
||
func TestAccPublicDashboard_basic(t *testing.T) { | ||
testutils.CheckOSSTestsEnabled(t, ">=10.2.0") | ||
|
||
resource.Test(t, resource.TestCase{ | ||
ProviderFactories: testutils.ProviderFactories, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testutils.TestAccExample(t, "resources/grafana_dashboard_public/resource.tf"), | ||
Check: resource.ComposeAggregateTestCheckFunc( | ||
testAccPublicDashboardCheckExistsUID("grafana_dashboard_public.my_public_dashboard"), | ||
resource.TestCheckResourceAttr("grafana_dashboard_public.my_public_dashboard", "uid", "my-custom-public-uid"), | ||
resource.TestCheckResourceAttr("grafana_dashboard_public.my_public_dashboard", "dashboard_uid", "my-dashboard-uid"), | ||
resource.TestCheckResourceAttr("grafana_dashboard_public.my_public_dashboard", "access_token", "e99e4275da6f410d83760eefa934d8d2"), | ||
resource.TestCheckResourceAttr("grafana_dashboard_public.my_public_dashboard", "is_enabled", "true"), | ||
resource.TestCheckResourceAttr("grafana_dashboard_public.my_public_dashboard", "share", "public"), | ||
resource.TestCheckResourceAttr("grafana_dashboard_public.my_public_dashboard", "time_selection_enabled", "true"), | ||
resource.TestCheckResourceAttr("grafana_dashboard_public.my_public_dashboard", "annotations_enabled", "true"), | ||
checkResourceIsInOrg("grafana_dashboard_public.my_public_dashboard", "grafana_organization.my_org"), | ||
|
||
// my_public_dashboard2 belong to a different org_id | ||
checkResourceIsInOrg("grafana_dashboard_public.my_public_dashboard2", "grafana_organization.my_org2"), | ||
resource.TestCheckResourceAttr("grafana_dashboard_public.my_public_dashboard2", "dashboard_uid", "my-dashboard-uid2"), | ||
resource.TestCheckResourceAttr("grafana_dashboard_public.my_public_dashboard2", "is_enabled", "false"), | ||
resource.TestCheckResourceAttr("grafana_dashboard_public.my_public_dashboard2", "share", "public"), | ||
resource.TestCheckResourceAttr("grafana_dashboard_public.my_public_dashboard2", "time_selection_enabled", "false"), | ||
resource.TestCheckResourceAttr("grafana_dashboard_public.my_public_dashboard2", "annotations_enabled", "false"), | ||
), | ||
}, | ||
{ | ||
ResourceName: "grafana_dashboard_public.my_public_dashboard", | ||
ImportState: true, | ||
ImportStateVerify: true, | ||
}, | ||
{ | ||
ResourceName: "grafana_dashboard_public.my_public_dashboard2", | ||
ImportState: true, | ||
ImportStateVerify: true, | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccPublicDashboardCheckExistsUID(rn string) resource.TestCheckFunc { | ||
return func(s *terraform.State) error { | ||
rs, ok := s.RootModule().Resources[rn] | ||
if !ok { | ||
return fmt.Errorf("Resource not found: %s\n %#v", rn, s.RootModule().Resources) | ||
} | ||
|
||
if rs.Primary.ID == "" { | ||
return fmt.Errorf("Resource id not set") | ||
} | ||
|
||
orgID, dashboardUID, _ := grafana.SplitPublicDashboardID(rs.Primary.ID) | ||
|
||
client := testutils.Provider.Meta().(*common.Client).GrafanaAPI.WithOrgID(orgID) | ||
pd, err := client.PublicDashboardbyUID(dashboardUID) | ||
if pd == nil || err != nil { | ||
return fmt.Errorf("Error getting public dashboard: %s", err) | ||
} | ||
|
||
return nil | ||
} | ||
} |
Oops, something went wrong.