From 3d7727795537cd8c01795c211817e032b25da2e5 Mon Sep 17 00:00:00 2001 From: Chris Marchesi Date: Tue, 26 Sep 2017 14:36:13 -0700 Subject: [PATCH] r/virutal_machine: Fix gateway discovery behavior The current gateway discovery code makes an assumption that any device tracked by VMware tools that is not virtual hardware on the instance will be ordered after any devices that are (even though the device key is properly being used as the source of truth when discovering interfaces). It does this by using the device index in a specific gateway entry as the literal index entry for the corresponding device in the list of devices that have actually been counted for saving in Terraform state. This will either point to the incorrect device or a flat out out-of-bounds value, respectively causing incorrect diffs or crashes. This fixes the situation by searching for the actual device key in the guest network information discovered by VMware tools - at the index specified by the gateway entry, and then searching for that key in the devices being counted for state. The index of the corresponding entry is where the gateway is saved. If any of these searches come up dry, either the gateway has legitimately moved and needs to be fixed or more than likely was not defined in config. Fixes #173. --- vsphere/resource_vsphere_virtual_machine.go | 39 ++++++++++++++++----- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/vsphere/resource_vsphere_virtual_machine.go b/vsphere/resource_vsphere_virtual_machine.go index 005e9b942..d7ce14f58 100644 --- a/vsphere/resource_vsphere_virtual_machine.go +++ b/vsphere/resource_vsphere_virtual_machine.go @@ -1199,16 +1199,39 @@ func resourceVSphereVirtualMachineRead(d *schema.ResourceData, meta interface{}) gatewaySetting = "ipv4_gateway" } if gatewaySetting != "" { - deviceID, err := strconv.Atoi(route.Gateway.Device) - if len(networkInterfaces) == 1 { - deviceID = 0 - } + // We need to get the correct device index which is not always + // aligned with what we have saved in Terraform state. + // + // The index in Device corresponds with the device index in + // Guest.Net, which we can use to discover the key. + did := route.Gateway.Device + nidx, err := strconv.Atoi(did) if err != nil { - log.Printf("[WARN] error at processing %s of device id %#v: %#v", gatewaySetting, route.Gateway.Device, err) - } else { - log.Printf("[DEBUG] %s of device id %d: %s", gatewaySetting, deviceID, route.Gateway.IpAddress) - networkInterfaces[deviceID][gatewaySetting] = route.Gateway.IpAddress + // "device" for some reason is a string, even though its result + // has always been observed to be an int. This should never + // happen, but we warn just in case. + log.Printf("[WARN] error at processing %s of device id %#v: %#v", gatewaySetting, did, err) + continue + } + key := mvm.Guest.Net[nidx].DeviceConfigId + if key < 0 { + // Gateway is not set to any hardware device, ignore. + continue + } + didx := -1 + for n, dev := range networkInterfaces { + if dev["key"] == key { + didx = n + break + } + } + if didx < 0 { + // We are not tracking the device that the gateway is going to + // in state, so just skip the gateway. + continue } + log.Printf("[DEBUG] %s of device id %d: %s", gatewaySetting, didx, route.Gateway.IpAddress) + networkInterfaces[didx][gatewaySetting] = route.Gateway.IpAddress } } }