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

Discovery network interfaces from pci devices instead from Guest information #129

Merged
merged 6 commits into from
Aug 17, 2017
Merged
Show file tree
Hide file tree
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
86 changes: 67 additions & 19 deletions vsphere/resource_vsphere_virtual_machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,11 @@ func resourceVSphereVirtualMachine() *schema.Resource {
ForceNew: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"key": &schema.Schema{
Type: schema.TypeInt,
Computed: true,
},

"label": &schema.Schema{
Type: schema.TypeString,
Required: true,
Expand Down Expand Up @@ -979,7 +984,7 @@ func resourceVSphereVirtualMachineRead(d *schema.ResourceData, meta interface{})

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)
log.Printf("[DEBUG] mvm.Config - %#v", mvm.Config)
log.Printf("[DEBUG] mvm.Guest.Net - %#v", mvm.Guest.Net)

err = d.Set("moid", mvm.Reference().Value)
Expand Down Expand Up @@ -1058,31 +1063,49 @@ func resourceVSphereVirtualMachineRead(d *schema.ResourceData, meta interface{})
}

networkInterfaces := make([]map[string]interface{}, 0)

deviceList := object.VirtualDeviceList(mvm.Config.Hardware.Device)
deviceList = deviceList.SelectByType((*types.VirtualEthernetCard)(nil))
log.Printf("[DEBUG] Device list %+v", deviceList)
for _, device := range deviceList {
networkInterface := make(map[string]interface{})
virtualDevice := device.GetVirtualDevice()
nic := device.(types.BaseVirtualEthernetCard)
DeviceName, _ := getNetworkName(client, vm, nic)
log.Printf("[DEBUG] device name %s", DeviceName)
networkInterface["label"] = DeviceName
networkInterface["mac_address"] = nic.GetVirtualEthernetCard().MacAddress
networkInterface["key"] = virtualDevice.Key
log.Printf("[DEBUG] networkInterface %#v", networkInterface)
networkInterfaces = append(networkInterfaces, networkInterface)
}
log.Printf("[DEBUG] networks: %#v", networkInterfaces)

