Skip to content

Commit

Permalink
Folder datasource fixes
Browse files Browse the repository at this point in the history
- Make the nested folders tests run in OSS, not in the cloud instance
- Build the folder datasource from the folder resource's schema, rather than duplicating things
- (bugfix) Use the search API rather than the get folders API, it seems that the latter does not return nested folders
  • Loading branch information
julienduchesne committed Mar 13, 2024
1 parent 156841e commit f62460b
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 46 deletions.
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ services:
- GF_SERVER_ROOT_URL=${GRAFANA_URL}
- GF_ENTERPRISE_LICENSE_TEXT=${GF_ENTERPRISE_LICENSE_TEXT:-}
- GF_SERVER_SERVE_FROM_SUB_PATH=${GF_SERVER_SERVE_FROM_SUB_PATH:-}
- GF_FEATURE_TOGGLES_ENABLE=nestedFolders
healthcheck:
test: wget --no-verbose --tries=1 --spider http://0.0.0.0:3000/api/health || exit 1 # Use wget because older versions of Grafana don't have curl
interval: 10s
Expand Down
7 changes: 4 additions & 3 deletions docs/data-sources/folder.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,15 @@ data "grafana_folder" "from_title" {

### Required

- `title` (String) The name of the Grafana folder.
- `title` (String) The title of the folder.

### Optional

- `org_id` (String) The Organization ID. If not set, the Org ID defined in the provider block will be used.

### Read-Only

- `id` (Number) The numerical ID of the Grafana folder.
- `uid` (String) The uid of the Grafana folder.
- `id` (String) The ID of this resource.
- `parent_folder_uid` (String) The uid of the parent folder. If set, the folder will be nested. If not set, the folder will be created in the root folder. Note: This requires the nestedFolders feature flag to be enabled on your Grafana instance.
- `uid` (String) Unique identifier.
- `url` (String) The full URL of the folder.
56 changes: 14 additions & 42 deletions internal/resources/grafana/data_source_folder.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@ package grafana
import (
"context"
"fmt"
"strconv"

goapi "github.com/grafana/grafana-openapi-client-go/client"
"github.com/grafana/grafana-openapi-client-go/client/folders"
"github.com/grafana/grafana-openapi-client-go/models"
"github.com/grafana/grafana-openapi-client-go/client/search"
"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"
Expand All @@ -20,53 +18,35 @@ func DatasourceFolder() *schema.Resource {
* [HTTP API](https://grafana.com/docs/grafana/latest/developers/http_api/folder/)
`,
ReadContext: dataSourceFolderRead,
Schema: map[string]*schema.Schema{
Schema: common.CloneResourceSchemaForDatasource(ResourceFolder(), map[string]*schema.Schema{
"org_id": orgIDAttribute(),
"title": {
Type: schema.TypeString,
Required: true,
Description: "The name of the Grafana folder.",
Description: "The title of the folder.",
},
"id": {
Type: schema.TypeInt,
Computed: true,
Description: "The numerical ID of the Grafana folder.",
},
"uid": {
Type: schema.TypeString,
Computed: true,
Description: "The uid of the Grafana folder.",
},
"url": {
Type: schema.TypeString,
Computed: true,
Description: "The full URL of the folder.",
},
},
"prevent_destroy_if_not_empty": nil,
}),
}
}

func findFolderWithTitle(client *goapi.GrafanaHTTPAPI, title string) (*models.Folder, error) {
func findFolderWithTitle(client *goapi.GrafanaHTTPAPI, title string) (string, error) {
var page int64 = 1

for {
params := folders.NewGetFoldersParams().WithPage(&page)
resp, err := client.Folders.GetFolders(params)
params := search.NewSearchParams().WithType(common.Ref("dash-folder")).WithPage(&page)
resp, err := client.Search.Search(params)
if err != nil {
return nil, err
return "", err
}

if len(resp.Payload) == 0 {
return nil, fmt.Errorf("folder with title %s not found", title)
return "", fmt.Errorf("folder with title %s not found", title)
}

for _, folder := range resp.Payload {
if folder.Title == title {
resp, err := client.Folders.GetFolderByUID(folder.UID)
if err != nil {
return nil, err
}
return resp.Payload, nil
return folder.UID, nil
}
}

Expand All @@ -75,19 +55,11 @@ func findFolderWithTitle(client *goapi.GrafanaHTTPAPI, title string) (*models.Fo
}

func dataSourceFolderRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
metaClient := meta.(*common.Client)
client, orgID := OAPIClientFromNewOrgResource(meta, d)

folder, err := findFolderWithTitle(client, d.Get("title").(string))
uid, err := findFolderWithTitle(client, d.Get("title").(string))
if err != nil {
return diag.FromErr(err)
}

d.SetId(strconv.FormatInt(folder.ID, 10))
d.Set("org_id", strconv.FormatInt(orgID, 10))
d.Set("uid", folder.UID)
d.Set("title", folder.Title)
d.Set("url", metaClient.GrafanaSubpath(folder.URL))

return nil
d.SetId(MakeOrgResourceID(orgID, uid))
return ReadFolder(ctx, d, meta)
}
59 changes: 59 additions & 0 deletions internal/resources/grafana/data_source_folder_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package grafana_test

import (
"fmt"
"os"
"strings"
"testing"

"github.com/grafana/grafana-openapi-client-go/models"
"github.com/grafana/terraform-provider-grafana/internal/common"
"github.com/grafana/terraform-provider-grafana/internal/testutils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

Expand Down Expand Up @@ -42,3 +44,60 @@ func TestAccDatasourceFolder_basic(t *testing.T) {
},
})
}

func TestAccDatasourceFolder_nested(t *testing.T) {
testutils.CheckOSSTestsEnabled(t, ">=10.3.0")

var parent models.Folder
var child models.Folder
randomName := acctest.RandStringFromCharSet(6, acctest.CharSetAlpha)

resource.ParallelTest(t, resource.TestCase{
ProviderFactories: testutils.ProviderFactories,
CheckDestroy: resource.ComposeTestCheckFunc(
folderCheckExists.destroyed(&parent, nil),
folderCheckExists.destroyed(&child, nil),
),
Steps: []resource.TestStep{
{
Config: testNestedFolderData(randomName),
Check: resource.ComposeTestCheckFunc(
folderCheckExists.exists("grafana_folder.parent", &parent),
folderCheckExists.exists("grafana_folder.child", &child),
resource.TestCheckResourceAttr("data.grafana_folder.parent", "title", randomName),
resource.TestCheckResourceAttr("data.grafana_folder.parent", "uid", randomName),
resource.TestMatchResourceAttr("data.grafana_folder.parent", "id", defaultOrgIDRegexp),
resource.TestCheckResourceAttr("data.grafana_folder.parent", "parent_folder_uid", ""),

resource.TestCheckResourceAttr("data.grafana_folder.child", "title", randomName+"-child"),
resource.TestCheckResourceAttr("data.grafana_folder.child", "uid", randomName+"-child"),
resource.TestMatchResourceAttr("data.grafana_folder.child", "id", defaultOrgIDRegexp),
resource.TestCheckResourceAttr("data.grafana_folder.child", "parent_folder_uid", randomName),
),
},
},
})
}

func testNestedFolderData(name string) string {
return fmt.Sprintf(`
resource "grafana_folder" "parent" {
title = "%[1]s"
uid = "%[1]s"
}
resource "grafana_folder" "child" {
title = "%[1]s-child"
uid = "%[1]s-child"
parent_folder_uid = grafana_folder.parent.uid
}
data "grafana_folder" "parent" {
title = grafana_folder.parent.title
}
data "grafana_folder" "child" {
title = grafana_folder.child.title
}
`, name)
}
2 changes: 1 addition & 1 deletion internal/resources/grafana/resource_folder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func TestAccFolder_basic(t *testing.T) {
}

func TestAccFolder_nested(t *testing.T) {
testutils.CheckCloudInstanceTestsEnabled(t) // TODO: Switch to OSS once nested folders are enabled by default
testutils.CheckOSSTestsEnabled(t, ">=10.3.0")

var parentFolder models.Folder
var childFolder1 models.Folder
Expand Down

0 comments on commit f62460b

Please sign in to comment.