Skip to content
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

[WIP] provider/vsphere: reliable network interface indices #7154

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 73 additions & 11 deletions builtin/providers/vsphere/resource_vsphere_virtual_machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"strconv"
"strings"

"github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/helper/schema"
"github.com/vmware/govmomi"
"github.com/vmware/govmomi/find"
Expand Down Expand Up @@ -93,6 +94,18 @@ type virtualMachine struct {
customConfigurations map[string](types.AnyType)
}

func NetInterfaceID(v interface{}) int {
device_key := v.(map[string]interface{})["device_key"].(string)
id, err := strconv.Atoi(device_key)
if err != nil {
log.Printf("[WARNING] using fallback hashing of network interface device id %s. %v", device_key, err)
// default hash method from terraform/helper/schema/set.go
return hashcode.String(device_key)
} else {
return id
}
}

func (v virtualMachine) Path() string {
return vmPath(v.folder, v.name)
}
Expand Down Expand Up @@ -264,11 +277,18 @@ func resourceVSphereVirtualMachine() *schema.Resource {
},

"network_interface": &schema.Schema{
Type: schema.TypeList,
Type: schema.TypeSet,
Set: NetInterfaceID,
Required: true,
ForceNew: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"device_key": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
},

"label": &schema.Schema{
Type: schema.TypeString,
Required: true,
Expand Down Expand Up @@ -870,7 +890,7 @@ func resourceVSphereVirtualMachineCreate(d *schema.ResourceData, meta interface{
log.Printf("[DEBUG] cdrom init: %v", cdroms)
}

err := vm.setupVirtualMachine(client)
err := vm.setupVirtualMachine(d, client)
if err != nil {
return err
}
Expand Down Expand Up @@ -910,6 +930,11 @@ func resourceVSphereVirtualMachineRead(d *schema.ResourceData, meta interface{})
return err
}

// device_list, err := vm.Device(context.TODO())
// if err != nil {
// return err
// }

log.Printf("[DEBUG] Datacenter - %#v", dc)
log.Printf("[DEBUG] mvm.Summary.Config - %#v", mvm.Summary.Config)
log.Printf("[DEBUG] mvm.Summary.Config - %#v", mvm.Config)
Expand Down Expand Up @@ -983,11 +1008,14 @@ func resourceVSphereVirtualMachineRead(d *schema.ResourceData, meta interface{})
return fmt.Errorf("Invalid disks to set: %#v", disks)
}

networkInterfaces := make([]map[string]interface{}, 0)
networkInterfaces := make(map[string]map[string]interface{}, 0)
for _, v := range mvm.Guest.Net {
if v.DeviceConfigId >= 0 {
log.Printf("[DEBUG] v.Network - %#v", v.Network)
networkInterface := make(map[string]interface{})
log.Printf("[DEBUG] mvm.Config.Hardware.Device - %#v", mvm.Config.Hardware.Device)
device_key := strconv.Itoa(int(v.DeviceConfigId))
networkInterface["device_key"] = device_key
networkInterface["label"] = v.Network
networkInterface["mac_address"] = v.MacAddress
for _, ip := range v.IpConfig.IpAddress {
Expand All @@ -1006,9 +1034,13 @@ func resourceVSphereVirtualMachineRead(d *schema.ResourceData, meta interface{})
log.Printf("[DEBUG] networkInterface: %#v", networkInterface)
}
log.Printf("[DEBUG] networkInterface: %#v", networkInterface)
networkInterfaces = append(networkInterfaces, networkInterface)
networkInterfaces[device_key] = networkInterface
}
}

// IP for SetConnInfo
connect_ip := ""

if mvm.Guest.IpStack != nil {
for _, v := range mvm.Guest.IpStack {
if v.IpRouteConfig != nil && v.IpRouteConfig.IpRoute != nil {
Expand All @@ -1025,25 +1057,34 @@ func resourceVSphereVirtualMachineRead(d *schema.ResourceData, meta interface{})
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_key := strconv.Itoa(int(mvm.Guest.Net[deviceID].DeviceConfigId))
log.Printf("[DEBUG] %s of device id %d (key %s): %s", gatewaySetting, deviceID, device_key, route.Gateway.IpAddress)
networkInterfaces[device_key][gatewaySetting] = route.Gateway.IpAddress
if gatewaySetting == "ipv4_gateway" {
connect_ip = networkInterfaces[device_key]["ipv4_address"].(string)
}
}
}
}
}
}
}
}
networkInterfaces_slice := []map[string]interface{}{}
for _, value := range networkInterfaces {
networkInterfaces_slice = append(networkInterfaces_slice, value)
}
log.Printf("[DEBUG] networkInterfaces: %#v", networkInterfaces)
err = d.Set("network_interface", networkInterfaces)
log.Printf("[DEBUG] networkInterfaces_slice: %#v", networkInterfaces_slice)
err = d.Set("network_interface", networkInterfaces_slice)
if err != nil {
return fmt.Errorf("Invalid network interfaces to set: %#v", networkInterfaces)
return fmt.Errorf("Invalid network interfaces to set: %#v", networkInterfaces_slice)
}

log.Printf("[DEBUG] ip address: %v", networkInterfaces[0]["ipv4_address"].(string))
log.Printf("[DEBUG] ip address: %v", connect_ip)
d.SetConnInfo(map[string]string{
"type": "ssh",
"host": networkInterfaces[0]["ipv4_address"].(string),
"host": connect_ip,
})

var rootDatastore string
Expand Down Expand Up @@ -1462,7 +1503,7 @@ func createCdroms(vm *object.VirtualMachine, cdroms []cdrom) error {
return nil
}

func (vm *virtualMachine) setupVirtualMachine(c *govmomi.Client) error {
func (vm *virtualMachine) setupVirtualMachine(d *schema.ResourceData, c *govmomi.Client) error {
dc, err := getDatacenter(c, vm.datacenter)

if err != nil {
Expand Down Expand Up @@ -1751,22 +1792,43 @@ func (vm *virtualMachine) setupVirtualMachine(c *govmomi.Client) error {
return err
}

var known_devices map[string]bool

for _, dvc := range devices {
// Issue 3559/3560: Delete all ethernet devices to add the correct ones later
// Also required to get a reliable mapping from vsphere device to device in config
if devices.Type(dvc) == "ethernet" {
err := newVM.RemoveDevice(context.TODO(), false, dvc)
if err != nil {
return err
}
} else {
known_devices[strconv.Itoa(int(dvc.GetVirtualDevice().Key))] = true
}
}

// Add Network devices
for _, dvc := range networkDevices {
err := newVM.AddDevice(
context.TODO(), dvc.GetVirtualDeviceConfigSpec().Device)
if err != nil {
return err
}
// get refreshed device list
refreshed_devices, err := newVM.Device(context.TODO())
if err != nil {
log.Printf("[ERROR] Getting new list of devices failed")
return err
}
// look for unknown device name => has to be added device
for _, new_dvc := range refreshed_devices {
device_key := strconv.Itoa(int(new_dvc.GetVirtualDevice().Key))
if !known_devices[device_key] {
key_name := fmt.Sprintf("network_interfaces.%v.device_key", device_key)
known_devices[device_key] = true
d.Set(key_name, device_key)
}
}
}

// Create the cdroms if needed.
Expand Down