-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Added new fields ipVersion and ipCollection to secondaryIpRange in compute subnetwork resource to support secondary IPv6 ranges. #17412
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
eb3b688
03a48d7
fbb1b14
9ede616
87059d6
37bc4da
268b107
af10f4a
b343043
3ef28d5
b008252
b6a680c
352b4a1
1e9f31e
20ca448
fda0adb
bd85719
b6e20da
9a87968
952df8d
67bf892
b731e13
9188282
6ef9339
0b9bc8a
055860e
4bc9a50
e3cdcce
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -67,7 +67,7 @@ func IpDiffSuppress(_, old, new string, d *schema.ResourceData) bool { | |
| addr_netmask_old := strings.Split(old, "/") | ||
| addr_netmask_new := strings.Split(new, "/") | ||
|
|
||
| if (!((len(addr_netmask_old)) == 2 && (len(addr_netmask_new) == 2))) { | ||
| if !((len(addr_netmask_old)) == 2 && (len(addr_netmask_new) == 2)) { | ||
| return false | ||
| } | ||
|
|
||
|
|
@@ -85,3 +85,138 @@ func IpDiffSuppress(_, old, new string, d *schema.ResourceData) bool { | |
|
|
||
| return addr_equality && netmask_equality | ||
| } | ||
|
|
||
| // CustomDiff function for secondary_ip_range. | ||
| // Normalizes old state and new config sets before Set comparison to prevent false TypeSet diffs. | ||
| // Specifically handles two Beta-only scenarios where state diverges from HCL config: | ||
| // 1. Automatically inherits allocated ULA CIDRs from state when omitted in HCL config. | ||
| // 2. Normalizes ip_collection self-links to relative paths to match user config short names. | ||
| func resourceComputeSubnetworkSecondaryIpRangeCustomDiff(_ context.Context, diff *schema.ResourceDiff, meta interface{}) error { | ||
| return resourceComputeSubnetworkSecondaryIpRangeCustomDiffFunc(diff) | ||
| } | ||
|
|
||
| func resourceComputeSubnetworkSecondaryIpRangeCustomDiffFunc(diff tpgresource.TerraformResourceDiff) error { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We now have two handwritten custom diff functions on the same parent field (technically three customdiffs total). For maintenance, I believe we should consider refactoring them to a single, large function so the different states and diff outcomes can be followed along within a single function vs mentally mapping them sequentially. Maybe not for this PR as it's already large and having a large amount of testing as is. |
||
| {{ if and (ne $.TargetVersionName `ga`) (and (ne $.ProductMetadata.Compiler `terraformgoogleconversion-codegen`) (ne $.ProductMetadata.Compiler `terraformgoogleconversionnext-codegen`)) -}} | ||
| if len(diff.GetChangedKeysPrefix("secondary_ip_range")) == 0 { | ||
| return nil | ||
| } | ||
|
|
||
| oldCount, newCount := diff.GetChange("secondary_ip_range.#") | ||
| count := oldCount.(int) | ||
| if newCount.(int) > count { | ||
| count = newCount.(int) | ||
| } | ||
| if count < 1 { | ||
| return nil | ||
| } | ||
|
|
||
| // Extract pristine user CIDR config directly from HCL | ||
| configCidrByName := make(map[string]string) | ||
| rawConfig := diff.GetRawConfig().GetAttr("secondary_ip_range") | ||
| if rawConfig.IsKnown() && !rawConfig.IsNull() { | ||
| for _, item := range rawConfig.AsValueSlice() { | ||
| if item.IsKnown() && !item.IsNull() && item.GetAttr("range_name").IsKnown() && !item.GetAttr("range_name").IsNull() { | ||
| nameVal := item.GetAttr("range_name").AsString() | ||
| if nameVal != "" { | ||
| if cidrVal := item.GetAttr("ip_cidr_range"); cidrVal.IsKnown() && !cidrVal.IsNull() { | ||
| configCidrByName[nameVal] = cidrVal.AsString() | ||
| } else { | ||
| configCidrByName[nameVal] = "" | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Extract old state and new proposed maps | ||
| oldByName := make(map[string]map[string]interface{}) | ||
| var oldList, newList []interface{} | ||
| for i := 0; i < count; i++ { | ||
| o, n := diff.GetChange(fmt.Sprintf("secondary_ip_range.%d", i)) | ||
| if o != nil { | ||
| oldList = append(oldList, o) | ||
| if m, ok := o.(map[string]interface{}); ok && m["range_name"] != nil { | ||
| oldByName[m["range_name"].(string)] = m | ||
| } | ||
| } | ||
| if n != nil { | ||
| newList = append(newList, n) | ||
| } | ||
| } | ||
|
|
||
| // Helper: normalizes CIDR strings and ip_collection self-links | ||
| normalizeItem := func(m map[string]interface{}, overrideCidr string) map[string]interface{} { | ||
| clean := make(map[string]interface{}) | ||
| for k, v := range m { | ||
| if k == "ip_cidr_range" { | ||
| cidrStr, _ := v.(string) | ||
| if overrideCidr != "" { | ||
| cidrStr = overrideCidr | ||
| } | ||
| if cidrStr == "" { | ||
| continue | ||
| } | ||
| if ip, ipNet, err := net.ParseCIDR(cidrStr); err == nil { | ||
| maskSize, _ := ipNet.Mask.Size() | ||
| cidrStr = fmt.Sprintf("%s/%d", ip.String(), maskSize) | ||
| } | ||
| clean[k] = cidrStr | ||
| continue | ||
| } | ||
| if v == nil || v == "" { | ||
| continue | ||
| } | ||
| if k == "ip_collection" { | ||
| if rel, err := tpgresource.GetRelativePath(v.(string)); err == nil { | ||
| clean[k] = rel | ||
| } else { | ||
| clean[k] = v | ||
| } | ||
| } else { | ||
| clean[k] = v | ||
| } | ||
| } | ||
| return clean | ||
| } | ||
|
|
||
| // Build clean normalized sets | ||
| var normalizedOld, normalizedNew []interface{} | ||
| for _, o := range oldList { | ||
| normalizedOld = append(normalizedOld, normalizeItem(o.(map[string]interface{}), "")) | ||
| } | ||
| for _, n := range newList { | ||
| m := n.(map[string]interface{}) | ||
| rangeName, _ := m["range_name"].(string) | ||
| userCidr := configCidrByName[rangeName] | ||
| if userCidr == "" { | ||
| // Inherit allocated state CIDR for ULA ranges | ||
| if oldItem, ok := oldByName[rangeName]; ok && oldItem["ip_cidr_range"] != nil { | ||
| userCidr, _ = oldItem["ip_cidr_range"].(string) | ||
| } | ||
| } | ||
| normalizedNew = append(normalizedNew, normalizeItem(m, userCidr)) | ||
| } | ||
|
|
||
| // Compare Sets and Clear Diff | ||
| var hashFunc schema.SchemaSetFunc | ||
| if ResourceComputeSubnetwork().Schema != nil && ResourceComputeSubnetwork().Schema["secondary_ip_range"] != nil { | ||
| hashFunc = schema.HashResource(ResourceComputeSubnetwork().Schema["secondary_ip_range"].Elem.(*schema.Resource)) | ||
| } else { | ||
| hashFunc = func(v interface{}) int { | ||
| buf := &bytes.Buffer{} | ||
| json.NewEncoder(buf).Encode(v) | ||
| return schema.HashString(buf.String()) | ||
| } | ||
| } | ||
|
|
||
| if schema.NewSet(hashFunc, normalizedOld).Equal(schema.NewSet(hashFunc, normalizedNew)) { | ||
| if err := diff.Clear("secondary_ip_range"); err != nil { | ||
| return err | ||
| } | ||
| } | ||
|
|
||
| return nil | ||
| {{ else -}} | ||
| return nil | ||
| {{ end -}} | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| resource "google_compute_subnetwork" "{{$.PrimaryResourceId}}" { | ||
| provider = google-beta | ||
| name = "{{index $.Vars "subnetwork_name"}}" | ||
| region = "us-central1" | ||
| network = google_compute_network.custom-test.id | ||
| stack_type = "IPV6_ONLY" | ||
| ipv6_access_type = "INTERNAL" | ||
|
|
||
| secondary_ip_range { | ||
| range_name = "v6-ula" | ||
| ip_version = "IPV6" | ||
| } | ||
|
|
||
| secondary_ip_range { | ||
| range_name = "v6-byogua-auto" | ||
| ip_version = "IPV6" | ||
| ip_collection = google_compute_public_delegated_prefix.ipv6_sub_pdp.self_link | ||
| } | ||
|
|
||
| secondary_ip_range { | ||
| range_name = "v6-byogua-manual" | ||
| ip_version = "IPV6" | ||
| ip_collection = google_compute_public_delegated_prefix.ipv6_sub_pdp.self_link | ||
| ip_cidr_range = "2001:db8:0:2::/64" | ||
| } | ||
| } | ||
|
|
||
| resource "google_compute_network" "custom-test" { | ||
| provider = google-beta | ||
| name = "{{index $.Vars "network_name"}}" | ||
| auto_create_subnetworks = false | ||
| enable_ula_internal_ipv6 = true | ||
| } | ||
|
|
||
| resource "google_compute_public_advertised_prefix" "ipv6_pap" { | ||
| provider = google-beta | ||
| name = "{{index $.Vars "pap_name"}}" | ||
| ip_cidr_range = "2001:db8::/40" | ||
| pdp_scope = "REGIONAL" | ||
| ipv6_access_type = "INTERNAL" | ||
| description = "GOOGLE_INTERNAL_TEST_PREFIX" | ||
| } | ||
|
|
||
| resource "google_compute_public_delegated_prefix" "ipv6_pdp" { | ||
| provider = google-beta | ||
| name = "{{index $.Vars "pdp_name"}}" | ||
| region = "us-central1" | ||
| description = "PDP in internal subnet mode" | ||
| ip_cidr_range = "2001:db8::/48" | ||
| parent_prefix = google_compute_public_advertised_prefix.ipv6_pap.id | ||
| mode = "DELEGATION" | ||
| } | ||
|
|
||
| resource "google_compute_public_delegated_prefix" "ipv6_sub_pdp" { | ||
| provider = google-beta | ||
| name = "{{index $.Vars "sub_pdp_name"}}" | ||
| region = "us-central1" | ||
| ip_cidr_range = "2001:db8::/56" | ||
| parent_prefix = google_compute_public_delegated_prefix.ipv6_pdp.id | ||
| mode = "INTERNAL_IPV6_SUBNETWORK_CREATION" | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.