for _, v := range mvm.Guest.Net {
if v.DeviceConfigId >= 0 {
log.Printf("[DEBUG] v.Network - %#v", v.Network)
networkInterface := make(map[string]interface{})
networkInterface["label"] = v.Network
networkInterface["mac_address"] = v.MacAddress
for _, ip := range v.IpConfig.IpAddress {
p := net.ParseIP(ip.IpAddress)
if p.To4() != nil {
log.Printf("[DEBUG] p.String - %#v", p.String())
log.Printf("[DEBUG] ip.PrefixLength - %#v", ip.PrefixLength)
networkInterface["ipv4_address"] = p.String()
networkInterface["ipv4_prefix_length"] = ip.PrefixLength
} else if p.To16() != nil {
log.Printf("[DEBUG] p.String - %#v", p.String())
log.Printf("[DEBUG] ip.PrefixLength - %#v", ip.PrefixLength)
networkInterface["ipv6_address"] = p.String()
networkInterface["ipv6_prefix_length"] = ip.PrefixLength
for _, networkInterface := range networkInterfaces {
if networkInterface["key"] == v.DeviceConfigId {
for _, ip := range v.IpConfig.IpAddress {
p := net.ParseIP(ip.IpAddress)
if p.To4() != nil {
log.Printf("[DEBUG] p.String - %#v", p.String())
log.Printf("[DEBUG] ip.PrefixLength - %#v", ip.PrefixLength)
networkInterface["ipv4_address"] = p.String()
networkInterface["ipv4_prefix_length"] = ip.PrefixLength
} else if p.To16() != nil {
log.Printf("[DEBUG] p.String - %#v", p.String())
log.Printf("[DEBUG] ip.PrefixLength - %#v", ip.PrefixLength)
networkInterface["ipv6_address"] = p.String()
networkInterface["ipv6_prefix_length"] = ip.PrefixLength
}
}
log.Printf("[DEBUG] networkInterface: %#v", networkInterface)
}
log.Printf("[DEBUG] networkInterface: %#v", networkInterface)
}
log.Printf("[DEBUG] networkInterface: %#v", networkInterface)
networkInterfaces = append(networkInterfaces, networkInterface)
}
}
log.Printf("[DEBUG] networks: %#v", networkInterfaces)
if mvm.Guest.IpStack != nil {
for _, v := range mvm.Guest.IpStack {
if v.IpRouteConfig != nil && v.IpRouteConfig.IpRoute != nil {
Expand Down Expand Up @@ -2164,3 +2187,28 @@ func (vm *virtualMachine) setupVirtualMachine(c *govmomi.Client) error {
}
return nil
}
func getNetworkName(c *govmomi.Client, vm *object.VirtualMachine, nic types.BaseVirtualEthernetCard) (string, error) {
backingInfo := nic.GetVirtualEthernetCard().Backing
var deviceName string
switch backingInfo.(type) {
case *types.VirtualEthernetCardNetworkBackingInfo:
deviceName = backingInfo.(*types.VirtualEthernetCardNetworkBackingInfo).DeviceName
break
case *types.VirtualEthernetCardDistributedVirtualPortBackingInfo:
portInfo := backingInfo.(*types.VirtualEthernetCardDistributedVirtualPortBackingInfo).Port
log.Printf("network Port %#v", portInfo)
o := object.NewDistributedVirtualPortgroup(c.Client, types.ManagedObjectReference{
Type: "DistributedVirtualPortgroup",
Value: portInfo.PortgroupKey,
})
var dvp mo.DistributedVirtualPortgroup
err := o.Properties(context.TODO(), o.Reference(), []string{"name", "config.distributedVirtualSwitch"}, &dvp)
if err != nil {
log.Printf("[ERROR]: Error retrieving portgroup %v", err)
return "", err
}
deviceName = dvp.Name
}
log.Printf("network Port DeviceName %#v", deviceName)
return deviceName, nil
}
77 changes: 76 additions & 1 deletion vsphere/resource_vsphere_virtual_machine_test.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
package vsphere

import (
"errors"
"fmt"
"log"
"os"
"regexp"
"testing"
"time"

"path/filepath"

"context"

"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"github.com/vmware/govmomi"
Expand All @@ -17,7 +21,6 @@ import (
"github.com/vmware/govmomi/property"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
"golang.org/x/net/context"
)

///////
Expand Down Expand Up @@ -294,6 +297,39 @@ func TestAccVSphereVirtualMachine_basic(t *testing.T) {
})
}

func TestAccVSphereVirtualMachine_noPanicShutdown(t *testing.T) {
var vm virtualMachine
basic_vars := setupTemplateBasicBodyVars()
config := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_really_basic)

log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_really_basic)
log.Printf("[DEBUG] template config= %s", config)

resource.Test(t, resource.TestCase{
PreCheck: func() { testBasicPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: config,
Check: resource.ComposeTestCheckFunc(
TestFuncData{vm: vm, label: basic_vars.label}.testCheckFuncBasic(),
),
},
resource.TestStep{
PreConfig: func() {
if err := testPowerOffVM("terraform-test"); err != nil {
panic(err)
}
},
PlanOnly: true,
Config: config,
ExpectNonEmptyPlan: true,
},
},
})
}

const testAccCheckVSphereVirtualMachineConfig_debug = `
provider "vsphere" {
client_debug = true
Expand Down Expand Up @@ -1153,6 +1189,45 @@ func TestAccVSphereVirtualMachine_mac_address(t *testing.T) {
})
}

// testPowerOffVM does an immediate power-off of the virtual machine and is
// used to help set up a refresh scenario where a VM is powered off, which has
// been a source of panics.
func testPowerOffVM(name string) error {
client := testAccProvider.Meta().(*govmomi.Client)
finder := find.NewFinder(client.Client, true)

dc, err := getDatacenter(client, os.Getenv("VSPHERE_DATACENTER"))
if err != nil {
return fmt.Errorf("error fetching datacenter: %s", err)
}

finder.SetDatacenter(dc)
if err != nil {
return fmt.Errorf("error finding datacenter: %s", err)
}

vm, err := finder.VirtualMachine(context.TODO(), name)
if err != nil {
return err
}
if vm == nil {
return fmt.Errorf("VM not found: %s", name)
}
task, err := vm.PowerOff(context.TODO())
if err != nil {
return fmt.Errorf("error powering off VM: %s", err)
}
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*5)
defer cancel()
if err := task.Wait(ctx); err != nil {
return fmt.Errorf("error waiting for poweroff: %s", err)
}
if ctx.Err() == context.Canceled {
return errors.New("timeout waiting for VM to shutdown")
}
return nil
}

func testAccCheckVSphereVirtualMachineDestroy(s *terraform.State) error {
client := testAccProvider.Meta().(*govmomi.Client)
finder := find.NewFinder(client.Client, true)
Expand Down