@@ -778,10 +778,10 @@ func resourceComputeInstanceGroupManagerRead(d *schema.ResourceData, meta interf
778
778
if err = d.Set("stateful_disk", flattenStatefulPolicy(manager.StatefulPolicy)); err != nil {
779
779
return fmt.Errorf("Error setting stateful_disk in state: %s", err.Error())
780
780
}
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 {
782
782
return fmt.Errorf("Error setting stateful_internal_ip in state: %s", err.Error())
783
783
}
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 {
785
785
return fmt.Errorf("Error setting stateful_external_ip in state: %s", err.Error())
786
786
}
787
787
if err := d.Set("fingerprint", manager.Fingerprint); err != nil {
@@ -1306,36 +1306,68 @@ func flattenStatefulPolicy(statefulPolicy *compute.StatefulPolicy) []map[string]
1306
1306
return result
1307
1307
}
1308
1308
1309
- func flattenStatefulPolicyStatefulInternalIps(statefulPolicy *compute.StatefulPolicy) []map[string]interface{} {
1309
+ func flattenStatefulPolicyStatefulInternalIps(d *schema.ResourceData, statefulPolicy *compute.StatefulPolicy) []map[string]interface{} {
1310
1310
if statefulPolicy == nil || statefulPolicy.PreservedState == nil || statefulPolicy.PreservedState.InternalIPs == nil {
1311
1311
return make([]map[string]interface{}, 0, 0)
1312
1312
}
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
- }
1319
1313
1320
- result = append(result, data)
1321
- }
1322
- return result
1314
+ return flattenStatefulPolicyStatefulIps(d, "stateful_internal_ip", statefulPolicy.PreservedState.InternalIPs)
1323
1315
}
1324
1316
1325
- func flattenStatefulPolicyStatefulExternalIps(statefulPolicy *compute.StatefulPolicy) []map[string]interface{} {
1317
+ func flattenStatefulPolicyStatefulExternalIps(d *schema.ResourceData, statefulPolicy *compute.StatefulPolicy) []map[string]interface{} {
1326
1318
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)
1328
1320
}
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 {
1331
1344
data := map[string]interface{}{
1332
1345
"interface_name": interfaceName,
1333
- "delete_rule": externalIp .AutoDelete,
1346
+ "delete_rule": ip .AutoDelete,
1334
1347
}
1335
1348
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
1337
1355
}
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
1339
1371
}
1340
1372
1341
1373
func flattenUpdatePolicy(updatePolicy *compute.InstanceGroupManagerUpdatePolicy) []map[string]interface{} {
0 commit comments