Skip to content

Config Generation: Simplify listing of org resources #1693

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 17, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion internal/resources/grafana/common_lister.go
Original file line number Diff line number Diff line change
@@ -54,8 +54,11 @@ func (ld *ListerData) OrgIDs(client *goapi.GrafanaHTTPAPI) ([]int64, error) {
return ld.orgIDs, nil
}

type grafanaListerFunc func(ctx context.Context, client *goapi.GrafanaHTTPAPI, data *ListerData) ([]string, error)
type grafanaOrgResourceListerFunc func(ctx context.Context, client *goapi.GrafanaHTTPAPI, orgID int64) ([]string, error)

// listerFunction is a helper function that wraps a lister function be used more easily in grafana resources.
func listerFunction(listerFunc func(ctx context.Context, client *goapi.GrafanaHTTPAPI, data *ListerData) ([]string, error)) common.ResourceListIDsFunc {
func listerFunction(listerFunc grafanaListerFunc) common.ResourceListIDsFunc {
return func(ctx context.Context, client *common.Client, data any) ([]string, error) {
lm, ok := data.(*ListerData)
if !ok {
@@ -67,3 +70,23 @@ func listerFunction(listerFunc func(ctx context.Context, client *goapi.GrafanaHT
return listerFunc(ctx, client.GrafanaAPI, lm)
}
}

func listerFunctionOrgResource(listerFunc grafanaOrgResourceListerFunc) common.ResourceListIDsFunc {
return listerFunction(func(ctx context.Context, client *goapi.GrafanaHTTPAPI, data *ListerData) ([]string, error) {
orgIDs, err := data.OrgIDs(client)
if err != nil {
return nil, err
}

var ids []string
for _, orgID := range orgIDs {
idsInOrg, err := listerFunc(ctx, client.Clone().WithOrgID(orgID), orgID)
if err != nil {
return nil, err
}
ids = append(ids, idsInOrg...)
}

return ids, nil
})
}
41 changes: 16 additions & 25 deletions internal/resources/grafana/resource_alerting_message_template.go
Original file line number Diff line number Diff line change
@@ -66,37 +66,28 @@ This resource requires Grafana 9.1.0 or later.
"grafana_message_template",
orgResourceIDString("name"),
schema,
).WithLister(listerFunction(listMessageTemplate))
).WithLister(listerFunctionOrgResource(listMessageTemplate))
}

func listMessageTemplate(ctx context.Context, client *goapi.GrafanaHTTPAPI, data *ListerData) ([]string, error) {
orgIDs, err := data.OrgIDs(client)
if err != nil {
return nil, err
}

func listMessageTemplate(ctx context.Context, client *goapi.GrafanaHTTPAPI, orgID int64) ([]string, error) {
var ids []string
for _, orgID := range orgIDs {
client = client.Clone().WithOrgID(orgID)

// Retry if the API returns 500 because it may be that the alertmanager is not ready in the org yet.
// The alertmanager is provisioned asynchronously when the org is created.
if err := retry.RetryContext(ctx, 2*time.Minute, func() *retry.RetryError {
resp, err := client.Provisioning.GetTemplates()
if err != nil {
if orgID > 1 && (err.(*runtime.APIError).IsCode(500) || err.(*runtime.APIError).IsCode(403)) {
return retry.RetryableError(err)
}
return retry.NonRetryableError(err)
// Retry if the API returns 500 because it may be that the alertmanager is not ready in the org yet.
// The alertmanager is provisioned asynchronously when the org is created.
if err := retry.RetryContext(ctx, 2*time.Minute, func() *retry.RetryError {
resp, err := client.Provisioning.GetTemplates()
if err != nil {
if orgID > 1 && (err.(*runtime.APIError).IsCode(500) || err.(*runtime.APIError).IsCode(403)) {
return retry.RetryableError(err)
}
return retry.NonRetryableError(err)
}

for _, template := range resp.Payload {
ids = append(ids, MakeOrgResourceID(orgID, template.Name))
}
return nil
}); err != nil {
return nil, err
for _, template := range resp.Payload {
ids = append(ids, MakeOrgResourceID(orgID, template.Name))
}
return nil
}); err != nil {
return nil, err
}

return ids, nil
41 changes: 16 additions & 25 deletions internal/resources/grafana/resource_alerting_mute_timing.go
Original file line number Diff line number Diff line change
@@ -133,37 +133,28 @@ This resource requires Grafana 9.1.0 or later.
"grafana_mute_timing",
orgResourceIDString("name"),
schema,
).WithLister(listerFunction(listMuteTimings))
).WithLister(listerFunctionOrgResource(listMuteTimings))
}

func listMuteTimings(ctx context.Context, client *goapi.GrafanaHTTPAPI, data *ListerData) ([]string, error) {
orgIDs, err := data.OrgIDs(client)
if err != nil {
return nil, err
}

func listMuteTimings(ctx context.Context, client *goapi.GrafanaHTTPAPI, orgID int64) ([]string, error) {
var ids []string
for _, orgID := range orgIDs {
client = client.Clone().WithOrgID(orgID)

// Retry if the API returns 500 because it may be that the alertmanager is not ready in the org yet.
// The alertmanager is provisioned asynchronously when the org is created.
if err := retry.RetryContext(ctx, 2*time.Minute, func() *retry.RetryError {
resp, err := client.Provisioning.GetMuteTimings()
if err != nil {
if orgID > 1 && (err.(*runtime.APIError).IsCode(500) || err.(*runtime.APIError).IsCode(403)) {
return retry.RetryableError(err)
}
return retry.NonRetryableError(err)
// Retry if the API returns 500 because it may be that the alertmanager is not ready in the org yet.
// The alertmanager is provisioned asynchronously when the org is created.
if err := retry.RetryContext(ctx, 2*time.Minute, func() *retry.RetryError {
resp, err := client.Provisioning.GetMuteTimings()
if err != nil {
if orgID > 1 && (err.(*runtime.APIError).IsCode(500) || err.(*runtime.APIError).IsCode(403)) {
return retry.RetryableError(err)
}
return retry.NonRetryableError(err)
}

for _, muteTiming := range resp.Payload {
ids = append(ids, MakeOrgResourceID(orgID, muteTiming.Name))
}
return nil
}); err != nil {
return nil, err
for _, muteTiming := range resp.Payload {
ids = append(ids, MakeOrgResourceID(orgID, muteTiming.Name))
}
return nil
}); err != nil {
return nil, err
}

return ids, nil
Original file line number Diff line number Diff line change
@@ -91,7 +91,7 @@ This resource requires Grafana 9.1.0 or later.
"grafana_notification_policy",
orgResourceIDString("anyString"),
schema,
).WithLister(listerFunction(listNotificationPolicies))
).WithLister(listerFunctionOrgResource(listNotificationPolicies))
}

// The maximum depth of policy tree that the provider supports, as Terraform does not allow for infinitely recursive schemas.
@@ -191,35 +191,26 @@ func policySchema(depth uint) *schema.Resource {
return resource
}

func listNotificationPolicies(ctx context.Context, client *goapi.GrafanaHTTPAPI, data *ListerData) ([]string, error) {
orgIDs, err := data.OrgIDs(client)
if err != nil {
return nil, err
}

func listNotificationPolicies(ctx context.Context, client *goapi.GrafanaHTTPAPI, orgID int64) ([]string, error) {
var ids []string
for _, orgID := range orgIDs {
client = client.Clone().WithOrgID(orgID)

// Retry if the API returns 500 because it may be that the alertmanager is not ready in the org yet.
// The alertmanager is provisioned asynchronously when the org is created.
if err := retry.RetryContext(ctx, 2*time.Minute, func() *retry.RetryError {
_, err := client.Provisioning.GetPolicyTree()
if err != nil {
if orgID > 1 && (err.(*runtime.APIError).IsCode(500) || err.(*runtime.APIError).IsCode(403)) {
return retry.RetryableError(err)
}
return retry.NonRetryableError(err)
// Retry if the API returns 500 because it may be that the alertmanager is not ready in the org yet.
// The alertmanager is provisioned asynchronously when the org is created.
if err := retry.RetryContext(ctx, 2*time.Minute, func() *retry.RetryError {
_, err := client.Provisioning.GetPolicyTree()
if err != nil {
if orgID > 1 && (err.(*runtime.APIError).IsCode(500) || err.(*runtime.APIError).IsCode(403)) {
return retry.RetryableError(err)
}

return nil
}); err != nil {
return nil, err
return retry.NonRetryableError(err)
}

ids = append(ids, MakeOrgResourceID(orgID, PolicySingletonID))
return nil
}); err != nil {
return nil, err
}

ids = append(ids, MakeOrgResourceID(orgID, PolicySingletonID))

return ids, nil
}

41 changes: 16 additions & 25 deletions internal/resources/grafana/resource_alerting_rule_group.go
Original file line number Diff line number Diff line change
@@ -255,37 +255,28 @@ This resource requires Grafana 9.1.0 or later.
"grafana_rule_group",
resourceRuleGroupID,
schema,
).WithLister(listerFunction(listRuleGroups))
).WithLister(listerFunctionOrgResource(listRuleGroups))
}

func listRuleGroups(ctx context.Context, client *goapi.GrafanaHTTPAPI, data *ListerData) ([]string, error) {
orgIDs, err := data.OrgIDs(client)
if err != nil {
return nil, err
}

func listRuleGroups(ctx context.Context, client *goapi.GrafanaHTTPAPI, orgID int64) ([]string, error) {
idMap := map[string]bool{}
for _, orgID := range orgIDs {
client = client.Clone().WithOrgID(orgID)

// Retry if the API returns 500 because it may be that the alertmanager is not ready in the org yet.
// The alertmanager is provisioned asynchronously when the org is created.
if err := retry.RetryContext(ctx, 2*time.Minute, func() *retry.RetryError {
resp, err := client.Provisioning.GetAlertRules()
if err != nil {
if orgID > 1 && (err.(*runtime.APIError).IsCode(500) || err.(*runtime.APIError).IsCode(403)) {
return retry.RetryableError(err)
}
return retry.NonRetryableError(err)
// Retry if the API returns 500 because it may be that the alertmanager is not ready in the org yet.
// The alertmanager is provisioned asynchronously when the org is created.
if err := retry.RetryContext(ctx, 2*time.Minute, func() *retry.RetryError {
resp, err := client.Provisioning.GetAlertRules()
if err != nil {
if orgID > 1 && (err.(*runtime.APIError).IsCode(500) || err.(*runtime.APIError).IsCode(403)) {
return retry.RetryableError(err)
}
return retry.NonRetryableError(err)
}

for _, rule := range resp.Payload {
idMap[resourceRuleGroupID.Make(orgID, rule.FolderUID, rule.RuleGroup)] = true
}
return nil
}); err != nil {
return nil, err
for _, rule := range resp.Payload {
idMap[resourceRuleGroupID.Make(orgID, rule.FolderUID, rule.RuleGroup)] = true
}
return nil
}); err != nil {
return nil, err
}

var ids []string
21 changes: 6 additions & 15 deletions internal/resources/grafana/resource_annotation.go
Original file line number Diff line number Diff line change
@@ -84,27 +84,18 @@ func resourceAnnotation() *common.Resource {
"grafana_annotation",
orgResourceIDInt("id"),
schema,
).WithLister(listerFunction(listAnnotations))
).WithLister(listerFunctionOrgResource(listAnnotations))
}

func listAnnotations(ctx context.Context, client *goapi.GrafanaHTTPAPI, data *ListerData) ([]string, error) {
orgIDs, err := data.OrgIDs(client)
func listAnnotations(ctx context.Context, client *goapi.GrafanaHTTPAPI, orgID int64) ([]string, error) {
var ids []string
resp, err := client.Annotations.GetAnnotations(annotations.NewGetAnnotationsParams())
if err != nil {
return nil, err
}

var ids []string
for _, orgID := range orgIDs {
client = client.Clone().WithOrgID(orgID)

resp, err := client.Annotations.GetAnnotations(annotations.NewGetAnnotationsParams())
if err != nil {
return nil, err
}

for _, annotation := range resp.Payload {
ids = append(ids, MakeOrgResourceID(orgID, annotation.ID))
}
for _, annotation := range resp.Payload {
ids = append(ids, MakeOrgResourceID(orgID, annotation.ID))
}

return ids, nil
25 changes: 8 additions & 17 deletions internal/resources/grafana/resource_dashboard.go
Original file line number Diff line number Diff line change
@@ -99,31 +99,22 @@ Manages Grafana dashboards.
"grafana_dashboard",
orgResourceIDString("uid"),
schema,
).WithLister(listerFunction(listDashboards))
).WithLister(listerFunctionOrgResource(listDashboards))
}

func listDashboards(ctx context.Context, client *goapi.GrafanaHTTPAPI, data *ListerData) ([]string, error) {
return listDashboardOrFolder(client, data, "dash-db")
func listDashboards(ctx context.Context, client *goapi.GrafanaHTTPAPI, orgID int64) ([]string, error) {
return listDashboardOrFolder(client, orgID, "dash-db")
}

func listDashboardOrFolder(client *goapi.GrafanaHTTPAPI, data *ListerData, searchType string) ([]string, error) {
orgIDs, err := data.OrgIDs(client)
func listDashboardOrFolder(client *goapi.GrafanaHTTPAPI, orgID int64, searchType string) ([]string, error) {
uids := []string{}
resp, err := client.Search.Search(search.NewSearchParams().WithType(common.Ref(searchType)))
if err != nil {
return nil, err
}

uids := []string{}
for _, orgID := range orgIDs {
client = client.Clone().WithOrgID(orgID)

resp, err := client.Search.Search(search.NewSearchParams().WithType(common.Ref(searchType)))
if err != nil {
return nil, err
}

for _, item := range resp.Payload {
uids = append(uids, MakeOrgResourceID(orgID, item.UID))
}
for _, item := range resp.Payload {
uids = append(uids, MakeOrgResourceID(orgID, item.UID))
}

return uids, nil
24 changes: 8 additions & 16 deletions internal/resources/grafana/resource_data_source.go
Original file line number Diff line number Diff line change
@@ -114,7 +114,7 @@ source selected (via the 'type' argument).
"grafana_data_source",
orgResourceIDString("uid"),
schema,
).WithLister(listerFunction(listDatasources))
).WithLister(listerFunctionOrgResource(listDatasources))
}

func datasourceHTTPHeadersAttribute() *schema.Schema {
@@ -182,26 +182,18 @@ func datasourceSecureJSONDataAttribute() *schema.Schema {
}
}

func listDatasources(ctx context.Context, client *goapi.GrafanaHTTPAPI, data *ListerData) ([]string, error) {
orgIDs, err := data.OrgIDs(client)
func listDatasources(ctx context.Context, client *goapi.GrafanaHTTPAPI, orgID int64) ([]string, error) {
var ids []string
resp, err := client.Datasources.GetDataSources()
if err != nil {
return nil, err
}

var ids []string
for _, orgID := range orgIDs {
client = client.Clone().WithOrgID(orgID)
resp, err := client.Datasources.GetDataSources()
if err != nil {
return nil, err
}

for _, ds := range resp.Payload {
if ds.ReadOnly {
continue
}
ids = append(ids, MakeOrgResourceID(orgID, ds.UID))
for _, ds := range resp.Payload {
if ds.ReadOnly {
continue
}
ids = append(ids, MakeOrgResourceID(orgID, ds.UID))
}

return ids, nil
6 changes: 3 additions & 3 deletions internal/resources/grafana/resource_folder.go
Original file line number Diff line number Diff line change
@@ -78,11 +78,11 @@ func resourceFolder() *common.Resource {
"grafana_folder",
orgResourceIDString("uid"),
schema,
).WithLister(listerFunction(listFolders))
).WithLister(listerFunctionOrgResource(listFolders))
}

func listFolders(ctx context.Context, client *goapi.GrafanaHTTPAPI, data *ListerData) ([]string, error) {
return listDashboardOrFolder(client, data, "dash-folder")
func listFolders(ctx context.Context, client *goapi.GrafanaHTTPAPI, orgID int64) ([]string, error) {
return listDashboardOrFolder(client, orgID, "dash-folder")
}

func CreateFolder(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
Loading