diff --git a/internal/provider/legacy_provider.go b/internal/provider/legacy_provider.go index 0ab70683f..ab5ce9b68 100644 --- a/internal/provider/legacy_provider.go +++ b/internal/provider/legacy_provider.go @@ -85,19 +85,6 @@ func Provider(version string) *schema.Provider { "grafana_synthetic_monitoring_probe": syntheticmonitoring.ResourceProbe(), }) - // Resources that require the Cloud client to exist. - cloudClientResources = addResourcesMetadataValidation(cloudClientPresent, map[string]*schema.Resource{ - "grafana_cloud_access_policy": cloud.ResourceAccessPolicy(), - "grafana_cloud_access_policy_token": cloud.ResourceAccessPolicyToken(), - "grafana_cloud_api_key": cloud.ResourceAPIKey(), - "grafana_cloud_plugin_installation": cloud.ResourcePluginInstallation(), - "grafana_cloud_stack": cloud.ResourceStack(), - "grafana_cloud_stack_api_key": cloud.ResourceStackAPIKey(), - "grafana_cloud_stack_service_account": cloud.ResourceStackServiceAccount(), - "grafana_cloud_stack_service_account_token": cloud.ResourceStackServiceAccountToken(), - "grafana_synthetic_monitoring_installation": cloud.ResourceInstallation(), - }) - // Resources that require the OnCall client to exist. onCallClientResources = addResourcesMetadataValidation(onCallClientPresent, map[string]*schema.Resource{ "grafana_oncall_integration": oncall.ResourceIntegration(), @@ -138,13 +125,6 @@ func Provider(version string) *schema.Provider { "grafana_synthetic_monitoring_probes": syntheticmonitoring.DataSourceProbes(), }) - // Datasources that require the Cloud client to exist. - cloudClientDatasources = addResourcesMetadataValidation(cloudClientPresent, map[string]*schema.Resource{ - "grafana_cloud_ips": cloud.DataSourceIPs(), - "grafana_cloud_organization": cloud.DataSourceOrganization(), - "grafana_cloud_stack": cloud.DataSourceStack(), - }) - // Datasources that require the OnCall client to exist. onCallClientDatasources = addResourcesMetadataValidation(onCallClientPresent, map[string]*schema.Resource{ "grafana_oncall_user": oncall.DataSourceUser(), @@ -279,14 +259,14 @@ func Provider(version string) *schema.Provider { grafanaClientResources, smClientResources, onCallClientResources, - cloudClientResources, + cloud.ResourcesMap, ), DataSourcesMap: mergeResourceMaps( grafanaClientDatasources, smClientDatasources, onCallClientDatasources, - cloudClientDatasources, + cloud.DatasourcesMap, ), } diff --git a/internal/provider/legacy_provider_validation.go b/internal/provider/legacy_provider_validation.go index 59c181277..f99fcf371 100644 --- a/internal/provider/legacy_provider_validation.go +++ b/internal/provider/legacy_provider_validation.go @@ -42,13 +42,6 @@ func smClientPresent(resourceName string, d *schema.ResourceData, m interface{}) return nil } -func cloudClientPresent(resourceName string, d *schema.ResourceData, m interface{}) error { - if m.(*common.Client).GrafanaCloudAPI == nil { - return fmt.Errorf("the Cloud API client is required for `%s`. Set the cloud_api_key provider attribute", resourceName) - } - return nil -} - func onCallClientPresent(resourceName string, d *schema.ResourceData, m interface{}) error { if m.(*common.Client).OnCallClient == nil { return fmt.Errorf("the Oncall client is required for `%s`. Set the oncall_access_token provider attribute", resourceName) diff --git a/internal/resources/cloud/common.go b/internal/resources/cloud/common.go index e64e76d71..6b1357c34 100644 --- a/internal/resources/cloud/common.go +++ b/internal/resources/cloud/common.go @@ -1,9 +1,13 @@ package cloud import ( + "context" + "github.com/grafana/grafana-com-public-clients/go/gcom" + "github.com/grafana/terraform-provider-grafana/internal/common" "github.com/hashicorp/go-uuid" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) func ClientRequestID() string { @@ -14,6 +18,18 @@ func ClientRequestID() string { return "tf-" + uuid } +type crudWithClientFunc func(ctx context.Context, d *schema.ResourceData, client *gcom.APIClient) diag.Diagnostics + +func withClient[T schema.CreateContextFunc | schema.UpdateContextFunc | schema.ReadContextFunc | schema.DeleteContextFunc](f crudWithClientFunc) T { + return func(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*common.Client).GrafanaCloudAPI + if client == nil { + return diag.Errorf("the Cloud API client is required for this resource. Set the cloud_access_policy_token provider attribute") + } + return f(ctx, d, client) + } +} + func apiError(err error) diag.Diagnostics { if err == nil { return nil diff --git a/internal/resources/cloud/data_source_cloud_ips.go b/internal/resources/cloud/data_source_cloud_ips.go index 6b0b5493e..6b10183d1 100644 --- a/internal/resources/cloud/data_source_cloud_ips.go +++ b/internal/resources/cloud/data_source_cloud_ips.go @@ -10,10 +10,10 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func DataSourceIPs() *schema.Resource { +func datasourceIPs() *schema.Resource { return &schema.Resource{ Description: "Data source for retrieving sets of cloud IPs. See https://grafana.com/docs/grafana-cloud/reference/allow-list/ for more info", - ReadContext: DataSourceIPsRead, + ReadContext: datasourceIPsRead, Schema: map[string]*schema.Schema{ "hosted_alerts": { Description: "Set of IP addresses that are used for hosted alerts.", @@ -59,7 +59,7 @@ func DataSourceIPs() *schema.Resource { } } -func DataSourceIPsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func datasourceIPsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { d.SetId("cloud_ips") for attr, dataURL := range map[string]string{ "hosted_alerts": "https://grafana.com/api/hosted-alerts/source-ips.txt", diff --git a/internal/resources/cloud/data_source_cloud_organization.go b/internal/resources/cloud/data_source_cloud_organization.go index c1ca0b45b..1deda7978 100644 --- a/internal/resources/cloud/data_source_cloud_organization.go +++ b/internal/resources/cloud/data_source_cloud_organization.go @@ -4,14 +4,14 @@ import ( "context" "strconv" - "github.com/grafana/terraform-provider-grafana/internal/common" + "github.com/grafana/grafana-com-public-clients/go/gcom" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func DataSourceOrganization() *schema.Resource { +func datasourceOrganization() *schema.Resource { return &schema.Resource{ - ReadContext: DataSourceOrganizationRead, + ReadContext: withClient[schema.ReadContextFunc](datasourceOrganizationRead), Schema: map[string]*schema.Schema{ "id": { Type: schema.TypeString, @@ -43,9 +43,7 @@ func DataSourceOrganization() *schema.Resource { } } -func DataSourceOrganizationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*common.Client).GrafanaCloudAPI - +func datasourceOrganizationRead(ctx context.Context, d *schema.ResourceData, client *gcom.APIClient) diag.Diagnostics { id := d.Get("id").(string) if id == "" { id = d.Get("slug").(string) diff --git a/internal/resources/cloud/data_source_cloud_stack.go b/internal/resources/cloud/data_source_cloud_stack.go index 91305c2b9..4b19691c4 100644 --- a/internal/resources/cloud/data_source_cloud_stack.go +++ b/internal/resources/cloud/data_source_cloud_stack.go @@ -3,16 +3,17 @@ package cloud import ( "context" + "github.com/grafana/grafana-com-public-clients/go/gcom" "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 DataSourceStack() *schema.Resource { +func datasourceStack() *schema.Resource { return &schema.Resource{ Description: "Data source for Grafana Stack", - ReadContext: DataSourceStackRead, - Schema: common.CloneResourceSchemaForDatasource(ResourceStack(), map[string]*schema.Schema{ + ReadContext: withClient[schema.ReadContextFunc](datasourceStackRead), + Schema: common.CloneResourceSchemaForDatasource(resourceStack(), map[string]*schema.Schema{ "slug": { Type: schema.TypeString, Required: true, @@ -31,7 +32,7 @@ available at “https://.grafana.net".`, } } -func DataSourceStackRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func datasourceStackRead(ctx context.Context, d *schema.ResourceData, client *gcom.APIClient) diag.Diagnostics { d.SetId(d.Get("slug").(string)) - return ReadStack(ctx, d, meta) + return readStack(ctx, d, client) } diff --git a/internal/resources/cloud/resource_cloud_access_policy.go b/internal/resources/cloud/resource_cloud_access_policy.go index 3100b4da7..160d5b62d 100644 --- a/internal/resources/cloud/resource_cloud_access_policy.go +++ b/internal/resources/cloud/resource_cloud_access_policy.go @@ -15,7 +15,7 @@ import ( var ResourceAccessPolicyID = common.NewResourceIDWithLegacySeparator("grafana_cloud_access_policy", "/", "region", "policyId") //nolint:staticcheck -func ResourceAccessPolicy() *schema.Resource { +func resourceAccessPolicy() *schema.Resource { return &schema.Resource{ Description: ` @@ -29,10 +29,10 @@ Required access policy scopes: * accesspolicies:delete `, - CreateContext: CreateCloudAccessPolicy, - UpdateContext: UpdateCloudAccessPolicy, - DeleteContext: DeleteCloudAccessPolicy, - ReadContext: ReadCloudAccessPolicy, + CreateContext: withClient[schema.CreateContextFunc](createCloudAccessPolicy), + UpdateContext: withClient[schema.UpdateContextFunc](updateCloudAccessPolicy), + DeleteContext: withClient[schema.DeleteContextFunc](deleteCloudAccessPolicy), + ReadContext: withClient[schema.ReadContextFunc](readCloudAccessPolicy), Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, @@ -126,8 +126,7 @@ var cloudAccessPolicyRealmSchema = &schema.Resource{ }, } -func CreateCloudAccessPolicy(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*common.Client).GrafanaCloudAPI +func createCloudAccessPolicy(ctx context.Context, d *schema.ResourceData, client *gcom.APIClient) diag.Diagnostics { region := d.Get("region").(string) displayName := d.Get("display_name").(string) @@ -149,12 +148,10 @@ func CreateCloudAccessPolicy(ctx context.Context, d *schema.ResourceData, meta i d.SetId(ResourceAccessPolicyID.Make(region, result.Id)) - return ReadCloudAccessPolicy(ctx, d, meta) + return readCloudAccessPolicy(ctx, d, client) } -func UpdateCloudAccessPolicy(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*common.Client).GrafanaCloudAPI - +func updateCloudAccessPolicy(ctx context.Context, d *schema.ResourceData, client *gcom.APIClient) diag.Diagnostics { split, err := ResourceAccessPolicyID.Split(d.Id()) if err != nil { return diag.FromErr(err) @@ -176,12 +173,10 @@ func UpdateCloudAccessPolicy(ctx context.Context, d *schema.ResourceData, meta i return apiError(err) } - return ReadCloudAccessPolicy(ctx, d, meta) + return readCloudAccessPolicy(ctx, d, client) } -func ReadCloudAccessPolicy(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*common.Client).GrafanaCloudAPI - +func readCloudAccessPolicy(ctx context.Context, d *schema.ResourceData, client *gcom.APIClient) diag.Diagnostics { split, err := ResourceAccessPolicyID.Split(d.Id()) if err != nil { return diag.FromErr(err) @@ -208,9 +203,7 @@ func ReadCloudAccessPolicy(ctx context.Context, d *schema.ResourceData, meta int return nil } -func DeleteCloudAccessPolicy(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*common.Client).GrafanaCloudAPI - +func deleteCloudAccessPolicy(ctx context.Context, d *schema.ResourceData, client *gcom.APIClient) diag.Diagnostics { split, err := ResourceAccessPolicyID.Split(d.Id()) if err != nil { return diag.FromErr(err) diff --git a/internal/resources/cloud/resource_cloud_access_policy_token.go b/internal/resources/cloud/resource_cloud_access_policy_token.go index b98c21ff6..cec946775 100644 --- a/internal/resources/cloud/resource_cloud_access_policy_token.go +++ b/internal/resources/cloud/resource_cloud_access_policy_token.go @@ -13,7 +13,7 @@ import ( var ResourceAccessPolicyTokenID = common.NewResourceIDWithLegacySeparator("grafana_cloud_access_policy_token", "/", "region", "tokenId") //nolint:staticcheck -func ResourceAccessPolicyToken() *schema.Resource { +func resourceAccessPolicyToken() *schema.Resource { return &schema.Resource{ Description: ` @@ -27,10 +27,10 @@ Required access policy scopes: * accesspolicies:delete `, - CreateContext: CreateCloudAccessPolicyToken, - UpdateContext: UpdateCloudAccessPolicyToken, - DeleteContext: DeleteCloudAccessPolicyToken, - ReadContext: ReadCloudAccessPolicyToken, + CreateContext: withClient[schema.CreateContextFunc](createCloudAccessPolicyToken), + UpdateContext: withClient[schema.UpdateContextFunc](updateCloudAccessPolicyToken), + DeleteContext: withClient[schema.DeleteContextFunc](deleteCloudAccessPolicyToken), + ReadContext: withClient[schema.ReadContextFunc](readCloudAccessPolicyToken), Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, @@ -94,8 +94,7 @@ Required access policy scopes: } } -func CreateCloudAccessPolicyToken(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*common.Client).GrafanaCloudAPI +func createCloudAccessPolicyToken(ctx context.Context, d *schema.ResourceData, client *gcom.APIClient) diag.Diagnostics { region := d.Get("region").(string) tokenInput := gcom.PostTokensRequest{ @@ -121,12 +120,10 @@ func CreateCloudAccessPolicyToken(ctx context.Context, d *schema.ResourceData, m d.SetId(ResourceAccessPolicyTokenID.Make(region, result.Id)) d.Set("token", result.Token) - return ReadCloudAccessPolicyToken(ctx, d, meta) + return readCloudAccessPolicyToken(ctx, d, client) } -func UpdateCloudAccessPolicyToken(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*common.Client).GrafanaCloudAPI - +func updateCloudAccessPolicyToken(ctx context.Context, d *schema.ResourceData, client *gcom.APIClient) diag.Diagnostics { split, err := ResourceAccessPolicyTokenID.Split(d.Id()) if err != nil { return diag.FromErr(err) @@ -145,12 +142,10 @@ func UpdateCloudAccessPolicyToken(ctx context.Context, d *schema.ResourceData, m return apiError(err) } - return ReadCloudAccessPolicyToken(ctx, d, meta) + return readCloudAccessPolicyToken(ctx, d, client) } -func ReadCloudAccessPolicyToken(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*common.Client).GrafanaCloudAPI - +func readCloudAccessPolicyToken(ctx context.Context, d *schema.ResourceData, client *gcom.APIClient) diag.Diagnostics { split, err := ResourceAccessPolicyTokenID.Split(d.Id()) if err != nil { return diag.FromErr(err) @@ -178,9 +173,7 @@ func ReadCloudAccessPolicyToken(ctx context.Context, d *schema.ResourceData, met return nil } -func DeleteCloudAccessPolicyToken(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*common.Client).GrafanaCloudAPI - +func deleteCloudAccessPolicyToken(ctx context.Context, d *schema.ResourceData, client *gcom.APIClient) diag.Diagnostics { split, err := ResourceAccessPolicyTokenID.Split(d.Id()) if err != nil { return diag.FromErr(err) diff --git a/internal/resources/cloud/resource_cloud_api_key.go b/internal/resources/cloud/resource_cloud_api_key.go index 566e27eef..a3875c765 100644 --- a/internal/resources/cloud/resource_cloud_api_key.go +++ b/internal/resources/cloud/resource_cloud_api_key.go @@ -14,7 +14,7 @@ import ( var ResourceAPIKeyID = common.NewResourceIDWithLegacySeparator("grafana_cloud_api_key", "-", "orgSlug", "apiKeyName") //nolint:staticcheck var cloudAPIKeyRoles = []string{"Viewer", "Editor", "Admin", "MetricsPublisher", "PluginPublisher"} -func ResourceAPIKey() *schema.Resource { +func resourceAPIKey() *schema.Resource { return &schema.Resource{ Description: `This resource is deprecated and will be removed in a future release. Please use grafana_cloud_access_policy instead. @@ -27,9 +27,9 @@ Required access policy scopes: * api-keys:write * api-keys:delete `, - CreateContext: ResourceAPIKeyCreate, - ReadContext: ResourceAPIKeyRead, - DeleteContext: ResourceAPIKeyDelete, + CreateContext: withClient[schema.CreateContextFunc](resourceAPIKeyCreate), + ReadContext: withClient[schema.ReadContextFunc](resourceAPIKeyRead), + DeleteContext: withClient[schema.DeleteContextFunc](resourceAPIKeyDelete), Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, @@ -65,9 +65,7 @@ Required access policy scopes: } } -func ResourceAPIKeyCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - c := meta.(*common.Client).GrafanaCloudAPI - +func resourceAPIKeyCreate(ctx context.Context, d *schema.ResourceData, c *gcom.APIClient) diag.Diagnostics { req := gcom.PostApiKeysRequest{ Name: d.Get("name").(string), Role: d.Get("role").(string), @@ -85,12 +83,10 @@ func ResourceAPIKeyCreate(ctx context.Context, d *schema.ResourceData, meta inte d.Set("key", *resp.Token) d.SetId(ResourceAPIKeyID.Make(org, resp.Name)) - return ResourceAPIKeyRead(ctx, d, meta) + return resourceAPIKeyRead(ctx, d, c) } -func ResourceAPIKeyRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - c := meta.(*common.Client).GrafanaCloudAPI - +func resourceAPIKeyRead(ctx context.Context, d *schema.ResourceData, c *gcom.APIClient) diag.Diagnostics { split, err := ResourceAPIKeyID.Split(d.Id()) if err != nil { return diag.FromErr(err) @@ -110,9 +106,7 @@ func ResourceAPIKeyRead(ctx context.Context, d *schema.ResourceData, meta interf return nil } -func ResourceAPIKeyDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - c := meta.(*common.Client).GrafanaCloudAPI - +func resourceAPIKeyDelete(ctx context.Context, d *schema.ResourceData, c *gcom.APIClient) diag.Diagnostics { split, err := ResourceAPIKeyID.Split(d.Id()) if err != nil { return diag.FromErr(err) diff --git a/internal/resources/cloud/resource_cloud_plugin.go b/internal/resources/cloud/resource_cloud_plugin.go index be5b3fdf9..1b46e557c 100644 --- a/internal/resources/cloud/resource_cloud_plugin.go +++ b/internal/resources/cloud/resource_cloud_plugin.go @@ -11,7 +11,7 @@ import ( var ResourcePluginInstallationID = common.NewResourceIDWithLegacySeparator("grafana_cloud_plugin_installation", "_", "stackSlug", "pluginSlug") //nolint:staticcheck -func ResourcePluginInstallation() *schema.Resource { +func resourcePluginInstallation() *schema.Resource { return &schema.Resource{ Description: ` Manages Grafana Cloud Plugin Installations. @@ -44,19 +44,17 @@ Required access policy scopes: ForceNew: true, }, }, - CreateContext: ResourcePluginInstallationCreate, - ReadContext: ResourcePluginInstallationRead, + CreateContext: withClient[schema.CreateContextFunc](resourcePluginInstallationCreate), + ReadContext: withClient[schema.ReadContextFunc](resourcePluginInstallationRead), UpdateContext: nil, - DeleteContext: ResourcePluginInstallationDelete, + DeleteContext: withClient[schema.DeleteContextFunc](resourcePluginInstallationDelete), Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, } } -func ResourcePluginInstallationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*common.Client).GrafanaCloudAPI - +func resourcePluginInstallationCreate(ctx context.Context, d *schema.ResourceData, client *gcom.APIClient) diag.Diagnostics { stackSlug := d.Get("stack_slug").(string) pluginSlug := d.Get("slug").(string) @@ -76,9 +74,7 @@ func ResourcePluginInstallationCreate(ctx context.Context, d *schema.ResourceDat return nil } -func ResourcePluginInstallationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*common.Client).GrafanaCloudAPI - +func resourcePluginInstallationRead(ctx context.Context, d *schema.ResourceData, client *gcom.APIClient) diag.Diagnostics { split, err := ResourcePluginInstallationID.Split(d.Id()) if err != nil { return diag.FromErr(err) @@ -98,9 +94,7 @@ func ResourcePluginInstallationRead(ctx context.Context, d *schema.ResourceData, return nil } -func ResourcePluginInstallationDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*common.Client).GrafanaCloudAPI - +func resourcePluginInstallationDelete(ctx context.Context, d *schema.ResourceData, client *gcom.APIClient) diag.Diagnostics { split, err := ResourcePluginInstallationID.Split(d.Id()) if err != nil { return diag.FromErr(err) diff --git a/internal/resources/cloud/resource_cloud_stack.go b/internal/resources/cloud/resource_cloud_stack.go index 9d2b63614..c6e2e8167 100644 --- a/internal/resources/cloud/resource_cloud_stack.go +++ b/internal/resources/cloud/resource_cloud_stack.go @@ -28,7 +28,7 @@ var ( stackSlugRegex = regexp.MustCompile(`^[a-z][a-z0-9]+$`) ) -func ResourceStack() *schema.Resource { +func resourceStack() *schema.Resource { return &schema.Resource{ Description: ` @@ -41,10 +41,10 @@ Required access policy scopes: * stacks:delete `, - CreateContext: CreateStack, - UpdateContext: UpdateStack, - DeleteContext: DeleteStack, - ReadContext: ReadStack, + CreateContext: withClient[schema.CreateContextFunc](createStack), + UpdateContext: withClient[schema.UpdateContextFunc](updateStack), + DeleteContext: withClient[schema.DeleteContextFunc](deleteStack), + ReadContext: withClient[schema.ReadContextFunc](readStack), Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, @@ -200,9 +200,7 @@ Required access policy scopes: } } -func CreateStack(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*common.Client).GrafanaCloudAPI - +func createStack(ctx context.Context, d *schema.ResourceData, client *gcom.APIClient) diag.Diagnostics { stack := gcom.PostInstancesRequest{ Name: d.Get("name").(string), Slug: common.Ref(d.Get("slug").(string)), @@ -242,16 +240,14 @@ func CreateStack(ctx context.Context, d *schema.ResourceData, meta interface{}) return apiError(err) } - if diag := ReadStack(ctx, d, meta); diag != nil { + if diag := readStack(ctx, d, client); diag != nil { return diag } return waitForStackReadiness(ctx, d) } -func UpdateStack(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*common.Client).GrafanaCloudAPI - +func updateStack(ctx context.Context, d *schema.ResourceData, client *gcom.APIClient) diag.Diagnostics { // Default to the slug if the URL is not set url := d.Get("url").(string) if url == "" { @@ -271,22 +267,20 @@ func UpdateStack(ctx context.Context, d *schema.ResourceData, meta interface{}) return apiError(err) } - if diag := ReadStack(ctx, d, meta); diag != nil { + if diag := readStack(ctx, d, client); diag != nil { return diag } return waitForStackReadiness(ctx, d) } -func DeleteStack(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*common.Client).GrafanaCloudAPI +func deleteStack(ctx context.Context, d *schema.ResourceData, client *gcom.APIClient) diag.Diagnostics { req := client.InstancesAPI.DeleteInstance(ctx, d.Id()).XRequestId(ClientRequestID()) _, _, err := req.Execute() return apiError(err) } -func ReadStack(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*common.Client).GrafanaCloudAPI +func readStack(ctx context.Context, d *schema.ResourceData, client *gcom.APIClient) diag.Diagnostics { req := client.InstancesAPI.GetInstance(ctx, d.Id()) stack, _, err := req.Execute() if err, shouldReturn := common.CheckReadError("stack", d, err); shouldReturn { diff --git a/internal/resources/cloud/resource_cloud_stack_api_key.go b/internal/resources/cloud/resource_cloud_stack_api_key.go index 7bd55a2e8..b96834338 100644 --- a/internal/resources/cloud/resource_cloud_stack_api_key.go +++ b/internal/resources/cloud/resource_cloud_stack_api_key.go @@ -6,6 +6,7 @@ import ( "strings" "time" + "github.com/grafana/grafana-com-public-clients/go/gcom" goapi "github.com/grafana/grafana-openapi-client-go/client" "github.com/grafana/grafana-openapi-client-go/client/api_keys" "github.com/grafana/grafana-openapi-client-go/models" @@ -16,7 +17,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) -func ResourceStackAPIKey() *schema.Resource { +func resourceStackAPIKey() *schema.Resource { return &schema.Resource{ Description: ` Manages API keys of a Grafana Cloud stack using the Cloud API @@ -31,9 +32,9 @@ Required access policy scopes: !> Deprecated: please use ` + "`grafana_cloud_stack_service_account`" + ` and ` + "`grafana_cloud_stack_service_account_token`" + ` instead, see https://grafana.com/docs/grafana/next/administration/api-keys/#migrate-api-keys-to-grafana-service-accounts-using-terraform. `, - CreateContext: resourceStackAPIKeyCreate, - ReadContext: resourceStackAPIKeyRead, - DeleteContext: resourceStackAPIKeyDelete, + CreateContext: withClient[schema.CreateContextFunc](resourceStackAPIKeyCreate), + ReadContext: withClient[schema.ReadContextFunc](resourceStackAPIKeyRead), + DeleteContext: withClient[schema.DeleteContextFunc](resourceStackAPIKeyDelete), DeprecationMessage: "Use `grafana_cloud_stack_service_account` together with `grafana_cloud_stack_service_account_token` resources instead see https://grafana.com/docs/grafana/next/administration/api-keys/#migrate-api-keys-to-grafana-service-accounts-using-terraform", Schema: map[string]*schema.Schema{ @@ -76,12 +77,11 @@ Required access policy scopes: } } -func resourceStackAPIKeyCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { +func resourceStackAPIKeyCreate(ctx context.Context, d *schema.ResourceData, cloudClient *gcom.APIClient) diag.Diagnostics { name := d.Get("name").(string) role := d.Get("role").(string) ttl := d.Get("seconds_to_live").(int) - cloudClient := m.(*common.Client).GrafanaCloudAPI c, cleanup, err := CreateTemporaryStackGrafanaClient(ctx, cloudClient, d.Get("stack_slug").(string), "terraform-temp-") if err != nil { return diag.FromErr(err) @@ -113,8 +113,7 @@ func resourceStackAPIKeyCreate(ctx context.Context, d *schema.ResourceData, m in return resourceStackAPIKeyReadWithClient(c, d) } -func resourceStackAPIKeyRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - cloudClient := m.(*common.Client).GrafanaCloudAPI +func resourceStackAPIKeyRead(ctx context.Context, d *schema.ResourceData, cloudClient *gcom.APIClient) diag.Diagnostics { c, cleanup, err := CreateTemporaryStackGrafanaClient(ctx, cloudClient, d.Get("stack_slug").(string), "terraform-temp-") if err != nil { return diag.FromErr(err) @@ -154,13 +153,12 @@ func resourceStackAPIKeyReadWithClient(c *goapi.GrafanaHTTPAPI, d *schema.Resour return nil } -func resourceStackAPIKeyDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { +func resourceStackAPIKeyDelete(ctx context.Context, d *schema.ResourceData, cloudClient *gcom.APIClient) diag.Diagnostics { id, err := strconv.ParseInt(d.Id(), 10, 32) if err != nil { return diag.FromErr(err) } - cloudClient := m.(*common.Client).GrafanaCloudAPI c, cleanup, err := CreateTemporaryStackGrafanaClient(ctx, cloudClient, d.Get("stack_slug").(string), "terraform-temp-") if err != nil { return diag.FromErr(err) diff --git a/internal/resources/cloud/resource_cloud_stack_service_account.go b/internal/resources/cloud/resource_cloud_stack_service_account.go index 5f8250055..18270d287 100644 --- a/internal/resources/cloud/resource_cloud_stack_service_account.go +++ b/internal/resources/cloud/resource_cloud_stack_service_account.go @@ -17,7 +17,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) -func ResourceStackServiceAccount() *schema.Resource { +func resourceStackServiceAccount() *schema.Resource { return &schema.Resource{ Description: ` @@ -32,10 +32,10 @@ Required access policy scopes: * stack-service-accounts:write `, - CreateContext: createStackServiceAccount, - ReadContext: readStackServiceAccount, - UpdateContext: updateStackServiceAccount, - DeleteContext: deleteStackServiceAccount, + CreateContext: withClient[schema.CreateContextFunc](createStackServiceAccount), + ReadContext: withClient[schema.ReadContextFunc](readStackServiceAccount), + UpdateContext: withClient[schema.UpdateContextFunc](updateStackServiceAccount), + DeleteContext: withClient[schema.DeleteContextFunc](deleteStackServiceAccount), Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, @@ -68,8 +68,7 @@ Required access policy scopes: } } -func createStackServiceAccount(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - cloudClient := meta.(*common.Client).GrafanaCloudAPI +func createStackServiceAccount(ctx context.Context, d *schema.ResourceData, cloudClient *gcom.APIClient) diag.Diagnostics { client, cleanup, err := CreateTemporaryStackGrafanaClient(ctx, cloudClient, d.Get("stack_slug").(string), "terraform-temp-") if err != nil { return diag.FromErr(err) @@ -91,8 +90,7 @@ func createStackServiceAccount(ctx context.Context, d *schema.ResourceData, meta return readStackServiceAccountWithClient(client, d) } -func readStackServiceAccount(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - cloudClient := meta.(*common.Client).GrafanaCloudAPI +func readStackServiceAccount(ctx context.Context, d *schema.ResourceData, cloudClient *gcom.APIClient) diag.Diagnostics { client, cleanup, err := CreateTemporaryStackGrafanaClient(ctx, cloudClient, d.Get("stack_slug").(string), "terraform-temp-") if err != nil { return diag.FromErr(err) @@ -130,8 +128,7 @@ func readStackServiceAccountWithClient(client *goapi.GrafanaHTTPAPI, d *schema.R return nil } -func updateStackServiceAccount(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - cloudClient := meta.(*common.Client).GrafanaCloudAPI +func updateStackServiceAccount(ctx context.Context, d *schema.ResourceData, cloudClient *gcom.APIClient) diag.Diagnostics { client, cleanup, err := CreateTemporaryStackGrafanaClient(ctx, cloudClient, d.Get("stack_slug").(string), "terraform-temp-") if err != nil { return diag.FromErr(err) @@ -158,8 +155,7 @@ func updateStackServiceAccount(ctx context.Context, d *schema.ResourceData, meta return readStackServiceAccountWithClient(client, d) } -func deleteStackServiceAccount(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - cloudClient := meta.(*common.Client).GrafanaCloudAPI +func deleteStackServiceAccount(ctx context.Context, d *schema.ResourceData, cloudClient *gcom.APIClient) diag.Diagnostics { client, cleanup, err := CreateTemporaryStackGrafanaClient(ctx, cloudClient, d.Get("stack_slug").(string), "terraform-temp-") if err != nil { return diag.FromErr(err) diff --git a/internal/resources/cloud/resource_cloud_stack_service_account_token.go b/internal/resources/cloud/resource_cloud_stack_service_account_token.go index 8d8aa58c2..f713826ac 100644 --- a/internal/resources/cloud/resource_cloud_stack_service_account_token.go +++ b/internal/resources/cloud/resource_cloud_stack_service_account_token.go @@ -5,15 +5,15 @@ import ( "log" "strconv" + "github.com/grafana/grafana-com-public-clients/go/gcom" goapi "github.com/grafana/grafana-openapi-client-go/client" "github.com/grafana/grafana-openapi-client-go/client/service_accounts" "github.com/grafana/grafana-openapi-client-go/models" - "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 ResourceStackServiceAccountToken() *schema.Resource { +func resourceStackServiceAccountToken() *schema.Resource { return &schema.Resource{ Description: ` Manages service account tokens of a Grafana Cloud stack using the Cloud API @@ -27,9 +27,9 @@ Required access policy scopes: * stack-service-accounts:write `, - CreateContext: stackServiceAccountTokenCreate, - ReadContext: stackServiceAccountTokenRead, - DeleteContext: stackServiceAccountTokenDelete, + CreateContext: withClient[schema.CreateContextFunc](stackServiceAccountTokenCreate), + ReadContext: withClient[schema.ReadContextFunc](stackServiceAccountTokenRead), + DeleteContext: withClient[schema.DeleteContextFunc](stackServiceAccountTokenDelete), Schema: map[string]*schema.Schema{ "stack_slug": { @@ -69,8 +69,7 @@ Required access policy scopes: } } -func stackServiceAccountTokenCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - cloudClient := m.(*common.Client).GrafanaCloudAPI +func stackServiceAccountTokenCreate(ctx context.Context, d *schema.ResourceData, cloudClient *gcom.APIClient) diag.Diagnostics { c, cleanup, err := CreateTemporaryStackGrafanaClient(ctx, cloudClient, d.Get("stack_slug").(string), "terraform-temp-") if err != nil { return diag.FromErr(err) @@ -105,8 +104,7 @@ func stackServiceAccountTokenCreate(ctx context.Context, d *schema.ResourceData, return stackServiceAccountTokenReadWithClient(c, d) } -func stackServiceAccountTokenRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - cloudClient := m.(*common.Client).GrafanaCloudAPI +func stackServiceAccountTokenRead(ctx context.Context, d *schema.ResourceData, cloudClient *gcom.APIClient) diag.Diagnostics { c, cleanup, err := CreateTemporaryStackGrafanaClient(ctx, cloudClient, d.Get("stack_slug").(string), "terraform-temp-") if err != nil { return diag.FromErr(err) @@ -156,8 +154,7 @@ func stackServiceAccountTokenReadWithClient(c *goapi.GrafanaHTTPAPI, d *schema.R return nil } -func stackServiceAccountTokenDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - cloudClient := m.(*common.Client).GrafanaCloudAPI +func stackServiceAccountTokenDelete(ctx context.Context, d *schema.ResourceData, cloudClient *gcom.APIClient) diag.Diagnostics { c, cleanup, err := CreateTemporaryStackGrafanaClient(ctx, cloudClient, d.Get("stack_slug").(string), "terraform-temp-") if err != nil { return diag.FromErr(err) diff --git a/internal/resources/cloud/resource_synthetic_monitoring_installation.go b/internal/resources/cloud/resource_synthetic_monitoring_installation.go index f117f39e8..8b696ae31 100644 --- a/internal/resources/cloud/resource_synthetic_monitoring_installation.go +++ b/internal/resources/cloud/resource_synthetic_monitoring_installation.go @@ -6,8 +6,8 @@ import ( "log" "strings" + "github.com/grafana/grafana-com-public-clients/go/gcom" SMAPI "github.com/grafana/synthetic-monitoring-api-go-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" ) @@ -20,7 +20,7 @@ var smAPIURLsExceptions = map[string]string{ "us-azure": "https://synthetic-monitoring-api-us-central2.grafana.net", } -func ResourceInstallation() *schema.Resource { +func resourceSyntheticMonitoringInstallation() *schema.Resource { return &schema.Resource{ Description: ` @@ -37,9 +37,9 @@ Required access policy scopes: * stacks:read `, - CreateContext: ResourceInstallationCreate, - ReadContext: ResourceInstallationRead, - DeleteContext: ResourceInstallationDelete, + CreateContext: withClient[schema.CreateContextFunc](resourceInstallationCreate), + ReadContext: resourceInstallationRead, + DeleteContext: resourceInstallationDelete, Schema: map[string]*schema.Schema{ "metrics_publisher_key": { @@ -71,8 +71,7 @@ Required access policy scopes: } } -func ResourceInstallationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - cloudClient := meta.(*common.Client).GrafanaCloudAPI +func resourceInstallationCreate(ctx context.Context, d *schema.ResourceData, cloudClient *gcom.APIClient) diag.Diagnostics { req := cloudClient.InstancesAPI.GetInstance(ctx, d.Get("stack_id").(string)) stack, _, err := req.Execute() if err != nil { @@ -98,12 +97,12 @@ func ResourceInstallationCreate(ctx context.Context, d *schema.ResourceData, met d.SetId(fmt.Sprintf("%s;%d", apiURL, stackID)) d.Set("sm_access_token", resp.AccessToken) d.Set("stack_sm_api_url", apiURL) - return ResourceInstallationRead(ctx, d, meta) + return resourceInstallationRead(ctx, d, nil) } // Management of the installation is a one-off operation. The state cannot be updated through a read operation. // This read function will only invalidate the state (forcing recreation) if the installation has been deleted. -func ResourceInstallationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourceInstallationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { apiURL := strings.Split(d.Id(), ";")[0] tempClient := SMAPI.NewClient(apiURL, d.Get("sm_access_token").(string), nil) if err := tempClient.ValidateToken(ctx); err != nil { @@ -114,7 +113,7 @@ func ResourceInstallationRead(ctx context.Context, d *schema.ResourceData, meta return nil } -func ResourceInstallationDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourceInstallationDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { apiURL := strings.Split(d.Id(), ";")[0] tempClient := SMAPI.NewClient(apiURL, d.Get("sm_access_token").(string), nil) if err := tempClient.DeleteToken(ctx); err != nil { diff --git a/internal/resources/cloud/resources.go b/internal/resources/cloud/resources.go new file mode 100644 index 000000000..9ae0bf54a --- /dev/null +++ b/internal/resources/cloud/resources.go @@ -0,0 +1,23 @@ +package cloud + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var DatasourcesMap = map[string]*schema.Resource{ + "grafana_cloud_ips": datasourceIPs(), + "grafana_cloud_organization": datasourceOrganization(), + "grafana_cloud_stack": datasourceStack(), +} + +var ResourcesMap = map[string]*schema.Resource{ + "grafana_cloud_access_policy": resourceAccessPolicy(), + "grafana_cloud_access_policy_token": resourceAccessPolicyToken(), + "grafana_cloud_api_key": resourceAPIKey(), + "grafana_cloud_plugin_installation": resourcePluginInstallation(), + "grafana_cloud_stack": resourceStack(), + "grafana_cloud_stack_api_key": resourceStackAPIKey(), + "grafana_cloud_stack_service_account": resourceStackServiceAccount(), + "grafana_cloud_stack_service_account_token": resourceStackServiceAccountToken(), + "grafana_synthetic_monitoring_installation": resourceSyntheticMonitoringInstallation(), +}