Skip to content

Commit 2ab68d4

Browse files
Use the swagger-generated OpenAPI client for the Folder service (#1013)
* Replace manual Grafana client with OAPI-generated client for Folder service * Fetch orgID in Folder service * Add method for fetching OrgID with manual client to tests * Add folderUID to UpdateFolder cmd * Change 'access denied' test exp error to 403 * Add OrgID to client in dashboard test * Add validation for force deletion rule * Add retries to OAPI Client * Update OAPI client dependency to use retries * Update OAPI client dependency to use retries * Feature parity with old client * Oops. Upper case --------- Co-authored-by: Julien Duchesne <[email protected]>
1 parent 2988bb3 commit 2ab68d4

9 files changed

+114
-62
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ require (
99
github.com/go-openapi/strfmt v0.21.7
1010
github.com/grafana/amixr-api-go-client v0.0.10
1111
github.com/grafana/grafana-api-golang-client v0.24.0
12-
github.com/grafana/grafana-openapi-client-go v0.0.0-20230918131703-659d2cff09a7
12+
github.com/grafana/grafana-openapi-client-go v0.0.0-20231025152211-949fda3a17a0
1313
github.com/grafana/machine-learning-go-client v0.5.0
1414
github.com/grafana/synthetic-monitoring-agent v0.18.1
1515
github.com/grafana/synthetic-monitoring-api-go-client v0.7.0

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,8 @@ github.com/grafana/amixr-api-go-client v0.0.10 h1:L2Wc1aETiG7ORqmB+XSCBJdncHM/V0
146146
github.com/grafana/amixr-api-go-client v0.0.10/go.mod h1:N6x26XUrM5zGtK5zL5vNJnAn2JFMxLFPPLTw/6pDkFE=
147147
github.com/grafana/grafana-api-golang-client v0.24.0 h1:9cUvft7xCMnnL/Uscwy7eoldn16Gz5TH4T1MymuVs8E=
148148
github.com/grafana/grafana-api-golang-client v0.24.0/go.mod h1:24W29gPe9yl0/3A9X624TPkAOR8DpHno490cPwnkv8E=
149-
github.com/grafana/grafana-openapi-client-go v0.0.0-20230918131703-659d2cff09a7 h1:LPPNA/l6jCMRheMWvMPdni3WlOGL6Wjw3d/A1IbWCVg=
150-
github.com/grafana/grafana-openapi-client-go v0.0.0-20230918131703-659d2cff09a7/go.mod h1:2vJ8YEgriYoHaNg5eijRU/q7eJTxT078VrGRSTTLeRk=
149+
github.com/grafana/grafana-openapi-client-go v0.0.0-20231025152211-949fda3a17a0 h1:DeH1i5ORbYQnhlB2vpB4H5iSHrALPfDgr3qGx0uBApM=
150+
github.com/grafana/grafana-openapi-client-go v0.0.0-20231025152211-949fda3a17a0/go.mod h1:2vJ8YEgriYoHaNg5eijRU/q7eJTxT078VrGRSTTLeRk=
151151
github.com/grafana/machine-learning-go-client v0.5.0 h1:Q1K+MPSy8vfMm2jsk3WQ7O77cGr2fM5hxwtPSoPc5NU=
152152
github.com/grafana/machine-learning-go-client v0.5.0/go.mod h1:QFfZz8NkqVF8++skjkKQXJEZfpCYd8S0yTWJUpsLLTA=
153153
github.com/grafana/synthetic-monitoring-agent v0.18.1 h1:qQoxf4h+cUNxCtwgajehPp+4fGmRvoZubciIou1Ydw0=

internal/provider/provider.go

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -433,13 +433,23 @@ func createGrafanaOAPIClient(apiURL string, d *schema.ResourceData) (*goapi.Graf
433433
}
434434

435435
cfg := goapi.TransportConfig{
436-
Host: u.Host,
437-
BasePath: "/api",
438-
Schemes: []string{u.Scheme},
439-
TLSConfig: tlsClientConfig,
440-
BasicAuth: userInfo,
441-
OrgID: orgID,
442-
APIKey: APIKey,
436+
Host: u.Host,
437+
BasePath: "/api",
438+
Schemes: []string{u.Scheme},
439+
NumRetries: d.Get("retries").(int),
440+
RetryTimeout: time.Second * time.Duration(d.Get("retry_wait").(int)),
441+
TLSConfig: tlsClientConfig,
442+
BasicAuth: userInfo,
443+
OrgID: orgID,
444+
APIKey: APIKey,
445+
}
446+
447+
if v, ok := d.GetOk("retry_status_codes"); ok {
448+
cfg.RetryStatusCodes = common.SetToStringSlice(v.(*schema.Set))
449+
}
450+
451+
if cfg.HTTPHeaders, err = getHTTPHeadersMap(d); err != nil {
452+
return nil, err
443453
}
444454

445455
return goapi.NewHTTPClientWithConfig(strfmt.Default, &cfg), nil

internal/resources/grafana/data_source_folder_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"strings"
66
"testing"
77

8-
gapi "github.com/grafana/grafana-api-golang-client"
8+
goapi "github.com/grafana/grafana-openapi-client-go/models"
99
"github.com/grafana/terraform-provider-grafana/internal/common"
1010
"github.com/grafana/terraform-provider-grafana/internal/testutils"
1111
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
@@ -14,7 +14,7 @@ import (
1414
func TestAccDatasourceFolder(t *testing.T) {
1515
testutils.CheckOSSTestsEnabled(t)
1616

17-
var folder gapi.Folder
17+
var folder goapi.Folder
1818
checks := []resource.TestCheckFunc{
1919
testAccFolderCheckExists("grafana_folder.test", &folder),
2020
resource.TestCheckResourceAttr(

internal/resources/grafana/data_source_folders_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@ package grafana_test
33
import (
44
"testing"
55

6-
gapi "github.com/grafana/grafana-api-golang-client"
6+
goapi "github.com/grafana/grafana-openapi-client-go/models"
77
"github.com/grafana/terraform-provider-grafana/internal/testutils"
88
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
99
)
1010

1111
func TestAccDatasourceFolders(t *testing.T) {
1212
testutils.CheckOSSTestsEnabled(t)
1313

14-
var folderA gapi.Folder
15-
var folderB gapi.Folder
14+
var folderA goapi.Folder
15+
var folderB goapi.Folder
1616
titleBase := "test-folder-"
1717
uidBase := "test-ds-folder-uid-"
1818
checks := []resource.TestCheckFunc{

internal/resources/grafana/resource_dashboard_test.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"testing"
88

99
gapi "github.com/grafana/grafana-api-golang-client"
10+
goapi "github.com/grafana/grafana-openapi-client-go/models"
1011
"github.com/grafana/terraform-provider-grafana/internal/common"
1112
"github.com/grafana/terraform-provider-grafana/internal/resources/grafana"
1213
"github.com/grafana/terraform-provider-grafana/internal/testutils"
@@ -163,7 +164,7 @@ func TestAccDashboard_folder(t *testing.T) {
163164
testutils.CheckOSSTestsEnabled(t)
164165

165166
var dashboard gapi.Dashboard
166-
var folder gapi.Folder
167+
var folder goapi.Folder
167168

168169
resource.ParallelTest(t, resource.TestCase{
169170
ProviderFactories: testutils.ProviderFactories,
@@ -189,7 +190,7 @@ func TestAccDashboard_folder_uid(t *testing.T) {
189190
testutils.CheckOSSTestsSemver(t, ">=8.0.0") // UID in folders were added in v8
190191

191192
var dashboard gapi.Dashboard
192-
var folder gapi.Folder
193+
var folder goapi.Folder
193194

194195
resource.ParallelTest(t, resource.TestCase{
195196
ProviderFactories: testutils.ProviderFactories,
@@ -219,7 +220,7 @@ func TestAccDashboard_inOrg(t *testing.T) {
219220
testutils.CheckOSSTestsEnabled(t)
220221

221222
var dashboard gapi.Dashboard
222-
var folder gapi.Folder
223+
var folder goapi.Folder
223224
var org gapi.Org
224225

225226
orgName := acctest.RandString(10)
@@ -285,7 +286,7 @@ func testAccDashboardCheckExists(rn string, dashboard *gapi.Dashboard) resource.
285286
}
286287
}
287288

288-
func testAccDashboardCheckExistsInFolder(dashboard *gapi.Dashboard, folder *gapi.Folder) resource.TestCheckFunc {
289+
func testAccDashboardCheckExistsInFolder(dashboard *gapi.Dashboard, folder *goapi.Folder) resource.TestCheckFunc {
289290
return func(s *terraform.State) error {
290291
if dashboard.FolderID != folder.ID && folder.ID != 0 {
291292
return fmt.Errorf("dashboard.Folder(%d) does not match folder.ID(%d)", dashboard.FolderID, folder.ID)
@@ -298,6 +299,9 @@ func testAccDashboardCheckDestroy(dashboard *gapi.Dashboard, orgID int64) resour
298299
return func(s *terraform.State) error {
299300
// Check that the dashboard was deleted from the default organization
300301
client := testutils.Provider.Meta().(*common.Client).GrafanaAPI
302+
if dashboard.Model["uid"] == nil {
303+
return fmt.Errorf("dashboard UID should be string, not nil")
304+
}
301305
dashboard, err := client.DashboardByUID(dashboard.Model["uid"].(string))
302306
if dashboard != nil || err == nil {
303307
return fmt.Errorf("dashboard still exists")
@@ -316,14 +320,17 @@ func testAccDashboardCheckDestroy(dashboard *gapi.Dashboard, orgID int64) resour
316320
}
317321
}
318322

319-
func testAccDashboardFolderCheckDestroy(dashboard *gapi.Dashboard, folder *gapi.Folder) resource.TestCheckFunc {
323+
func testAccDashboardFolderCheckDestroy(dashboard *gapi.Dashboard, folder *goapi.Folder) resource.TestCheckFunc {
320324
return func(s *terraform.State) error {
321325
client := testutils.Provider.Meta().(*common.Client).GrafanaAPI
322326
_, err := client.DashboardByUID(dashboard.Model["uid"].(string))
323327
if err == nil {
324328
return fmt.Errorf("dashboard still exists")
325329
}
326-
folder, err = grafana.GetFolderByIDorUID(client, folder.UID)
330+
331+
orgID := testutils.Provider.Meta().(*common.Client).GrafanaAPIConfig.OrgID
332+
OAPIclient := testutils.Provider.Meta().(*common.Client).GrafanaOAPI.WithOrgID(orgID)
333+
folder, err = grafana.GetFolderByIDorUID(OAPIclient.Folders, folder.UID)
327334
if err == nil {
328335
return fmt.Errorf("the following folder still exists: %s", folder.Title)
329336
}

internal/resources/grafana/resource_folder.go

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import (
88
"strings"
99

1010
gapi "github.com/grafana/grafana-api-golang-client"
11+
goapi "github.com/grafana/grafana-openapi-client-go/client/folders"
12+
"github.com/grafana/grafana-openapi-client-go/models"
13+
1114
"github.com/grafana/terraform-provider-grafana/internal/common"
1215
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
1316
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -58,36 +61,51 @@ func ResourceFolder() *schema.Resource {
5861
}
5962

6063
func CreateFolder(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
61-
client, orgID := ClientFromNewOrgResource(meta, d)
64+
client, orgID := OAPIClientFromNewOrgResource(meta, d)
65+
66+
var body models.CreateFolderCommand
67+
if title := d.Get("title").(string); title != "" {
68+
body.Title = title
69+
}
6270

63-
var resp gapi.Folder
64-
var err error
65-
title := d.Get("title").(string)
6671
if uid, ok := d.GetOk("uid"); ok {
67-
resp, err = client.NewFolder(title, uid.(string))
68-
} else {
69-
resp, err = client.NewFolder(title)
72+
body.UID = uid.(string)
7073
}
74+
75+
params := goapi.NewCreateFolderParams().WithBody(&body)
76+
resp, err := client.Folders.CreateFolder(params, nil)
7177
if err != nil {
7278
return diag.Errorf("failed to create folder: %s", err)
7379
}
7480

75-
d.SetId(MakeOrgResourceID(orgID, resp.ID))
76-
d.Set("uid", resp.UID)
77-
d.Set("title", resp.Title)
81+
folder := resp.GetPayload()
82+
d.SetId(MakeOrgResourceID(orgID, folder.ID))
83+
d.Set("uid", folder.UID)
84+
d.Set("title", folder.Title)
7885

7986
return ReadFolder(ctx, d, meta)
8087
}
8188

8289
func UpdateFolder(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
83-
client, _, idStr := ClientFromExistingOrgResource(meta, d.Id())
90+
client, _, idStr := OAPIClientFromExistingOrgResource(meta, d.Id())
8491

85-
folder, err := GetFolderByIDorUID(client, idStr)
92+
folder, err := GetFolderByIDorUID(client.Folders, idStr)
8693
if err != nil {
8794
return diag.Errorf("failed to get folder %s: %s", idStr, err)
8895
}
8996

90-
if err := client.UpdateFolder(folder.UID, d.Get("title").(string), d.Get("uid").(string)); err != nil {
97+
params := goapi.NewUpdateFolderParams().
98+
WithBody(&models.UpdateFolderCommand{
99+
Overwrite: true,
100+
Title: d.Get("title").(string),
101+
}).
102+
WithFolderUID(folder.UID)
103+
104+
if newUID := d.Get("uid").(string); newUID != "" {
105+
params.Body.UID = newUID
106+
}
107+
108+
if _, err := client.Folders.UpdateFolder(params, nil); err != nil {
91109
return diag.FromErr(err)
92110
}
93111

@@ -96,9 +114,9 @@ func UpdateFolder(ctx context.Context, d *schema.ResourceData, meta interface{})
96114

97115
func ReadFolder(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
98116
gapiURL := meta.(*common.Client).GrafanaAPIURL
99-
client, orgID, idStr := ClientFromExistingOrgResource(meta, d.Id())
117+
client, orgID, idStr := OAPIClientFromExistingOrgResource(meta, d.Id())
100118

101-
folder, err := GetFolderByIDorUID(client, idStr)
119+
folder, err := GetFolderByIDorUID(client.Folders, idStr)
102120
if err, shouldReturn := common.CheckReadError("folder", d, err); shouldReturn {
103121
return err
104122
}
@@ -113,12 +131,11 @@ func ReadFolder(ctx context.Context, d *schema.ResourceData, meta interface{}) d
113131
}
114132

115133
func DeleteFolder(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
116-
client, _, idStr := ClientFromExistingOrgResource(meta, d.Id())
117-
118134
deleteParams := []url.Values{}
119135
if d.Get("prevent_destroy_if_not_empty").(bool) {
120136
// Search for dashboards and fail if any are found
121-
dashboards, err := client.FolderDashboardSearch(url.Values{
137+
GAPIClient, _, idStr := ClientFromExistingOrgResource(meta, d.Id())
138+
dashboards, err := GAPIClient.FolderDashboardSearch(url.Values{
122139
"type": []string{"dash-db"},
123140
"folderIds": []string{idStr},
124141
})
@@ -137,7 +154,14 @@ func DeleteFolder(ctx context.Context, d *schema.ResourceData, meta interface{})
137154
deleteParams = append(deleteParams, gapi.ForceDeleteFolderRules())
138155
}
139156

140-
if err := client.DeleteFolder(d.Get("uid").(string), deleteParams...); err != nil {
157+
var force bool
158+
if len(deleteParams) > 0 {
159+
force, _ = strconv.ParseBool(deleteParams[0].Get("forceDeleteRules"))
160+
}
161+
162+
client, _, _ := OAPIClientFromExistingOrgResource(meta, d.Id())
163+
params := goapi.NewDeleteFolderParams().WithForceDeleteRules(&force).WithFolderUID(d.Get("uid").(string))
164+
if _, err := client.Folders.DeleteFolder(params, nil); err != nil {
141165
return diag.Errorf("failed to delete folder: %s", err)
142166
}
143167

@@ -178,16 +202,17 @@ func NormalizeFolderConfigJSON(configI interface{}) string {
178202
return string(ret)
179203
}
180204

181-
func GetFolderByIDorUID(client *gapi.Client, id string) (*gapi.Folder, error) {
205+
func GetFolderByIDorUID(client goapi.ClientService, id string) (*models.Folder, error) {
182206
// If the ID is a number, find the folder UID
183207
// Getting the folder by ID is broken in some versions, but getting by UID works in all versions
184208
// We need to use two API calls in the numerical ID case, because the "list" call doesn't have all the info
185209
uid := id
186210
if numericalID, err := strconv.ParseInt(id, 10, 64); err == nil {
187-
folders, err := client.Folders()
211+
resp, err := client.GetFolders(goapi.NewGetFoldersParams(), nil)
188212
if err != nil {
189213
return nil, err
190214
}
215+
folders := resp.GetPayload()
191216
for _, folder := range folders {
192217
if folder.ID == numericalID {
193218
uid = folder.UID
@@ -196,5 +221,10 @@ func GetFolderByIDorUID(client *gapi.Client, id string) (*gapi.Folder, error) {
196221
}
197222
}
198223

199-
return client.FolderByUID(uid)
224+
params := goapi.NewGetFolderByUIDParams().WithFolderUID(uid)
225+
resp, err := client.GetFolderByUID(params, nil)
226+
if err != nil {
227+
return nil, err
228+
}
229+
return resp.GetPayload(), nil
200230
}

0 commit comments

Comments
 (0)