From 03a664495757cf74326c7ce9ffbd2207ef049620 Mon Sep 17 00:00:00 2001 From: Julien Duchesne Date: Sun, 3 Mar 2024 09:46:27 -0500 Subject: [PATCH] Self-contained SLO package Just like https://github.com/grafana/terraform-provider-grafana/pull/1393 - Makes the resource functions private (exposed via a single map attribute) rather than each resource individually - Puts the client validation in the SLO package --- internal/provider/legacy_provider.go | 8 ++---- internal/resources/slo/data_source_slo.go | 9 +++---- internal/resources/slo/resource_slo.go | 28 +++++++++------------ internal/resources/slo/resources.go | 30 +++++++++++++++++++++++ 4 files changed, 47 insertions(+), 28 deletions(-) create mode 100644 internal/resources/slo/resources.go diff --git a/internal/provider/legacy_provider.go b/internal/provider/legacy_provider.go index 0ab70683f..1d9b936fe 100644 --- a/internal/provider/legacy_provider.go +++ b/internal/provider/legacy_provider.go @@ -74,9 +74,6 @@ func Provider(version string) *schema.Provider { "grafana_machine_learning_job": machinelearning.ResourceJob(), "grafana_machine_learning_holiday": machinelearning.ResourceHoliday(), "grafana_machine_learning_outlier_detector": machinelearning.ResourceOutlierDetector(), - - // SLO - "grafana_slo": slo.ResourceSlo(), }) // Resources that require the Synthetic Monitoring client to exist. @@ -127,9 +124,6 @@ func Provider(version string) *schema.Provider { "grafana_team": grafana.DatasourceTeam(), "grafana_organization": grafana.DatasourceOrganization(), "grafana_organization_preferences": grafana.DatasourceOrganizationPreferences(), - - // SLO - "grafana_slos": slo.DatasourceSlo(), }) // Datasources that require the Synthetic Monitoring client to exist. @@ -277,6 +271,7 @@ func Provider(version string) *schema.Provider { ResourcesMap: mergeResourceMaps( grafanaClientResources, + slo.ResourcesMap, smClientResources, onCallClientResources, cloudClientResources, @@ -284,6 +279,7 @@ func Provider(version string) *schema.Provider { DataSourcesMap: mergeResourceMaps( grafanaClientDatasources, + slo.DatasourcesMap, smClientDatasources, onCallClientDatasources, cloudClientDatasources, diff --git a/internal/resources/slo/data_source_slo.go b/internal/resources/slo/data_source_slo.go index 1f5d0e2f9..2433ae1d1 100644 --- a/internal/resources/slo/data_source_slo.go +++ b/internal/resources/slo/data_source_slo.go @@ -9,7 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func DatasourceSlo() *schema.Resource { +func datasourceSlo() *schema.Resource { return &schema.Resource{ Description: ` Datasource for retrieving all SLOs. @@ -18,14 +18,14 @@ Datasource for retrieving all SLOs. * [API documentation](https://grafana.com/docs/grafana-cloud/alerting-and-irm/slo/api/) * [Additional Information On Alerting Rule Annotations and Labels](https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/#templating/) `, - ReadContext: datasourceSloRead, + ReadContext: withClient[schema.ReadContextFunc](datasourceSloRead), Schema: map[string]*schema.Schema{ "slos": { Type: schema.TypeList, Computed: true, Description: `Returns a list of all SLOs"`, Elem: &schema.Resource{ - Schema: common.CloneResourceSchemaForDatasource(ResourceSlo(), map[string]*schema.Schema{ + Schema: common.CloneResourceSchemaForDatasource(resourceSlo(), map[string]*schema.Schema{ "uuid": { Type: schema.TypeString, Description: `A unique, random identifier. This value will also be the name of the resource stored in the API server. This value is read-only.`, @@ -40,10 +40,9 @@ Datasource for retrieving all SLOs. // Function sends a GET request to the SLO API Endpoint which returns a list of all SLOs // Maps the API Response body to the Terraform Schema and displays as a READ in the terminal -func datasourceSloRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { +func datasourceSloRead(ctx context.Context, d *schema.ResourceData, client *slo.APIClient) diag.Diagnostics { var diags diag.Diagnostics - client := m.(*common.Client).SLOClient req := client.DefaultAPI.V1SloGet(ctx) apiSlos, _, err := req.Execute() if err != nil { diff --git a/internal/resources/slo/resource_slo.go b/internal/resources/slo/resource_slo.go index eb5be7db6..370832b5b 100644 --- a/internal/resources/slo/resource_slo.go +++ b/internal/resources/slo/resource_slo.go @@ -20,7 +20,7 @@ const ( QueryTypeThreshold string = "threshold" ) -func ResourceSlo() *schema.Resource { +func resourceSlo() *schema.Resource { return &schema.Resource{ Description: ` Resource manages Grafana SLOs. @@ -29,10 +29,10 @@ Resource manages Grafana SLOs. * [API documentation](https://grafana.com/docs/grafana-cloud/alerting-and-irm/slo/api/) * [Additional Information On Alerting Rule Annotations and Labels](https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/#templating/) `, - CreateContext: resourceSloCreate, - ReadContext: resourceSloRead, - UpdateContext: resourceSloUpdate, - DeleteContext: resourceSloDelete, + CreateContext: withClient[schema.CreateContextFunc](resourceSloCreate), + ReadContext: withClient[schema.ReadContextFunc](resourceSloRead), + UpdateContext: withClient[schema.UpdateContextFunc](resourceSloUpdate), + DeleteContext: withClient[schema.DeleteContextFunc](resourceSloDelete), Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, @@ -234,7 +234,7 @@ var keyvalueSchema = &schema.Resource{ }, } -func resourceSloCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { +func resourceSloCreate(ctx context.Context, d *schema.ResourceData, client *slo.APIClient) diag.Diagnostics { var diags diag.Diagnostics sloModel, err := packSloResource(d) @@ -247,7 +247,6 @@ func resourceSloCreate(ctx context.Context, d *schema.ResourceData, m interface{ return diags } - client := m.(*common.Client).SLOClient req := client.DefaultAPI.V1SloPost(ctx).Slo(sloModel) response, _, err := req.Execute() @@ -256,18 +255,16 @@ func resourceSloCreate(ctx context.Context, d *schema.ResourceData, m interface{ } d.SetId(response.Uuid) - resourceSloRead(ctx, d, m) - return resourceSloRead(ctx, d, m) + return resourceSloRead(ctx, d, client) } // resourceSloRead - sends a GET Request to the single SLO Endpoint -func resourceSloRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { +func resourceSloRead(ctx context.Context, d *schema.ResourceData, client *slo.APIClient) diag.Diagnostics { var diags diag.Diagnostics sloID := d.Id() - client := m.(*common.Client).SLOClient req := client.DefaultAPI.V1SloIdGet(ctx, sloID) slo, _, err := req.Execute() @@ -280,7 +277,7 @@ func resourceSloRead(ctx context.Context, d *schema.ResourceData, m interface{}) return diags } -func resourceSloUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { +func resourceSloUpdate(ctx context.Context, d *schema.ResourceData, client *slo.APIClient) diag.Diagnostics { var diags diag.Diagnostics sloID := d.Id() @@ -295,21 +292,18 @@ func resourceSloUpdate(ctx context.Context, d *schema.ResourceData, m interface{ return diags } - client := m.(*common.Client).SLOClient - req := client.DefaultAPI.V1SloIdPut(ctx, sloID).Slo(slo) if _, err := req.Execute(); err != nil { return apiError("Unable to Update SLO - API", err) } } - return resourceSloRead(ctx, d, m) + return resourceSloRead(ctx, d, client) } -func resourceSloDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { +func resourceSloDelete(ctx context.Context, d *schema.ResourceData, client *slo.APIClient) diag.Diagnostics { sloID := d.Id() - client := m.(*common.Client).SLOClient req := client.DefaultAPI.V1SloIdDelete(ctx, sloID) _, err := req.Execute() diff --git a/internal/resources/slo/resources.go b/internal/resources/slo/resources.go new file mode 100644 index 000000000..2d08b82e8 --- /dev/null +++ b/internal/resources/slo/resources.go @@ -0,0 +1,30 @@ +package slo + +import ( + "context" + + slo "github.com/grafana/slo-openapi-client/go" + "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" +) + +type crudWithClientFunc func(ctx context.Context, d *schema.ResourceData, client *slo.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).SLOClient + if client == nil { + return diag.Errorf("the SLO API client is required for this resource. Set the url and auth provider attributes") + } + return f(ctx, d, client) + } +} + +var DatasourcesMap = map[string]*schema.Resource{ + "grafana_slos": datasourceSlo(), +} + +var ResourcesMap = map[string]*schema.Resource{ + "grafana_slo": resourceSlo(), +}