From d8b4d704d8179aa4031043da5e0cbf9ba80d783c Mon Sep 17 00:00:00 2001 From: The Magician Date: Thu, 15 Aug 2024 13:24:14 -0700 Subject: [PATCH] reduce name prefix in compute resources (#11448) (#19152) [upstream:ce440583cb42cfef57c0271cead35f41f3374d9f] Signed-off-by: Modular Magician --- .changelog/11448.txt | 3 + .../resource_compute_instance_template.go | 15 +++-- ...resource_compute_instance_template_test.go | 61 +++++++++++++++++++ ...source_compute_region_instance_template.go | 13 ++-- ...resource_compute_region_ssl_certificate.go | 13 ++-- .../resource_compute_ssl_certificate.go | 13 ++-- .../workflows/resource_workflows_workflow.go | 7 ++- google/tpgresource/utils.go | 14 +++++ .../guides/version_6_upgrade.html.markdown | 9 ++- .../r/compute_instance_template.html.markdown | 9 ++- ...ute_region_instance_template.html.markdown | 9 ++- ...mpute_region_ssl_certificate.html.markdown | 8 ++- .../r/compute_ssl_certificate.html.markdown | 8 ++- 13 files changed, 158 insertions(+), 24 deletions(-) create mode 100644 .changelog/11448.txt diff --git a/.changelog/11448.txt b/.changelog/11448.txt new file mode 100644 index 00000000000..1b0a49a3e82 --- /dev/null +++ b/.changelog/11448.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +compute: changed the behavior of `name_prefix` in multiple Compute resources to allow for a longer max length of 54 characters. See the upgrade guide and resource documentation for more details. +``` \ No newline at end of file diff --git a/google/services/compute/resource_compute_instance_template.go b/google/services/compute/resource_compute_instance_template.go index 113eb55cb0a..d97e805f567 100644 --- a/google/services/compute/resource_compute_instance_template.go +++ b/google/services/compute/resource_compute_instance_template.go @@ -89,14 +89,14 @@ func ResourceComputeInstanceTemplate() *schema.Resource { Optional: true, Computed: true, ForceNew: true, - Description: `Creates a unique name beginning with the specified prefix. Conflicts with name.`, + Description: `Creates a unique name beginning with the specified prefix. Conflicts with name. Max length is 54 characters. Prefixes with lengths longer than 37 characters will use a shortened UUID that will be more prone to collisions.`, ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { // https://cloud.google.com/compute/docs/reference/latest/instanceTemplates#resource - // uuid is 26 characters, limit the prefix to 37. + // shortened uuid is 9 characters, limit the prefix to 55. value := v.(string) - if len(value) > 37 { + if len(value) > 54 { errors = append(errors, fmt.Errorf( - "%q cannot be longer than 37 characters, name is limited to 63", k)) + "%q cannot be longer than 54 characters, name is limited to 63", k)) } return }, @@ -1377,7 +1377,12 @@ func resourceComputeInstanceTemplateCreate(d *schema.ResourceData, meta interfac if v, ok := d.GetOk("name"); ok { itName = v.(string) } else if v, ok := d.GetOk("name_prefix"); ok { - itName = id.PrefixedUniqueId(v.(string)) + prefix := v.(string) + if len(prefix) > 37 { + itName = tpgresource.ReducedPrefixedUniqueId(prefix) + } else { + itName = id.PrefixedUniqueId(prefix) + } } else { itName = id.UniqueId() } diff --git a/google/services/compute/resource_compute_instance_template_test.go b/google/services/compute/resource_compute_instance_template_test.go index b403d6c4007..0498fae2774 100644 --- a/google/services/compute/resource_compute_instance_template_test.go +++ b/google/services/compute/resource_compute_instance_template_test.go @@ -795,6 +795,45 @@ func TestAccComputeInstanceTemplate_invalidDiskType(t *testing.T) { }) } +func TestAccComputeInstanceTemplate_withNamePrefix(t *testing.T) { + t.Parallel() + + // 8 + 46 = 54 which is the valid max + normalPrefix := "tf-test-" + fmt.Sprintf("%046s", "") + reducedSuffixPrefix := "tf-test-" + fmt.Sprintf("%029s", "") + invalidPrefix := "tf-test-" + fmt.Sprintf("%047s", "") + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeInstanceTemplate_withNamePrefix(normalPrefix), + }, + { + ResourceName: "google_compute_instance_template.foobar", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name_prefix"}, + }, + { + Config: testAccComputeInstanceTemplate_withNamePrefix(invalidPrefix), + PlanOnly: true, + ExpectError: regexp.MustCompile("cannot be longer than 54 characters"), + }, + { + Config: testAccComputeInstanceTemplate_withNamePrefix(reducedSuffixPrefix), + }, + { + ResourceName: "google_compute_instance_template.foobar", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name_prefix"}, + }, + }, + }) +} + func TestAccComputeInstanceTemplate_withScratchDisk(t *testing.T) { t.Parallel() @@ -2341,6 +2380,28 @@ resource "google_compute_instance_template" "foobar" { `, suffix, suffix) } +func testAccComputeInstanceTemplate_withNamePrefix(prefix string) string { + return fmt.Sprintf(` +data "google_compute_image" "my_image" { + family = "debian-12" + project = "debian-cloud" +} +resource "google_compute_instance_template" "foobar" { + name_prefix = "%s" + machine_type = "n1-standard-1" // can't be e2 because of local-ssd + can_ip_forward = false + disk { + source_image = data.google_compute_image.my_image.name + auto_delete = true + boot = true + } + network_interface { + network = "default" + } +} +`, prefix) +} + func testAccComputeInstanceTemplate_with375GbScratchDisk(suffix string) string { return fmt.Sprintf(` data "google_compute_image" "my_image" { diff --git a/google/services/compute/resource_compute_region_instance_template.go b/google/services/compute/resource_compute_region_instance_template.go index dc400e7b627..1a46df16ce2 100644 --- a/google/services/compute/resource_compute_region_instance_template.go +++ b/google/services/compute/resource_compute_region_instance_template.go @@ -73,11 +73,11 @@ func ResourceComputeRegionInstanceTemplate() *schema.Resource { Description: `Creates a unique name beginning with the specified prefix. Conflicts with name.`, ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { // https://cloud.google.com/compute/docs/reference/latest/instanceTemplates#resource - // uuid is 26 characters, limit the prefix to 37. + // uuid is 9 characters, limit the prefix to 54. value := v.(string) - if len(value) > 37 { + if len(value) > 54 { errors = append(errors, fmt.Errorf( - "%q cannot be longer than 37 characters, name is limited to 63", k)) + "%q cannot be longer than 54 characters, name is limited to 63", k)) } return }, @@ -1085,7 +1085,12 @@ func resourceComputeRegionInstanceTemplateCreate(d *schema.ResourceData, meta in if v, ok := d.GetOk("name"); ok { itName = v.(string) } else if v, ok := d.GetOk("name_prefix"); ok { - itName = id.PrefixedUniqueId(v.(string)) + prefix := v.(string) + if len(prefix) > 37 { + itName = tpgresource.ReducedPrefixedUniqueId(prefix) + } else { + itName = id.PrefixedUniqueId(prefix) + } } else { itName = id.UniqueId() } diff --git a/google/services/compute/resource_compute_region_ssl_certificate.go b/google/services/compute/resource_compute_region_ssl_certificate.go index e1cb4b9223b..f330f74798c 100644 --- a/google/services/compute/resource_compute_region_ssl_certificate.go +++ b/google/services/compute/resource_compute_region_ssl_certificate.go @@ -133,11 +133,11 @@ If it is not provided, the provider region is used.`, Description: "Creates a unique name beginning with the specified prefix. Conflicts with name.", ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { // https://cloud.google.com/compute/docs/reference/latest/sslCertificates#resource - // uuid is 26 characters, limit the prefix to 37. + // uuid is 9 characters, limit the prefix to 54. value := v.(string) - if len(value) > 37 { + if len(value) > 54 { errors = append(errors, fmt.Errorf( - "%q cannot be longer than 37 characters, name is limited to 63", k)) + "%q cannot be longer than 54 characters, name is limited to 63", k)) } return }, @@ -456,7 +456,12 @@ func expandComputeRegionSslCertificateName(v interface{}, d tpgresource.Terrafor if v, ok := d.GetOk("name"); ok { certName = v.(string) } else if v, ok := d.GetOk("name_prefix"); ok { - certName = id.PrefixedUniqueId(v.(string)) + prefix := v.(string) + if len(prefix) > 37 { + certName = tpgresource.ReducedPrefixedUniqueId(prefix) + } else { + certName = id.PrefixedUniqueId(prefix) + } } else { certName = id.UniqueId() } diff --git a/google/services/compute/resource_compute_ssl_certificate.go b/google/services/compute/resource_compute_ssl_certificate.go index a8bde8eb789..24e9b790b94 100644 --- a/google/services/compute/resource_compute_ssl_certificate.go +++ b/google/services/compute/resource_compute_ssl_certificate.go @@ -116,11 +116,11 @@ These are in the same namespace as the managed SSL certificates.`, Description: "Creates a unique name beginning with the specified prefix. Conflicts with name.", ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { // https://cloud.google.com/compute/docs/reference/latest/sslCertificates#resource - // uuid is 26 characters, limit the prefix to 37. + // uuid is 9 characters, limit the prefix to 54. value := v.(string) - if len(value) > 37 { + if len(value) > 54 { errors = append(errors, fmt.Errorf( - "%q cannot be longer than 37 characters, name is limited to 63", k)) + "%q cannot be longer than 54 characters, name is limited to 63", k)) } return }, @@ -422,7 +422,12 @@ func expandComputeSslCertificateName(v interface{}, d tpgresource.TerraformResou if v, ok := d.GetOk("name"); ok { certName = v.(string) } else if v, ok := d.GetOk("name_prefix"); ok { - certName = id.PrefixedUniqueId(v.(string)) + prefix := v.(string) + if len(prefix) > 37 { + certName = tpgresource.ReducedPrefixedUniqueId(prefix) + } else { + certName = id.PrefixedUniqueId(prefix) + } } else { certName = id.UniqueId() } diff --git a/google/services/workflows/resource_workflows_workflow.go b/google/services/workflows/resource_workflows_workflow.go index cb80bd1f16d..75db8259139 100644 --- a/google/services/workflows/resource_workflows_workflow.go +++ b/google/services/workflows/resource_workflows_workflow.go @@ -733,7 +733,12 @@ func resourceWorkflowsWorkflowEncoder(d *schema.ResourceData, meta interface{}, if v, ok := d.GetOk("name"); ok { ResName = v.(string) } else if v, ok := d.GetOk("name_prefix"); ok { - ResName = id.PrefixedUniqueId(v.(string)) + prefix := v.(string) + if len(prefix) > 37 { + ResName = tpgresource.ReducedPrefixedUniqueId(prefix) + } else { + ResName = id.PrefixedUniqueId(prefix) + } } else { ResName = id.UniqueId() } diff --git a/google/tpgresource/utils.go b/google/tpgresource/utils.go index ab376408eb9..55a9f50535a 100644 --- a/google/tpgresource/utils.go +++ b/google/tpgresource/utils.go @@ -24,6 +24,7 @@ import ( "github.com/hashicorp/go-cty/cty" fwDiags "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/id" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "golang.org/x/exp/maps" @@ -880,3 +881,16 @@ func DefaultProviderZone(_ context.Context, diff *schema.ResourceDiff, meta inte return nil } + +// id.UniqueId() returns a timestamp + incremental hash +// This function truncates the timestamp to provide a prefix + 9 using +// YYmmdd + last 3 digits of the incremental hash +func ReducedPrefixedUniqueId(prefix string) string { + // uniqueID is timestamp + 8 digit counter (YYYYmmddHHMMSSssss + 12345678) + uniqueId := id.PrefixedUniqueId("") + // last three digits of the counter (678) + counter := uniqueId[len(uniqueId)-3:] + // YYmmdd of date + date := uniqueId[2:8] + return prefix + date + counter +} diff --git a/website/docs/guides/version_6_upgrade.html.markdown b/website/docs/guides/version_6_upgrade.html.markdown index 54f299004ea..f1ed81419ba 100644 --- a/website/docs/guides/version_6_upgrade.html.markdown +++ b/website/docs/guides/version_6_upgrade.html.markdown @@ -88,9 +88,14 @@ terraform { ## Provider -### Provider-level change example header +### Compute: `name_prefix` max length has been extended from 37 to 54 characters -Description of the change and how users should adjust their configuration (if needed). +Affected resources: `google_compute_instance_template`, `google_compute_region_instance_template`, `google_compute_ssl_certificate`, +and `google_compute_region_ssl_certificate` + +Previously, the max length of `name_prefix` was 37 characters since the autogenerated UUID suffix was 26 characters which combined to +the total max length for names of 63 characters. +In 6.0, providing a `name_prefix` larger than 37 characters will prompt the provider to use a shortened suffix of only 9 characters, leading to a new max of 54 characters for `name_prefix`. This shortened suffix is inevitably more prone to collisions, so use the longer max `name_prefix` length with caution. ## Datasources diff --git a/website/docs/r/compute_instance_template.html.markdown b/website/docs/r/compute_instance_template.html.markdown index 36f3392a992..cd97bf4405e 100644 --- a/website/docs/r/compute_instance_template.html.markdown +++ b/website/docs/r/compute_instance_template.html.markdown @@ -295,7 +295,14 @@ The following arguments are supported: this blank, Terraform will auto-generate a unique name. * `name_prefix` - (Optional) Creates a unique name beginning with the specified - prefix. Conflicts with `name`. + prefix. Conflicts with `name`. Max length is 54 characters. + Prefixes with lengths longer than 37 characters will use a shortened + UUID that will be more prone to collisions. + + Resulting name for a `name_prefix` <= 37 characters: + `name_prefix` + YYYYmmddHHSSssss + 8 digit incremental counter + Resulting name for a `name_prefix` 38 - 54 characters: + `name_prefix` + YYmmdd + 3 digit incremental counter * `can_ip_forward` - (Optional) Whether to allow sending and receiving of packets with non-matching source or destination IPs. This defaults to false. diff --git a/website/docs/r/compute_region_instance_template.html.markdown b/website/docs/r/compute_region_instance_template.html.markdown index 74384427c13..c7ebb9e0c3d 100644 --- a/website/docs/r/compute_region_instance_template.html.markdown +++ b/website/docs/r/compute_region_instance_template.html.markdown @@ -307,7 +307,14 @@ The following arguments are supported: this blank, Terraform will auto-generate a unique name. * `name_prefix` - (Optional) Creates a unique name beginning with the specified - prefix. Conflicts with `name`. + prefix. Conflicts with `name`. Max length is 54 characters. + Prefixes with lengths longer than 37 characters will use a shortened + UUID that will be more prone to collisions. + + Resulting name for a `name_prefix` <= 37 characters: + `name_prefix` + YYYYmmddHHSSssss + 8 digit incremental counter + Resulting name for a `name_prefix` 38 - 54 characters: + `name_prefix` + YYmmdd + 3 digit incremental counter * `can_ip_forward` - (Optional) Whether to allow sending and receiving of packets with non-matching source or destination IPs. This defaults to false. diff --git a/website/docs/r/compute_region_ssl_certificate.html.markdown b/website/docs/r/compute_region_ssl_certificate.html.markdown index 65210568883..02ae5444d55 100644 --- a/website/docs/r/compute_region_ssl_certificate.html.markdown +++ b/website/docs/r/compute_region_ssl_certificate.html.markdown @@ -214,7 +214,13 @@ The following arguments are supported: If it is not provided, the provider project is used. * `name_prefix` - (Optional) Creates a unique name beginning with the - specified prefix. Conflicts with `name`. + specified prefix. Conflicts with `name`. Max length is 54 characters. + Prefixes with lengths longer than 37 characters will use a shortened + UUID that will be more prone to collisions. + Resulting name for a `name_prefix` <= 37 characters: + `name_prefix` + YYYYmmddHHSSssss + 8 digit incremental counter + Resulting name for a `name_prefix` 38 - 54 characters: + `name_prefix` + YYmmdd + 3 digit incremental counter ## Attributes Reference diff --git a/website/docs/r/compute_ssl_certificate.html.markdown b/website/docs/r/compute_ssl_certificate.html.markdown index db3205a65ee..e96d17f09cd 100644 --- a/website/docs/r/compute_ssl_certificate.html.markdown +++ b/website/docs/r/compute_ssl_certificate.html.markdown @@ -201,7 +201,13 @@ The following arguments are supported: If it is not provided, the provider project is used. * `name_prefix` - (Optional) Creates a unique name beginning with the - specified prefix. Conflicts with `name`. + specified prefix. Conflicts with `name`. Max length is 54 characters. + Prefixes with lengths longer than 37 characters will use a shortened + UUID that will be more prone to collisions. + Resulting name for a `name_prefix` <= 37 characters: + `name_prefix` + YYYYmmddHHSSssss + 8 digit incremental counter + Resulting name for a `name_prefix` 38 - 54 characters: + `name_prefix` + YYmmdd + 3 digit incremental counter ## Attributes Reference