Skip to content

Commit 85173e7

Browse files
Library Panel: Make org_id an Optional attribute (#814)
- Also fixed a few possible bugs as I moved through the resource - Gradually improving the "framework" as I work through this. It will go faster and faster to do more resources as I move forward
1 parent a75b1ee commit 85173e7

File tree

8 files changed

+134
-56
lines changed

8 files changed

+134
-56
lines changed

docs/data-sources/library_panel.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ data "grafana_library_panel" "from_name" {
2929
}
3030
3131
data "grafana_library_panel" "from_uid" {
32-
uid = grafana_library_panel.test.id
32+
uid = grafana_library_panel.test.uid
3333
}
3434
3535
// create library panels to be added to a dashboard
@@ -89,6 +89,7 @@ data "grafana_dashboard" "from_library_panel_connection" {
8989
### Optional
9090

9191
- `name` (String) Name of the library panel.
92+
- `org_id` (String) The Organization ID. If not set, the Org ID defined in the provider block will be used.
9293
- `uid` (String) The unique identifier (UID) of the library panel.
9394

9495
### Read-Only
@@ -101,7 +102,6 @@ data "grafana_dashboard" "from_library_panel_connection" {
101102
- `folder_uid` (String) Unique ID (UID) of the folder containing the library panel.
102103
- `id` (String) The ID of this resource.
103104
- `model_json` (String) The JSON model for the library panel.
104-
- `org_id` (Number) The numeric ID of the library panel computed by Grafana.
105105
- `panel_id` (Number) The numeric ID of the library panel computed by Grafana.
106106
- `type` (String) Type of the library panel (eg. text).
107107
- `updated` (String) Timestamp when the library panel was last modified.

docs/resources/library_panel.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ resource "grafana_library_panel" "test" {
3838
### Optional
3939

4040
- `folder_id` (Number) ID of the folder where the library panel is stored.
41+
- `org_id` (String) The Organization ID. If not set, the Org ID defined in the provider block will be used.
4142
- `uid` (String) The unique identifier (UID) of a library panel uniquely identifies library panels between multiple Grafana installs. It’s automatically generated unless you specify it during library panel creation.The UID provides consistent URLs for accessing library panels and when syncing library panels between multiple Grafana installs.
4243

4344
### Read-Only
@@ -48,7 +49,6 @@ resource "grafana_library_panel" "test" {
4849
- `folder_name` (String) Name of the folder containing the library panel.
4950
- `folder_uid` (String) Unique ID (UID) of the folder containing the library panel.
5051
- `id` (String) The ID of this resource.
51-
- `org_id` (Number) The numeric ID of the library panel computed by Grafana.
5252
- `panel_id` (Number) The numeric ID of the library panel computed by Grafana.
5353
- `type` (String) Type of the library panel (eg. text).
5454
- `updated` (String) Timestamp when the library panel was last modified.

examples/data-sources/grafana_library_panel/data-source.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ data "grafana_library_panel" "from_name" {
1414
}
1515

1616
data "grafana_library_panel" "from_uid" {
17-
uid = grafana_library_panel.test.id
17+
uid = grafana_library_panel.test.uid
1818
}
1919

2020
// create library panels to be added to a dashboard

internal/resources/grafana/data_source_library_panel.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ func DatasourceLibraryPanel() *schema.Resource {
1313
Description: "Data source for retrieving a single library panel by name or uid.",
1414
ReadContext: dataSourceLibraryPanelRead,
1515
Schema: common.CloneResourceSchemaForDatasource(ResourceLibraryPanel(), map[string]*schema.Schema{
16+
"org_id": {
17+
Type: schema.TypeString,
18+
Optional: true,
19+
Description: "The Organization ID. If not set, the Org ID defined in the provider block will be used.",
20+
},
1621
"name": {
1722
Type: schema.TypeString,
1823
Optional: true,
@@ -28,7 +33,7 @@ func DatasourceLibraryPanel() *schema.Resource {
2833
}
2934

3035
func dataSourceLibraryPanelRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
31-
client := meta.(*common.Client).GrafanaAPI
36+
client, orgID := ClientFromOrgIDAttr(meta, d)
3237
uid := d.Get("uid").(string)
3338

3439
// get UID from name if specified
@@ -41,8 +46,7 @@ func dataSourceLibraryPanelRead(ctx context.Context, d *schema.ResourceData, met
4146
uid = panel.UID
4247
}
4348

44-
d.SetId(uid)
45-
ReadLibraryPanel(ctx, d, meta)
49+
d.SetId(MakeOSSOrgID(orgID, uid))
4650

47-
return nil
51+
return readLibraryPanel(ctx, d, meta)
4852
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package grafana_test
2+
3+
import (
4+
"fmt"
5+
"regexp"
6+
"strconv"
7+
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
10+
)
11+
12+
var (
13+
defaultOrgIDRegexp = regexp.MustCompile(`^(0|1):[a-zA-Z0-9-_]+$`)
14+
// https://regex101.com/r/icTmfm/1
15+
nonDefaultOrgIDRegexp = regexp.MustCompile(`^([^0-1]\d*|1\d+):[a-zA-Z0-9-_]+$`)
16+
)
17+
18+
func checkResourceIsInOrg(resourceName, orgResourceName string) resource.TestCheckFunc {
19+
return func(s *terraform.State) error {
20+
resourceOrgID, err := strconv.Atoi(s.RootModule().Resources[resourceName].Primary.Attributes["org_id"])
21+
if err != nil {
22+
return err
23+
}
24+
25+
if resourceOrgID <= 1 {
26+
return fmt.Errorf("resource org ID %d is not greater than 1", resourceOrgID)
27+
}
28+
29+
orgID, err := strconv.Atoi(s.RootModule().Resources[orgResourceName].Primary.ID)
30+
if err != nil {
31+
return err
32+
}
33+
34+
if orgID != resourceOrgID {
35+
return fmt.Errorf("expected org ID %d, got %d", orgID, resourceOrgID)
36+
}
37+
38+
return nil
39+
}
40+
}

internal/resources/grafana/resource_dashboard_test.go

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -200,19 +200,13 @@ func TestAccDashboard_inOrg(t *testing.T) {
200200
{
201201
Config: testAccDashboardInOrganization(orgName),
202202
Check: resource.ComposeTestCheckFunc(
203-
testAccOrganizationCheckExists("grafana_organization.test", &org),
204203
testAccDashboardCheckExists("grafana_dashboard.test", &dashboard),
205204
resource.TestCheckResourceAttr("grafana_dashboard.test", "uid", "dashboard-"+orgName),
206-
// Check that the dashboard is not in the default org, from its ID
207-
func(s *terraform.State) error {
208-
expectedOrgID := org.ID
209-
if org.ID <= 1 {
210-
return fmt.Errorf("expected org ID higher than 1, got %d", org.ID)
211-
}
212-
expectedDashboardID := fmt.Sprintf("%d:dashboard-%s", expectedOrgID, orgName) // <org id>:<uid>
213-
checkFunc := resource.TestCheckResourceAttr("grafana_dashboard.test", "id", expectedDashboardID)
214-
return checkFunc(s)
215-
},
205+
206+
// Check that the dashboard is in the correct organization
207+
resource.TestMatchResourceAttr("grafana_dashboard.test", "id", nonDefaultOrgIDRegexp),
208+
testAccOrganizationCheckExists("grafana_organization.test", &org),
209+
checkResourceIsInOrg("grafana_dashboard.test", "grafana_organization.test"),
216210
),
217211
},
218212
},

internal/resources/grafana/resource_library_panel.go

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7+
"strconv"
78
"strings"
89

910
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
1011
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
1112

1213
gapi "github.com/grafana/grafana-api-golang-client"
13-
"github.com/grafana/terraform-provider-grafana/internal/common"
1414
)
1515

1616
func ResourceLibraryPanel() *schema.Resource {
@@ -23,10 +23,10 @@ Manages Grafana library panels.
2323
* [HTTP API](https://grafana.com/docs/grafana/latest/developers/http_api/library_element/)
2424
`,
2525

26-
CreateContext: CreateLibraryPanel,
27-
ReadContext: ReadLibraryPanel,
28-
UpdateContext: UpdateLibraryPanel,
29-
DeleteContext: DeleteLibraryPanel,
26+
CreateContext: createLibraryPanel,
27+
ReadContext: readLibraryPanel,
28+
UpdateContext: updateLibraryPanel,
29+
DeleteContext: deleteLibraryPanel,
3030
Importer: &schema.ResourceImporter{
3131
StateContext: schema.ImportStatePassthroughContext,
3232
},
@@ -46,9 +46,13 @@ Manages Grafana library panels.
4646
Description: "The numeric ID of the library panel computed by Grafana.",
4747
},
4848
"org_id": {
49-
Type: schema.TypeInt,
50-
Computed: true,
51-
Description: "The numeric ID of the library panel computed by Grafana.",
49+
Type: schema.TypeString,
50+
Optional: true,
51+
Description: "The Organization ID. If not set, the Org ID defined in the provider block will be used.",
52+
ForceNew: true,
53+
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
54+
return new == "" // Ignore the case where we have a global org_id set
55+
},
5256
},
5357
"folder_id": {
5458
Type: schema.TypeInt,
@@ -112,30 +116,29 @@ Manages Grafana library panels.
112116
}
113117
}
114118

115-
func CreateLibraryPanel(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
116-
client := meta.(*common.Client).GrafanaAPI
119+
func createLibraryPanel(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
120+
client, _ := ClientFromOrgIDAttr(meta, d)
121+
117122
panel := makeLibraryPanel(d)
118123
resp, err := client.NewLibraryPanel(panel)
119124
if err != nil {
120125
return diag.FromErr(err)
121126
}
122-
d.SetId(resp.UID)
123-
d.Set("uid", resp.UID)
124-
return ReadLibraryPanel(ctx, d, meta)
127+
d.SetId(MakeOSSOrgID(resp.OrgID, resp.UID))
128+
return readLibraryPanel(ctx, d, meta)
125129
}
126130

127-
func ReadLibraryPanel(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
128-
client := meta.(*common.Client).GrafanaAPI
129-
uid := d.Id()
131+
func readLibraryPanel(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
132+
client, _, uid := ClientFromOSSOrgID(meta, d.Id())
130133

131134
panel, err := client.LibraryPanelByUID(uid)
132135
var diags diag.Diagnostics
133136
if err != nil {
134137
if strings.HasPrefix(err.Error(), "status: 404") {
135138
diags = append(diags, diag.Diagnostic{
136139
Severity: diag.Warning,
137-
Summary: fmt.Sprintf("Library Panel %q is in state, but no longer exists in grafana", panel.Name),
138-
Detail: fmt.Sprintf("%q will be recreated when you apply", panel.Name),
140+
Summary: fmt.Sprintf("Library Panel %s is in state, but no longer exists in grafana", uid),
141+
Detail: fmt.Sprintf("%s will be recreated when you apply", uid),
139142
})
140143
d.SetId("")
141144
return diags
@@ -154,10 +157,9 @@ func ReadLibraryPanel(ctx context.Context, d *schema.ResourceData, meta interfac
154157
}
155158
modelJSON := normalizeLibraryPanelModelJSON(remotePanelJSON)
156159

157-
d.SetId(panel.UID)
158160
d.Set("uid", panel.UID)
159161
d.Set("panel_id", panel.ID)
160-
d.Set("org_id", panel.OrgID)
162+
d.Set("org_id", strconv.FormatInt(panel.OrgID, 10))
161163
d.Set("folder_id", panel.Folder)
162164
d.Set("description", panel.Description)
163165
d.Set("type", panel.Type)
@@ -183,28 +185,22 @@ func ReadLibraryPanel(ctx context.Context, d *schema.ResourceData, meta interfac
183185
return diags
184186
}
185187

186-
func UpdateLibraryPanel(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
187-
client := meta.(*common.Client).GrafanaAPI
188-
uid := d.Id()
188+
func updateLibraryPanel(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
189+
client, _, uid := ClientFromOSSOrgID(meta, d.Id())
189190
panel := makeLibraryPanel(d)
190191

191192
resp, err := client.PatchLibraryPanel(uid, panel)
192193
if err != nil {
193194
return diag.FromErr(err)
194195
}
195-
d.SetId(resp.UID)
196-
d.Set("uid", resp.UID)
197-
return ReadLibraryPanel(ctx, d, meta)
196+
d.SetId(MakeOSSOrgID(resp.OrgID, resp.UID))
197+
return readLibraryPanel(ctx, d, meta)
198198
}
199199

200-
func DeleteLibraryPanel(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
201-
client := meta.(*common.Client).GrafanaAPI
202-
uid := d.Id()
200+
func deleteLibraryPanel(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
201+
client, _, uid := ClientFromOSSOrgID(meta, d.Id())
203202
_, err := client.DeleteLibraryPanel(uid)
204-
if err != nil {
205-
return diag.FromErr(err)
206-
}
207-
return nil
203+
return diag.FromErr(err)
208204
}
209205

210206
func makeLibraryPanel(d *schema.ResourceData) gapi.LibraryPanel {

0 commit comments

Comments
 (0)