From b05a6438e07504cb8df1080ca97d189ca0710e66 Mon Sep 17 00:00:00 2001 From: Modular Magician Date: Fri, 9 Jan 2026 22:26:40 +0000 Subject: [PATCH] Add IpCollection to the Address resource (#16070) [upstream:e75d9b1a7a0e84ffa521b4ec68cfc51284bc45d2] Signed-off-by: Modular Magician --- .changelog/16070.txt | 6 ++ .../compute/resource_compute_address.go | 58 +++++++++++++++++++ ...source_compute_address_generated_meta.yaml | 1 + ...resource_compute_address_generated_test.go | 44 ++++++++++++++ ...esource_compute_public_delegated_prefix.go | 44 ++++++++++---- ...ublic_delegated_prefix_generated_meta.yaml | 2 + website/docs/r/compute_address.html.markdown | 33 +++++++++++ ...pute_public_delegated_prefix.html.markdown | 9 +++ 8 files changed, 187 insertions(+), 10 deletions(-) create mode 100644 .changelog/16070.txt diff --git a/.changelog/16070.txt b/.changelog/16070.txt new file mode 100644 index 00000000000..27c43ace33e --- /dev/null +++ b/.changelog/16070.txt @@ -0,0 +1,6 @@ +```release-note:enhancement +compute: added `ip_collection` field to `google_compute_address` resource +``` +```release-note:enhancement +compute: added `enable_enhanced_ipv4_allocation` field to `google_compute_public_delegated_prefix` resource +``` \ No newline at end of file diff --git a/google/services/compute/resource_compute_address.go b/google/services/compute/resource_compute_address.go index 568bab809b9..246d388685d 100644 --- a/google/services/compute/resource_compute_address.go +++ b/google/services/compute/resource_compute_address.go @@ -54,6 +54,33 @@ import ( "google.golang.org/api/googleapi" ) +// Compare only the relative path from 'regions' of two IP collection links +func AddressIpCollectionDiffSuppress(_, old, new string, d *schema.ResourceData) bool { + oldStripped, err := GetRelativePath(old) + if err != nil { + return false + } + + newStripped, err := GetRelativePath(new) + if err != nil { + return false + } + + if oldStripped == newStripped { + return true + } + return false +} + +func GetRelativePath(resourceLink string) (string, error) { + stringParts := strings.SplitAfterN(resourceLink, "regions/", 2) + if len(stringParts) != 2 { + return "", fmt.Errorf("String is not a valid link: %s", resourceLink) + } + + return "regions/" + stringParts[1], nil +} + var ( _ = bytes.Clone _ = context.WithCancel @@ -145,6 +172,20 @@ Note: if you set this argument's value as 'INTERNAL' you need to leave the 'netw ForceNew: true, Description: `An optional description of this resource.`, }, + "ip_collection": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + DiffSuppressFunc: AddressIpCollectionDiffSuppress, + Description: `Reference to the source of external IPv4 addresses, like a PublicDelegatedPrefix(PDP) for BYOIP. +The PDP must support enhanced IPv4 allocations. +Use one of the following formats to specify a PDP when reserving an external IPv4 address using BYOIP. +Full resource URL, as in: + * 'https://www.googleapis.com/compute/v1/projects/{{projectId}}/regions/{{region}}/publicDelegatedPrefixes/{{pdp-name}}' +Partial URL, as in: + * 'projects/{{projectId}}/regions/region/publicDelegatedPrefixes/{{pdp-name}}' + * 'regions/{{region}}/publicDelegatedPrefixes/{{pdp-name}}'`, + }, "ip_version": { Type: schema.TypeString, Optional: true, @@ -370,6 +411,12 @@ func resourceComputeAddressCreate(d *schema.ResourceData, meta interface{}) erro } else if v, ok := d.GetOkExists("ipv6_endpoint_type"); !tpgresource.IsEmptyValue(reflect.ValueOf(ipv6EndpointTypeProp)) && (ok || !reflect.DeepEqual(v, ipv6EndpointTypeProp)) { obj["ipv6EndpointType"] = ipv6EndpointTypeProp } + ipCollectionProp, err := expandComputeAddressIpCollection(d.Get("ip_collection"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("ip_collection"); !tpgresource.IsEmptyValue(reflect.ValueOf(ipCollectionProp)) && (ok || !reflect.DeepEqual(v, ipCollectionProp)) { + obj["ipCollection"] = ipCollectionProp + } effectiveLabelsProp, err := expandComputeAddressEffectiveLabels(d.Get("effective_labels"), d, config) if err != nil { return err @@ -586,6 +633,9 @@ func resourceComputeAddressRead(d *schema.ResourceData, meta interface{}) error if err := d.Set("ipv6_endpoint_type", flattenComputeAddressIpv6EndpointType(res["ipv6EndpointType"], d, config)); err != nil { return fmt.Errorf("Error reading Address: %s", err) } + if err := d.Set("ip_collection", flattenComputeAddressIpCollection(res["ipCollection"], d, config)); err != nil { + return fmt.Errorf("Error reading Address: %s", err) + } if err := d.Set("terraform_labels", flattenComputeAddressTerraformLabels(res["labels"], d, config)); err != nil { return fmt.Errorf("Error reading Address: %s", err) } @@ -847,6 +897,10 @@ func flattenComputeAddressIpv6EndpointType(v interface{}, d *schema.ResourceData return v } +func flattenComputeAddressIpCollection(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + func flattenComputeAddressTerraformLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { if v == nil { return v @@ -929,6 +983,10 @@ func expandComputeAddressIpv6EndpointType(v interface{}, d tpgresource.Terraform return v, nil } +func expandComputeAddressIpCollection(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + func expandComputeAddressEffectiveLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) { if v == nil { return map[string]string{}, nil diff --git a/google/services/compute/resource_compute_address_generated_meta.yaml b/google/services/compute/resource_compute_address_generated_meta.yaml index 5e06818cfb1..ddb339f69b3 100644 --- a/google/services/compute/resource_compute_address_generated_meta.yaml +++ b/google/services/compute/resource_compute_address_generated_meta.yaml @@ -11,6 +11,7 @@ fields: - api_field: description - field: effective_labels provider_only: true + - api_field: ipCollection - api_field: ipVersion - api_field: ipv6EndpointType - api_field: labelFingerprint diff --git a/google/services/compute/resource_compute_address_generated_test.go b/google/services/compute/resource_compute_address_generated_test.go index 9637d63feea..d3cf9459575 100644 --- a/google/services/compute/resource_compute_address_generated_test.go +++ b/google/services/compute/resource_compute_address_generated_test.go @@ -301,6 +301,50 @@ resource "google_compute_network" "network" { `, context) } +func TestAccComputeAddress_computeAddressEnhancedByoipExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "root_pdp_url": "projects/tf-static-byoip/regions/us-central1/publicDelegatedPrefixes/tf-enhanced-pdp-136-124-3-120-29", + "sub_pdp_ip_cidr": fmt.Sprintf("136.124.3.%d/32", 120+acctest.RandIntRange(t, 0, 7)), + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckComputeAddressDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeAddress_computeAddressEnhancedByoipExample(context), + }, + { + ResourceName: "google_compute_address.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"labels", "network", "region", "subnetwork", "terraform_labels"}, + }, + }, + }) +} + +func testAccComputeAddress_computeAddressEnhancedByoipExample(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_compute_address" "default" { + name = "tf-test-test-address%{random_suffix}" + region = "us-central1" + ip_collection = google_compute_public_delegated_prefix.sub_pdp.self_link +} + +resource "google_compute_public_delegated_prefix" "sub_pdp" { + name = "tf-test-test-sub-pdp%{random_suffix}" + region = "us-central1" + ip_cidr_range = "%{sub_pdp_ip_cidr}" + parent_prefix = "%{root_pdp_url}" +} +`, context) +} + func testAccCheckComputeAddressDestroyProducer(t *testing.T) func(s *terraform.State) error { return func(s *terraform.State) error { for name, rs := range s.RootModule().Resources { diff --git a/google/services/compute/resource_compute_public_delegated_prefix.go b/google/services/compute/resource_compute_public_delegated_prefix.go index b90ea78e54d..68412f822ff 100644 --- a/google/services/compute/resource_compute_public_delegated_prefix.go +++ b/google/services/compute/resource_compute_public_delegated_prefix.go @@ -165,6 +165,12 @@ except the last character, which cannot be a dash.`, * EXTERNAL_IPV6_FORWARDING_RULE_CREATION * EXTERNAL_IPV6_SUBNETWORK_CREATION * INTERNAL_IPV6_SUBNETWORK_CREATION Possible values: ["DELEGATION", "EXTERNAL_IPV6_FORWARDING_RULE_CREATION", "EXTERNAL_IPV6_SUBNETWORK_CREATION", "INTERNAL_IPV6_SUBNETWORK_CREATION"]`, + }, + "enable_enhanced_ipv4_allocation": { + Type: schema.TypeBool, + Computed: true, + Description: `Whether this PublicDelegatedPrefix supports enhanced IPv4 allocations. +Applicable for IPv4 PDPs only.`, }, "ipv6_access_type": { Type: schema.TypeString, @@ -232,6 +238,12 @@ used to create addresses or further allocations.`, ValidateFunc: verify.ValidateEnum([]string{"INITIALIZING", "READY_TO_ANNOUNCE", "ANNOUNCED", "DELETING", ""}), Description: `The status of the sub public delegated prefix. Possible values: ["INITIALIZING", "READY_TO_ANNOUNCE", "ANNOUNCED", "DELETING"]`, }, + "enable_enhanced_ipv4_allocation": { + Type: schema.TypeBool, + Computed: true, + Description: `Whether this PublicDelegatedSubPrefix supports enhanced IPv4 allocations. +Applicable for IPv4 sub-PDPs only.`, + }, "ipv6_access_type": { Type: schema.TypeString, Computed: true, @@ -434,6 +446,9 @@ func resourceComputePublicDelegatedPrefixRead(d *schema.ResourceData, meta inter if err := d.Set("ipv6_access_type", flattenComputePublicDelegatedPrefixIpv6AccessType(res["ipv6AccessType"], d, config)); err != nil { return fmt.Errorf("Error reading PublicDelegatedPrefix: %s", err) } + if err := d.Set("enable_enhanced_ipv4_allocation", flattenComputePublicDelegatedPrefixEnableEnhancedIpv4Allocation(res["enableEnhancedIpv4Allocation"], d, config)); err != nil { + return fmt.Errorf("Error reading PublicDelegatedPrefix: %s", err) + } if err := d.Set("public_delegated_sub_prefixs", flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixs(res["publicDelegatedSubPrefixs"], d, config)); err != nil { return fmt.Errorf("Error reading PublicDelegatedPrefix: %s", err) } @@ -566,6 +581,10 @@ func flattenComputePublicDelegatedPrefixIpv6AccessType(v interface{}, d *schema. return v } +func flattenComputePublicDelegatedPrefixEnableEnhancedIpv4Allocation(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + func flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixs(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { if v == nil { return v @@ -579,16 +598,17 @@ func flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixs(v interface{}, continue } transformed = append(transformed, map[string]interface{}{ - "name": flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixsName(original["name"], d, config), - "description": flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixsDescription(original["description"], d, config), - "region": flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixsRegion(original["region"], d, config), - "status": flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixsStatus(original["status"], d, config), - "ip_cidr_range": flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixsIpCidrRange(original["ipCidrRange"], d, config), - "is_address": flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixsIsAddress(original["isAddress"], d, config), - "mode": flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixsMode(original["mode"], d, config), - "allocatable_prefix_length": flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixsAllocatablePrefixLength(original["allocatablePrefixLength"], d, config), - "ipv6_access_type": flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixsIpv6AccessType(original["ipv6AccessType"], d, config), - "delegatee_project": flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixsDelegateeProject(original["delegateeProject"], d, config), + "name": flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixsName(original["name"], d, config), + "description": flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixsDescription(original["description"], d, config), + "region": flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixsRegion(original["region"], d, config), + "status": flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixsStatus(original["status"], d, config), + "ip_cidr_range": flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixsIpCidrRange(original["ipCidrRange"], d, config), + "is_address": flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixsIsAddress(original["isAddress"], d, config), + "mode": flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixsMode(original["mode"], d, config), + "allocatable_prefix_length": flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixsAllocatablePrefixLength(original["allocatablePrefixLength"], d, config), + "ipv6_access_type": flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixsIpv6AccessType(original["ipv6AccessType"], d, config), + "enable_enhanced_ipv4_allocation": flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixsEnableEnhancedIpv4Allocation(original["enableEnhancedIpv4Allocation"], d, config), + "delegatee_project": flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixsDelegateeProject(original["delegateeProject"], d, config), }) } return transformed @@ -642,6 +662,10 @@ func flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixsIpv6AccessType( return v } +func flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixsEnableEnhancedIpv4Allocation(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + func flattenComputePublicDelegatedPrefixPublicDelegatedSubPrefixsDelegateeProject(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { return v } diff --git a/google/services/compute/resource_compute_public_delegated_prefix_generated_meta.yaml b/google/services/compute/resource_compute_public_delegated_prefix_generated_meta.yaml index 9ed336c952e..e01ef19029e 100644 --- a/google/services/compute/resource_compute_public_delegated_prefix_generated_meta.yaml +++ b/google/services/compute/resource_compute_public_delegated_prefix_generated_meta.yaml @@ -7,6 +7,7 @@ api_resource_type_kind: PublicDelegatedPrefix fields: - api_field: allocatablePrefixLength - api_field: description + - api_field: enableEnhancedIpv4Allocation - api_field: ipCidrRange - api_field: ipv6AccessType - api_field: isLiveMigration @@ -16,6 +17,7 @@ fields: - api_field: publicDelegatedSubPrefixs.allocatablePrefixLength - api_field: publicDelegatedSubPrefixs.delegateeProject - api_field: publicDelegatedSubPrefixs.description + - api_field: publicDelegatedSubPrefixs.enableEnhancedIpv4Allocation - api_field: publicDelegatedSubPrefixs.ipCidrRange - api_field: publicDelegatedSubPrefixs.ipv6AccessType - api_field: publicDelegatedSubPrefixs.isAddress diff --git a/website/docs/r/compute_address.html.markdown b/website/docs/r/compute_address.html.markdown index ffe197dab7d..4bf74812d6f 100644 --- a/website/docs/r/compute_address.html.markdown +++ b/website/docs/r/compute_address.html.markdown @@ -159,6 +159,28 @@ resource "google_compute_network" "network" { auto_create_subnetworks = false } ``` + +## Example Usage - Compute Address Enhanced Byoip + + +```hcl +resource "google_compute_address" "default" { + name = "test-address" + region = "us-central1" + ip_collection = google_compute_public_delegated_prefix.sub_pdp.self_link +} + +resource "google_compute_public_delegated_prefix" "sub_pdp" { + name = "test-sub-pdp" + region = "us-central1" + ip_cidr_range = ""136.124.3.120/32"" + parent_prefix = ""projects/tf-static-byoip/regions/us-central1/publicDelegatedPrefixes/tf-enhanced-pdp-136-124-3-120-29"" +} +``` ## Argument Reference @@ -251,6 +273,17 @@ The following arguments are supported: the external IPv6 address reservation. Possible values are: `VM`, `NETLB`. +* `ip_collection` - + (Optional) + Reference to the source of external IPv4 addresses, like a PublicDelegatedPrefix(PDP) for BYOIP. + The PDP must support enhanced IPv4 allocations. + Use one of the following formats to specify a PDP when reserving an external IPv4 address using BYOIP. + Full resource URL, as in: + * `https://www.googleapis.com/compute/v1/projects/{{projectId}}/regions/{{region}}/publicDelegatedPrefixes/{{pdp-name}}` + Partial URL, as in: + * `projects/{{projectId}}/regions/region/publicDelegatedPrefixes/{{pdp-name}}` + * `regions/{{region}}/publicDelegatedPrefixes/{{pdp-name}}` + * `region` - (Optional) The Region in which the created address should reside. diff --git a/website/docs/r/compute_public_delegated_prefix.html.markdown b/website/docs/r/compute_public_delegated_prefix.html.markdown index 32a88fa335b..a4305515c42 100644 --- a/website/docs/r/compute_public_delegated_prefix.html.markdown +++ b/website/docs/r/compute_public_delegated_prefix.html.markdown @@ -209,6 +209,10 @@ In addition to the arguments listed above, the following computed attributes are be used privately within Google Cloud. All children PDPs will have access type as INTERNAL. +* `enable_enhanced_ipv4_allocation` - + Whether this PublicDelegatedPrefix supports enhanced IPv4 allocations. + Applicable for IPv4 PDPs only. + * `public_delegated_sub_prefixs` - List of sub public delegated fixes for BYO IP functionality. Each item in this array represents a sub prefix that can be @@ -263,6 +267,11 @@ In addition to the arguments listed above, the following computed attributes are be used privately within Google Cloud. All children PDPs will have access type as INTERNAL. +* `enable_enhanced_ipv4_allocation` - + (Output) + Whether this PublicDelegatedSubPrefix supports enhanced IPv4 allocations. + Applicable for IPv4 sub-PDPs only. + * `delegatee_project` - (Optional) Name of the project scoping this PublicDelegatedSubPrefix.