Skip to content

Commit de43d70

Browse files
authored
Fix permadiff that reorders stateful_external_ip blocks on google_compute_instance_group_manager and google_compute_region_instance_group_manager resources (#9577)
* Make `flattenStatefulPolicyStatefulExternalIps` reorder `stateful_external_ip` fields from API to match user's config * Add unit test for new ordering behaviour of `flattenStatefulPolicyStatefulExternalIps` * Whitespace fix * Update test file to be templated to use GA or Beta version of compute client library * Add new test cases where the config contains no `stateful_external_ip` blocks vs 0 or 1+ in API data * Refactor `flattenStatefulPolicyStatefulExternalIps` to make data ordering and data transformation occur in same loop * Add test case for when nic in TF config is missing in the API response, update code to pass * Remove unused test step * Refactor IP sorting code to be reusable * Update `flattenStatefulPolicyStatefulInternalIps` to reorder IPs * Update unit and acceptance tests following refactor
1 parent ce85734 commit de43d70

6 files changed

+460
-102
lines changed

mmv1/third_party/terraform/services/compute/resource_compute_instance_group_manager.go.erb

+51-19
Original file line numberDiff line numberDiff line change
@@ -778,10 +778,10 @@ func resourceComputeInstanceGroupManagerRead(d *schema.ResourceData, meta interf
778778
if err = d.Set("stateful_disk", flattenStatefulPolicy(manager.StatefulPolicy)); err != nil {
779779
return fmt.Errorf("Error setting stateful_disk in state: %s", err.Error())
780780
}
781-
if err = d.Set("stateful_internal_ip", flattenStatefulPolicyStatefulInternalIps(manager.StatefulPolicy)); err != nil {
781+
if err = d.Set("stateful_internal_ip", flattenStatefulPolicyStatefulInternalIps(d, manager.StatefulPolicy)); err != nil {
782782
return fmt.Errorf("Error setting stateful_internal_ip in state: %s", err.Error())
783783
}
784-
if err = d.Set("stateful_external_ip", flattenStatefulPolicyStatefulExternalIps(manager.StatefulPolicy)); err != nil {
784+
if err = d.Set("stateful_external_ip", flattenStatefulPolicyStatefulExternalIps(d, manager.StatefulPolicy)); err != nil {
785785
return fmt.Errorf("Error setting stateful_external_ip in state: %s", err.Error())
786786
}
787787
if err := d.Set("fingerprint", manager.Fingerprint); err != nil {
@@ -1306,36 +1306,68 @@ func flattenStatefulPolicy(statefulPolicy *compute.StatefulPolicy) []map[string]
13061306
return result
13071307
}
13081308

1309-
func flattenStatefulPolicyStatefulInternalIps(statefulPolicy *compute.StatefulPolicy) []map[string]interface{} {
1309+
func flattenStatefulPolicyStatefulInternalIps(d *schema.ResourceData, statefulPolicy *compute.StatefulPolicy) []map[string]interface{} {
13101310
if statefulPolicy == nil || statefulPolicy.PreservedState == nil || statefulPolicy.PreservedState.InternalIPs == nil {
13111311
return make([]map[string]interface{}, 0, 0)
13121312
}
1313-
result := make([]map[string]interface{}, 0, len(statefulPolicy.PreservedState.InternalIPs))
1314-
for interfaceName, internalIp := range statefulPolicy.PreservedState.InternalIPs {
1315-
data := map[string]interface{}{
1316-
"interface_name": interfaceName,
1317-
"delete_rule": internalIp.AutoDelete,
1318-
}
13191313

1320-
result = append(result, data)
1321-
}
1322-
return result
1314+
return flattenStatefulPolicyStatefulIps(d, "stateful_internal_ip", statefulPolicy.PreservedState.InternalIPs)
13231315
}
13241316

1325-
func flattenStatefulPolicyStatefulExternalIps(statefulPolicy *compute.StatefulPolicy) []map[string]interface{} {
1317+
func flattenStatefulPolicyStatefulExternalIps(d *schema.ResourceData, statefulPolicy *compute.StatefulPolicy) []map[string]interface{} {
13261318
if statefulPolicy == nil || statefulPolicy.PreservedState == nil || statefulPolicy.PreservedState.ExternalIPs == nil {
1327-
return make([]map[string]interface{}, 0, 0)
1319+
return make([]map[string]interface{}, 0)
13281320
}
1329-
result := make([]map[string]interface{}, 0, len(statefulPolicy.PreservedState.ExternalIPs))
1330-
for interfaceName, externalIp := range statefulPolicy.PreservedState.ExternalIPs {
1321+
1322+
return flattenStatefulPolicyStatefulIps(d, "stateful_external_ip", statefulPolicy.PreservedState.ExternalIPs)
1323+
}
1324+
1325+
func flattenStatefulPolicyStatefulIps(d *schema.ResourceData, ipfieldName string, ips map[string]compute.StatefulPolicyPreservedStateNetworkIp) []map[string]interface{} {
1326+
1327+
// statefulPolicy.PreservedState.ExternalIPs and statefulPolicy.PreservedState.InternalIPs are affected by API-side reordering
1328+
// of external/internal IPs, where ordering is done by the interface_name value.
1329+
// Below we intend to reorder the IPs to match the order in the config.
1330+
// Also, data is converted from a map (client library's statefulPolicy.PreservedState.ExternalIPs, or .InternalIPs) to a slice (stored in state).
1331+
// Any IPs found from the API response that aren't in the config are appended to the end of the slice.
1332+
1333+
configIpOrder := d.Get(ipfieldName).([]interface{})
1334+
order := map[string]int{} // record map of interface name to index
1335+
for i, el := range configIpOrder {
1336+
ip := el.(map[string]interface{})
1337+
interfaceName := ip["interface_name"].(string)
1338+
order[interfaceName] = i
1339+
}
1340+
1341+
orderedResult := make([]map[string]interface{}, len(configIpOrder))
1342+
unexpectedIps := []map[string]interface{}{}
1343+
for interfaceName, ip := range ips {
13311344
data := map[string]interface{}{
13321345
"interface_name": interfaceName,
1333-
"delete_rule": externalIp.AutoDelete,
1346+
"delete_rule": ip.AutoDelete,
13341347
}
13351348

1336-
result = append(result, data)
1349+
index, found := order[interfaceName]
1350+
if !found {
1351+
unexpectedIps = append(unexpectedIps, data)
1352+
continue
1353+
}
1354+
orderedResult[index] = data // Put elements from API response in order that matches the config
13371355
}
1338-
return result
1356+
1357+
// Remove any nils from the ordered list. This can occur if the API doesn't include an interface present in the config.
1358+
finalResult := []map[string]interface{}{}
1359+
for _, item := range orderedResult {
1360+
if item != nil {
1361+
finalResult = append(finalResult, item)
1362+
}
1363+
}
1364+
1365+
if len(unexpectedIps) > 0 {
1366+
// Additional IPs returned from API but not in the config are appended to the end of the slice
1367+
finalResult = append(finalResult, unexpectedIps...)
1368+
}
1369+
1370+
return finalResult
13391371
}
13401372

13411373
func flattenUpdatePolicy(updatePolicy *compute.InstanceGroupManagerUpdatePolicy) []map[string]interface{} {

mmv1/third_party/terraform/services/compute/resource_compute_instance_group_manager_internal_test.go

-78
This file was deleted.

0 commit comments

Comments
 (0)