From e35a7f09226634a2230199e8cabc2aa3c1ddf0ee Mon Sep 17 00:00:00 2001 From: Julien Duchesne Date: Mon, 17 Apr 2023 15:32:57 -0400 Subject: [PATCH] Cloud stack: Allow read operations from either slug or ID (#884) * Cloud stack: Allow read operations from either slug or ID Currently, the logic is in the importer but that doesn't work for Crossplane that doesn't use import but instead seems to custom build a state This will be functionally the same but the slug is now usable at all points in the process, instead of being translated in the importer * Remove `SetID` * Oops * Fixed it for real now. Tests pass --- .../resources/cloud/resource_cloud_stack.go | 49 +++++++++---------- .../cloud/resource_cloud_stack_test.go | 3 ++ 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/internal/resources/cloud/resource_cloud_stack.go b/internal/resources/cloud/resource_cloud_stack.go index 9d0d81dee..ea1610a06 100644 --- a/internal/resources/cloud/resource_cloud_stack.go +++ b/internal/resources/cloud/resource_cloud_stack.go @@ -36,22 +36,8 @@ func ResourceStack() *schema.Resource { UpdateContext: UpdateStack, DeleteContext: DeleteStack, ReadContext: ReadStack, - - // Import either by ID or slug Importer: &schema.ResourceImporter{ - StateContext: func(c context.Context, rd *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - _, err := strconv.ParseInt(rd.Id(), 10, 64) - if err != nil { - // If the ID is not a number, then it may be a slug - client := meta.(*common.Client).GrafanaCloudAPI - stack, err := client.StackBySlug(rd.Id()) - if err != nil { - return nil, fmt.Errorf("failed to find stack by ID or slug '%s': %w", rd.Id(), err) - } - rd.SetId(strconv.FormatInt(stack.ID, 10)) - } - return []*schema.ResourceData{rd}, nil - }, + StateContext: schema.ImportStatePassthroughContext, }, Schema: map[string]*schema.Schema{ @@ -308,8 +294,7 @@ func UpdateStack(ctx context.Context, d *schema.ResourceData, meta interface{}) func DeleteStack(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { client := meta.(*common.Client).GrafanaCloudAPI - slug := d.Get("slug").(string) - if err := client.DeleteStack(slug); err != nil { + if err := client.DeleteStack(d.Id()); err != nil { return diag.FromErr(err) } @@ -318,14 +303,8 @@ func DeleteStack(ctx context.Context, d *schema.ResourceData, meta interface{}) func ReadStack(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { client := meta.(*common.Client).GrafanaCloudAPI + stack, err := getStackFromIDOrSlug(client, d.Id()) - idStr := d.Id() - id, err := strconv.ParseInt(idStr, 10, 64) - if err != nil { - return diag.Errorf("Invalid id: %#v", idStr) - } - - stack, err := client.StackByID(id) if err != nil { if strings.HasPrefix(err.Error(), "status: 404") { log.Printf("[WARN] removing stack %s from state because it no longer exists in grafana", d.Get("name").(string)) @@ -341,7 +320,7 @@ func ReadStack(ctx context.Context, d *schema.ResourceData, meta interface{}) di return nil } - if err := FlattenStack(d, stack); err != nil { + if err := FlattenStack(d, *stack); err != nil { return diag.FromErr(err) } // Always set the wait attribute to true after creation @@ -353,7 +332,6 @@ func ReadStack(ctx context.Context, d *schema.ResourceData, meta interface{}) di func FlattenStack(d *schema.ResourceData, stack gapi.Stack) error { id := strconv.FormatInt(stack.ID, 10) - d.SetId(id) d.Set("name", stack.Name) d.Set("slug", stack.Slug) @@ -404,6 +382,25 @@ func FlattenStack(d *schema.ResourceData, stack gapi.Stack) error { return nil } +func getStackFromIDOrSlug(client *gapi.Client, id string) (*gapi.Stack, error) { + numericalID, err := strconv.ParseInt(id, 10, 64) + if err != nil { + // If the ID is not a number, then it may be a slug + stack, err := client.StackBySlug(id) + if err != nil { + return nil, fmt.Errorf("failed to find stack by ID or slug '%s': %w", id, err) + } + return &stack, nil + } + + stack, err := client.StackByID(numericalID) + if err != nil { + return nil, err + } + + return &stack, nil +} + // Append path to baseurl func appendPath(baseURL, path string) (string, error) { bu, err := url.Parse(baseURL) diff --git a/internal/resources/cloud/resource_cloud_stack_test.go b/internal/resources/cloud/resource_cloud_stack_test.go index 54d5ec164..be0b1b73f 100644 --- a/internal/resources/cloud/resource_cloud_stack_test.go +++ b/internal/resources/cloud/resource_cloud_stack_test.go @@ -3,6 +3,7 @@ package cloud_test import ( "fmt" "strings" + "time" "strconv" "testing" @@ -53,6 +54,7 @@ func TestResourceStack_Basic(t *testing.T) { // Terraform should detect that it's gone and recreate it (status should be active at all times) PreConfig: func() { testAccDeleteExistingStacks(t, prefix) + time.Sleep(10 * time.Second) }, Config: testAccStackConfigBasic(resourceName, resourceName), Check: resource.ComposeTestCheckFunc( @@ -74,6 +76,7 @@ func TestResourceStack_Basic(t *testing.T) { resource.TestCheckResourceAttr("grafana_cloud_stack.test", "status", "active"), ), }, + // Test import from ID { ResourceName: "grafana_cloud_stack.test", ImportState: true,