From 89bda18a4f1de46a17dc884e520d54c52f61e00c Mon Sep 17 00:00:00 2001 From: Fabian Holler Date: Wed, 15 Jun 2022 09:56:57 +0200 Subject: [PATCH 1/9] storagezone: fix: creation fails Creating a storagezone failed with the immutable attribute errors: * 'name' is immutable and cannot be changed from '' to 'tf-test-20220615075051824800000019'.[..] * 'region' is immutable and cannot be changed from '' to 'DE'. [..] Fix it by always allowing changes in validateImmutableStringProperty if the old value was an empty string. --- internal/provider/resource_storagezone.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/provider/resource_storagezone.go b/internal/provider/resource_storagezone.go index 2f91a53..1b338e8 100644 --- a/internal/provider/resource_storagezone.go +++ b/internal/provider/resource_storagezone.go @@ -166,6 +166,10 @@ func validateImmutableStringProperty(key string, old interface{}, new interface{ o := old.(string) n, nok := new.(string) + if o == "" { + return nil + } + if new == nil || !nok { return immutableStringPropertyError(key, o, "") } From 0ebb31b8b06268c1cab317b2ed1ac92d10c2d24e Mon Sep 17 00:00:00 2001 From: Fabian Holler Date: Wed, 15 Jun 2022 10:45:26 +0200 Subject: [PATCH 2/9] storagezone: improve error message for immutable fields - add newlines to make the message easier to read, - make the message vars constants, --- internal/provider/resource_storagezone.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/provider/resource_storagezone.go b/internal/provider/resource_storagezone.go index 1b338e8..6767f5d 100644 --- a/internal/provider/resource_storagezone.go +++ b/internal/provider/resource_storagezone.go @@ -182,16 +182,16 @@ func validateImmutableStringProperty(key string, old interface{}, new interface{ } func immutableStringPropertyError(key string, old string, new string) error { - message := "'%s' is immutable and cannot be changed from '%s' to '%s'. " + - "If you must change the '%s' of our region you must first delete your resource and then redefine it. " + + const message = "'%s' is immutable and cannot be changed from '%s' to '%s'.\n" + + "If you must change the '%s' of our region, first delete your resource and then redefine it.\n" + "WARNING: deleting a 'bunny_storagezone' will also delete all the data it contains!" return fmt.Errorf(message, key, old, new, key) } func immutableReplicationRegionError(key string, removed []interface{}) error { - message := "'%s' can be added to but not be removed once the zone has been created. " + - "This error occurred when attempting to remove values %+q from '%s'. " + - "To remove an existing '%s' the 'bunny_storagezone' must be deleted and recreated. " + + const message = "'%s' can be added but not removed once the zone has been created.\n" + + "This error occurred when attempting to remove values %+q from '%s'.\n" + + "To remove an existing '%s' the 'bunny_storagezone' must be deleted and recreated.\n" + "WARNING: deleting a 'bunny_storagezone' will also delete all the data it contains!" return fmt.Errorf( message, From 103e042798dc875ba5564a89b8eadaf1549aa4b3 Mon Sep 17 00:00:00 2001 From: Fabian Holler Date: Wed, 15 Jun 2022 10:46:15 +0200 Subject: [PATCH 3/9] storagezone: remove date_modified key --- docs/resources/storagezone.md | 1 - internal/provider/resource_storagezone.go | 9 --------- 2 files changed, 10 deletions(-) diff --git a/docs/resources/storagezone.md b/docs/resources/storagezone.md index c89b7d4..7bd574e 100644 --- a/docs/resources/storagezone.md +++ b/docs/resources/storagezone.md @@ -29,7 +29,6 @@ description: |- ### Read-Only -- `date_modified` (String) The last modified date of the storage zone. - `deleted` (Boolean) - `files_stored` (Number) The number of files stored in the storage zone. - `id` (String) The ID of this resource. diff --git a/internal/provider/resource_storagezone.go b/internal/provider/resource_storagezone.go index 6767f5d..97a0e77 100644 --- a/internal/provider/resource_storagezone.go +++ b/internal/provider/resource_storagezone.go @@ -16,7 +16,6 @@ import ( const ( keyUserID = "user_id" keyPassword = "password" - keyDateModified = "date_modified" keyDeleted = "deleted" keyStorageUsed = "storage_used" keyFilesStored = "files_stored" @@ -94,11 +93,6 @@ func resourceStorageZone() *schema.Resource { Computed: true, Sensitive: true, }, - keyDateModified: { - Type: schema.TypeString, - Description: "The last modified date of the storage zone.", - Computed: true, - }, keyDeleted: { Type: schema.TypeBool, Computed: true, @@ -336,9 +330,6 @@ func storageZoneToResource(sz *bunny.StorageZone, d *schema.ResourceData) error if err := d.Set(keyPassword, sz.Password); err != nil { return err } - if err := d.Set(keyDateModified, sz.DateModified); err != nil { - return err - } if err := d.Set(keyDeleted, sz.Deleted); err != nil { return err } From 932b9e2149f15501f11752a14a0d05fc81a1c634 Mon Sep 17 00:00:00 2001 From: Fabian Holler Date: Wed, 15 Jun 2022 12:53:58 +0200 Subject: [PATCH 4/9] storagezone: remove setting state to current values on failed update It is not needed. d.Get() only returns the proposed state, if updating fails it is not stored as current state. --- internal/provider/resource_storagezone.go | 25 ----------------------- 1 file changed, 25 deletions(-) diff --git a/internal/provider/resource_storagezone.go b/internal/provider/resource_storagezone.go index 97a0e77..85979b8 100644 --- a/internal/provider/resource_storagezone.go +++ b/internal/provider/resource_storagezone.go @@ -254,14 +254,6 @@ func resourceStorageZoneUpdate(ctx context.Context, d *schema.ResourceData, meta updateErr := clt.StorageZone.Update(ctx, id, storageZone) if updateErr != nil { - // if our update failed then revert our values to their original - // state so that we can run an apply again. - revertErr := revertUpdateValues(d) - - if revertErr != nil { - return diagsErrFromErr("updating storage zone via API failed", revertErr) - } - return diagsErrFromErr("updating storage zone via API failed", updateErr) } @@ -352,23 +344,6 @@ func storageZoneToResource(sz *bunny.StorageZone, d *schema.ResourceData) error return nil } -func revertUpdateValues(d *schema.ResourceData) error { - o, _ := d.GetChange(keyOriginURL) - if err := d.Set(keyOriginURL, o); err != nil { - return err - } - o, _ = d.GetChange(keyCustom404FilePath) - if err := d.Set(keyCustom404FilePath, o); err != nil { - return err - } - o, _ = d.GetChange(keyRewrite404To200) - if err := d.Set(keyRewrite404To200, o); err != nil { - return err - } - - return nil -} - // storageZoneFromResource returns a StorageZoneUpdateOptions API type that // has fields set to the values in d. func storageZoneFromResource(d *schema.ResourceData) (*bunny.StorageZoneUpdateOptions, error) { From 773b9beca8d5ae51bf7b3279f019e6dceedcb96c Mon Sep 17 00:00:00 2001 From: Fabian Holler Date: Wed, 15 Jun 2022 12:57:10 +0200 Subject: [PATCH 5/9] simplify storageZoneFromResource storageZoneFromResource was only setting fields in *bunny.StorageZoneUpdateOptions that changed in the resource. Change it to set always all fields to the current values. This is consistent with how other *FromResource functions are behaving. The update message sent to the bunny API will contain all settings also the current ones instead of only the changed ones. Depending on how the bunny.net endpoint handles missing fields in JSON payloads for update messages this could be better or worse. :-) If it always interprets missing fields as no change is done, it causes only unnecessary network traffic. If it interprets missing fields as the setting should be unset/disabled, it's better to include the whole configuration. The bunny.net API distinguishes between missing and empty string values for the OriginURL and Custom404FilePath fields. When submitting empty strings for those it resulted in an error, that those fields set to invalid values. To handle it the helper function getOkStrPtr() is introduced. It returns nil if the value is unset instead of an empty string. Replacing all getPtr() calls with getOkPtr() might make sense and should be investigated in a follow-up. --- internal/provider/resource_storagezone.go | 28 ++++++--------------- internal/provider/types_resource_getters.go | 12 +++++++++ 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/internal/provider/resource_storagezone.go b/internal/provider/resource_storagezone.go index 85979b8..99bff48 100644 --- a/internal/provider/resource_storagezone.go +++ b/internal/provider/resource_storagezone.go @@ -242,10 +242,7 @@ func resourceStorageZoneCreate(ctx context.Context, d *schema.ResourceData, meta func resourceStorageZoneUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { clt := meta.(*bunny.Client) - storageZone, err := storageZoneFromResource(d) - if err != nil { - return diagsErrFromErr("converting resource to API type failed", err) - } + storageZone := storageZoneFromResource(d) id, err := getIDAsInt64(d) if err != nil { @@ -346,22 +343,11 @@ func storageZoneToResource(sz *bunny.StorageZone, d *schema.ResourceData) error // storageZoneFromResource returns a StorageZoneUpdateOptions API type that // has fields set to the values in d. -func storageZoneFromResource(d *schema.ResourceData) (*bunny.StorageZoneUpdateOptions, error) { - var res bunny.StorageZoneUpdateOptions - - res.ReplicationRegions = getStrSetAsSlice(d, keyReplicationRegions) - - if d.HasChange(keyOriginURL) { - res.OriginURL = getStrPtr(d, keyOriginURL) - } - - if d.HasChange(keyCustom404FilePath) { - res.Custom404FilePath = getStrPtr(d, keyCustom404FilePath) - } - - if d.HasChange(keyRewrite404To200) { - res.Rewrite404To200 = getBoolPtr(d, keyRewrite404To200) +func storageZoneFromResource(d *schema.ResourceData) *bunny.StorageZoneUpdateOptions { + return &bunny.StorageZoneUpdateOptions{ + ReplicationRegions: getStrSetAsSlice(d, keyReplicationRegions), + OriginURL: getOkStrPtr(d, keyOriginURL), + Custom404FilePath: getOkStrPtr(d, keyCustom404FilePath), + Rewrite404To200: getBoolPtr(d, keyRewrite404To200), } - - return &res, nil } diff --git a/internal/provider/types_resource_getters.go b/internal/provider/types_resource_getters.go index ec7337f..95b4ac9 100644 --- a/internal/provider/types_resource_getters.go +++ b/internal/provider/types_resource_getters.go @@ -8,6 +8,18 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) +// getOkStrPtr returns the value of the string field keyName in d. +// If the field is not it returns nil. +func getOkStrPtr(d *schema.ResourceData, keyName string) *string { + val, isSet := d.GetOk(keyName) + if !isSet || val == nil { + return nil + } + + v := val.(string) + return &v +} + func getStrPtr(d *schema.ResourceData, keyName string) *string { val := d.Get(keyName) if val == nil { From cc6281881532c3b662546375d83ce18c0ccd3ae1 Mon Sep 17 00:00:00 2001 From: Fabian Holler Date: Wed, 15 Jun 2022 12:58:37 +0200 Subject: [PATCH 6/9] examples: add a simple storagezone resource example --- examples/resources/storagezone_resource/basic.tf | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 examples/resources/storagezone_resource/basic.tf diff --git a/examples/resources/storagezone_resource/basic.tf b/examples/resources/storagezone_resource/basic.tf new file mode 100644 index 0000000..b857781 --- /dev/null +++ b/examples/resources/storagezone_resource/basic.tf @@ -0,0 +1,4 @@ +resource "bunny_storagezone" "mysz" { + name = "testsz" + region = "DE" +} From 0764bd1c19d5de5d2a543aea34b561cd39a7e1d3 Mon Sep 17 00:00:00 2001 From: Fabian Holler Date: Wed, 15 Jun 2022 15:49:06 +0200 Subject: [PATCH 7/9] tests: add testcase for immutable storagezone fields Add a testcase that ensures changing an immutable storagezone field fails --- .../provider/resource_storagezone_test.go | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/internal/provider/resource_storagezone_test.go b/internal/provider/resource_storagezone_test.go index 6da5a85..fa687f1 100644 --- a/internal/provider/resource_storagezone_test.go +++ b/internal/provider/resource_storagezone_test.go @@ -2,6 +2,7 @@ package provider import ( "context" + "regexp" "errors" "fmt" @@ -172,6 +173,94 @@ resource "bunny_storagezone" "%s" { }) } +func TestChangingImmutableFieldsFails(t *testing.T) { + const resourceName = "mytest1" + const fullResourceName = "bunny_storagezone." + resourceName + storageZoneName := randStorageZoneName() + + attrs := bunny.StorageZone{ + Name: ptr.ToString(storageZoneName), + Region: ptr.ToString("NY"), + ReplicationRegions: []string{"DE"}, + } + + resource.Test(t, resource.TestCase{ + Providers: testProviders, + Steps: []resource.TestStep{ + // create storagezone + { + Config: fmt.Sprintf(` +resource "bunny_storagezone" "mytest1" { + name = "%s" + region = "%s" + replication_regions = %s +} +`, + storageZoneName, + *attrs.Region, + tfStrList(attrs.ReplicationRegions), + ), + Check: checkSzState(t, fullResourceName, &attrs), + }, + // change region + { + Config: fmt.Sprintf(` +resource "bunny_storagezone" "mytest1" { + name = "%s" + region = "LA" + replication_regions = ["DE"] +} +`, + storageZoneName, + ), + ExpectError: regexp.MustCompile(".*'region' is immutable.*"), + }, + // change name + { + Config: fmt.Sprintf(` +resource "bunny_storagezone" "mytest1" { + name = "%s" + region = "LA" + replication_regions = ["DE"] +} +`, + storageZoneName+resource.UniqueId(), + ), + Check: checkSzState(t, fullResourceName, &attrs), + ExpectError: regexp.MustCompile(".*'name' is immutable.*"), + }, + // replace a replication_region + { + Config: fmt.Sprintf(` +resource "bunny_storagezone" "mytest1" { + name = "%s" + region = "NY" + replication_regions = ["LA"] +} +`, + storageZoneName, + ), + Check: checkSzState(t, fullResourceName, &attrs), + ExpectError: regexp.MustCompile(".*'replication_regions' can be added but not removed.*"), + }, + // remove replication_region + { + Config: fmt.Sprintf(` +resource "bunny_storagezone" "mytest1" { + name = "%s" + region = "NY" +} +`, + storageZoneName, + ), + Check: checkSzState(t, fullResourceName, &attrs), + ExpectError: regexp.MustCompile(".*'replication_regions' can be added but not removed.*"), + }, + }, + CheckDestroy: checkStorageZoneNotExists(fullResourceName), + }) +} + func checkSzState(t *testing.T, resourceName string, wanted *bunny.StorageZone) resource.TestCheckFunc { return func(s *terraform.State) error { clt := newAPIClient() From a4ca60679ed4ab923fe0459dd42044c6fb1ad6f3 Mon Sep 17 00:00:00 2001 From: Fabian Holler Date: Wed, 15 Jun 2022 16:04:54 +0200 Subject: [PATCH 8/9] readme: mention support for storage zones --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f713481..f057de9 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This repository provides a [Terraform](https://terraform.io) provider for the [Bunny.net CDN platform](https://bunny.net/). \ -It currently only supports to manage Pull Zones. +It supports to manage Pull and Storage Zones. ## Development From ab029029c65e10eee96338fdcbfe9e710b2feb23 Mon Sep 17 00:00:00 2001 From: Fabian Holler Date: Wed, 15 Jun 2022 16:07:00 +0200 Subject: [PATCH 9/9] tests: replace randPullZoneName(), randStorageZoneName() with 1 function replace the randPullZoneName() and randStorageZoneName() functions that were doing the same with a function called randResourceName() --- internal/provider/resource_edgerule_test.go | 12 ++++++------ internal/provider/resource_hostname_test.go | 16 ++++++++-------- internal/provider/resource_pullzone_test.go | 12 ++++-------- internal/provider/resource_storagezone_test.go | 10 +++------- internal/provider/utils_test.go | 5 +++++ 5 files changed, 26 insertions(+), 29 deletions(-) diff --git a/internal/provider/resource_edgerule_test.go b/internal/provider/resource_edgerule_test.go index 54b6f2a..284a961 100644 --- a/internal/provider/resource_edgerule_test.go +++ b/internal/provider/resource_edgerule_test.go @@ -98,7 +98,7 @@ func defPullZoneHostname(pullzoneName string) string { } func TestAccEdgeRule_full(t *testing.T) { - pzName := randPullZoneName() + pzName := randResourceName() tfPz := fmt.Sprintf(` resource "bunny_pullzone" "mypz" { @@ -311,7 +311,7 @@ resource "bunny_edgerule" "er3" { } func TestAccEdgeRule_basic(t *testing.T) { - pzName := randPullZoneName() + pzName := randResourceName() tf := fmt.Sprintf(` resource "bunny_pullzone" "mypz" { name = "%s" @@ -363,7 +363,7 @@ resource "bunny_edgerule" "myer" { } func TestAccEdgeRule_delete(t *testing.T) { - pzName := randPullZoneName() + pzName := randResourceName() tfPz := fmt.Sprintf(` resource "bunny_pullzone" "mypz" { @@ -421,7 +421,7 @@ resource "bunny_pullzone" "mypz" { } func TestAccEdgeRule_enable_disable(t *testing.T) { - pzName := randPullZoneName() + pzName := randResourceName() tfPz := fmt.Sprintf(` resource "bunny_pullzone" "mypz" { @@ -558,8 +558,8 @@ resource "bunny_edgerule" "er2" { } func TestAccEdgeRule_changePullZoneID(t *testing.T) { - pzName1 := randPullZoneName() - pzName2 := randPullZoneName() + pzName1 := randResourceName() + pzName2 := randResourceName() tfPz := fmt.Sprintf(` resource "bunny_pullzone" "pz1" { diff --git a/internal/provider/resource_hostname_test.go b/internal/provider/resource_hostname_test.go index 1242d83..b0bdf3f 100644 --- a/internal/provider/resource_hostname_test.go +++ b/internal/provider/resource_hostname_test.go @@ -76,7 +76,7 @@ func sortHostnames(hostnames []*bunny.Hostname) { } func TestAccHostname_basic(t *testing.T) { - pzName := randPullZoneName() + pzName := randResourceName() tf := fmt.Sprintf(` resource "bunny_pullzone" "pz" { name = "%s" @@ -121,7 +121,7 @@ resource "bunny_hostname" "h1" { } func TestAccHostname_addRemove(t *testing.T) { - pzName := randPullZoneName() + pzName := randResourceName() hostname1 := randHostname() hostname2 := randHostname() hostname3 := randHostname() @@ -244,7 +244,7 @@ resource "bunny_hostname" "h2" { } func TestAccHostname_DefiningDuplicateHostnamesFails(t *testing.T) { - pzName := randPullZoneName() + pzName := randResourceName() tf := fmt.Sprintf(` resource "bunny_pullzone" "pz" { name = "%s" @@ -275,7 +275,7 @@ resource "bunny_hostname" "h2" { } func TestAccHostname_DefiningDefPullZoneHostnameFails(t *testing.T) { - pzName := randPullZoneName() + pzName := randResourceName() tf := fmt.Sprintf(` resource "bunny_pullzone" "pz" { name = "%s" @@ -300,7 +300,7 @@ resource "bunny_hostname" "h1" { } func TestAccCertificateOneof(t *testing.T) { - pzName := randPullZoneName() + pzName := randResourceName() tf := fmt.Sprintf(` resource "bunny_pullzone" "pz" { name = "%s" @@ -333,7 +333,7 @@ resource "bunny_hostname" "h1" { } func TestAccCertificateCanBeSetWhenLoadFreeCertIsDisabled(t *testing.T) { - pzName := randPullZoneName() + pzName := randResourceName() tf := fmt.Sprintf(` resource "bunny_pullzone" "pz" { name = "%s" @@ -366,7 +366,7 @@ resource "bunny_hostname" "h1" { } func TestAccCertificates(t *testing.T) { - pzName := randPullZoneName() + pzName := randResourceName() hostname := randHostname() resource.Test(t, resource.TestCase{ @@ -486,7 +486,7 @@ resource "bunny_hostname" "h1" { func TestAccHostname_StateIsValidWhenCertUploadFails(t *testing.T) { t.Skip("disabled, because test sends 800kiB of bogus data to bunny api, which is not kind") - pzName := randPullZoneName() + pzName := randResourceName() hostname := randHostname() // The bunny API does not return an error if the posted data is not a diff --git a/internal/provider/resource_pullzone_test.go b/internal/provider/resource_pullzone_test.go index c5a4696..6bba1a4 100644 --- a/internal/provider/resource_pullzone_test.go +++ b/internal/provider/resource_pullzone_test.go @@ -18,10 +18,6 @@ import ( bunny "github.com/simplesurance/bunny-go" ) -func randPullZoneName() string { - return resource.PrefixedUniqueId(resourcePrefix) -} - func randHostname() string { return resource.PrefixedUniqueId(resourcePrefix) + ".test" } @@ -173,7 +169,7 @@ func TestAccPullZone_basic(t *testing.T) { */ attrs := pullZoneWanted{ TerraformResourceName: "bunny_pullzone.mytest1", - Name: randPullZoneName(), + Name: randResourceName(), OriginURL: "https://tabletennismap.de", EnableGeoZoneAsia: true, EnableGeoZoneEU: true, @@ -285,7 +281,7 @@ func TestAccPullZone_full(t *testing.T) { VerifyOriginSSL: ptr.ToBool(true), ZoneSecurityEnabled: ptr.ToBool(true), ZoneSecurityIncludeHashRemoteIP: ptr.ToBool(false), - Name: ptr.ToString(randPullZoneName()), + Name: ptr.ToString(randResourceName()), // TODO: Test StorageZoneID ZoneSecurityKey: ptr.ToString("xyz"), @@ -523,7 +519,7 @@ resource "bunny_pullzone" "%s" { } func TestAccPullZone_CaseInsensitiveOrderIndependentFields(t *testing.T) { - pzName := randPullZoneName() + pzName := randResourceName() resource.Test(t, resource.TestCase{ Providers: testProviders, @@ -772,7 +768,7 @@ func pzDiff(t *testing.T, a, b interface{}) []string { } func TestAccPullZone_OriginURLAndStorageZoneIDAreExclusive(t *testing.T) { - pzName := randPullZoneName() + pzName := randResourceName() resource.Test(t, resource.TestCase{ Providers: testProviders, diff --git a/internal/provider/resource_storagezone_test.go b/internal/provider/resource_storagezone_test.go index fa687f1..35369cc 100644 --- a/internal/provider/resource_storagezone_test.go +++ b/internal/provider/resource_storagezone_test.go @@ -17,10 +17,6 @@ import ( bunny "github.com/simplesurance/bunny-go" ) -func randStorageZoneName() string { - return resource.PrefixedUniqueId(resourcePrefix) -} - type storageZoneWanted struct { TerraformResourceName string bunny.StorageZone @@ -96,7 +92,7 @@ func checkStorageZoneNotExists(storageZoneName string) resource.TestCheckFunc { func TestAccStorageZone_basic(t *testing.T) { attrs := storageZoneWanted{ TerraformResourceName: "bunny_storagezone.mytest1", - Name: randStorageZoneName(), + Name: randResourceName(), Region: "DE", } @@ -132,7 +128,7 @@ func TestAccStorageZone_full(t *testing.T) { // set fields to different values then their defaults, to be able to test if the settings are applied attrs := bunny.StorageZone{ - Name: ptr.ToString(randStorageZoneName()), + Name: ptr.ToString(randResourceName()), Region: ptr.ToString("DE"), ReplicationRegions: []string{"NY", "LA"}, } @@ -176,7 +172,7 @@ resource "bunny_storagezone" "%s" { func TestChangingImmutableFieldsFails(t *testing.T) { const resourceName = "mytest1" const fullResourceName = "bunny_storagezone." + resourceName - storageZoneName := randStorageZoneName() + storageZoneName := randResourceName() attrs := bunny.StorageZone{ Name: ptr.ToString(storageZoneName), diff --git a/internal/provider/utils_test.go b/internal/provider/utils_test.go index ea81f3f..d7bedb5 100644 --- a/internal/provider/utils_test.go +++ b/internal/provider/utils_test.go @@ -6,9 +6,14 @@ import ( "reflect" "testing" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) +func randResourceName() string { + return resource.PrefixedUniqueId(resourcePrefix) +} + func idFromState(s *terraform.State, resourceName string) (string, error) { resourceState := s.Modules[0].Resources[resourceName] if resourceState == nil {