From 2f387e83b810a2e942011c4241b61b6493cf4ad2 Mon Sep 17 00:00:00 2001 From: brian57860 <53904715+brian57860@users.noreply.github.com> Date: Tue, 8 Dec 2020 08:06:54 +0000 Subject: [PATCH 1/4] Added network_interfaces to VM data source --- .../data_source_vsphere_virtual_machine.go | 55 ++++++++++++++++++ ...l_machine_network_interface_subresource.go | 58 +++++++++++++++++++ 2 files changed, 113 insertions(+) diff --git a/vsphere/data_source_vsphere_virtual_machine.go b/vsphere/data_source_vsphere_virtual_machine.go index db8ad7b2b..6f8c798df 100644 --- a/vsphere/data_source_vsphere_virtual_machine.go +++ b/vsphere/data_source_vsphere_virtual_machine.go @@ -5,10 +5,12 @@ import ( "log" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-vsphere/vsphere/internal/helper/structure" "github.com/hashicorp/terraform-provider-vsphere/vsphere/internal/helper/virtualmachine" "github.com/hashicorp/terraform-provider-vsphere/vsphere/internal/virtualdevice" "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/vim25/types" ) func dataSourceVSphereVirtualMachine() *schema.Resource { @@ -81,6 +83,55 @@ func dataSourceVSphereVirtualMachine() *schema.Resource { Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, + "network_interfaces": { + Type: schema.TypeList, + Description: "The types of network interfaces found on the virtual machine, sorted by unit number.", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "adapter_type": { + Type: schema.TypeString, + Computed: true, + }, + "bandwidth_limit": { + Type: schema.TypeInt, + Optional: true, + Default: -1, + Description: "The upper bandwidth limit of this network interface, in Mbits/sec.", + ValidateFunc: validation.IntAtLeast(-1), + }, + "bandwidth_reservation": { + Type: schema.TypeInt, + Optional: true, + Default: 0, + Description: "The bandwidth reservation of this network interface, in Mbits/sec.", + ValidateFunc: validation.IntAtLeast(0), + }, + "bandwidth_share_level": { + Type: schema.TypeString, + Optional: true, + Default: string(types.SharesLevelNormal), + Description: "The bandwidth share allocation level for this interface. Can be one of low, normal, high, or custom.", + ValidateFunc: validation.StringInSlice(sharesLevelAllowedValues, false), + }, + "bandwidth_share_count": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + Description: "The share count for this network interface when the share level is custom.", + ValidateFunc: validation.IntAtLeast(0), + }, + "mac_address": { + Type: schema.TypeString, + Computed: true, + }, + "network_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, "guest_ip_addresses": { Type: schema.TypeList, Description: "The current list of IP addresses on this virtual machine.", @@ -151,6 +202,10 @@ func dataSourceVSphereVirtualMachineRead(d *schema.ResourceData, meta interface{ if err != nil { return fmt.Errorf("error reading network interface types: %s", err) } + networkInterfaces, err := virtualdevice.ReadNetworkInterfaces(object.VirtualDeviceList(props.Config.Hardware.Device)) + if err != nil { + return fmt.Errorf("error reading network interfaces: %s", err) + } if err := d.Set("disks", disks); err != nil { return fmt.Errorf("error setting disk sizes: %s", err) } diff --git a/vsphere/internal/virtualdevice/virtual_machine_network_interface_subresource.go b/vsphere/internal/virtualdevice/virtual_machine_network_interface_subresource.go index 0a66a2ac0..1d2df9d98 100644 --- a/vsphere/internal/virtualdevice/virtual_machine_network_interface_subresource.go +++ b/vsphere/internal/virtualdevice/virtual_machine_network_interface_subresource.go @@ -535,6 +535,64 @@ func ReadNetworkInterfaceTypes(l object.VirtualDeviceList) ([]string, error) { return out, nil } +// ReadNetworkInterfaces returns a list of network interfaces. This is used +// in the VM data source to discover the properties of the network interfaces on the +// virtual machine. The list is sorted by the order that they would be added in +// if a clone were to be done. +func ReadNetworkInterfaces(l object.VirtualDeviceList) ([]map[string]interface{}, error) { + log.Printf("[DEBUG] ReadNetworkInterfaces: Fetching network interfaces") + devices := l.Select(func(device types.BaseVirtualDevice) bool { + if _, ok := device.(types.BaseVirtualEthernetCard); ok { + return true + } + return false + }) + log.Printf("[DEBUG] ReadNetworkInterface: Network devices located: %s", DeviceListString(devices)) + // Sort the device list, in case it's not sorted already. + devSort := virtualDeviceListSorter{ + Sort: devices, + DeviceList: l, + } + sort.Sort(devSort) + devices = devSort.Sort + log.Printf("[DEBUG] ReadNetworkInterfaceTypes: Network devices order after sort: %s", DeviceListString(devices)) + var out []map[string]interface{} + for _, device := range devices { + m := make(map[string]interface{}) + + ethernetCard := device.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard() + + // Determine the network from the backing object + var networkID string + + switch backing := ethernetCard.Backing.(type) { + case *types.VirtualEthernetCardNetworkBackingInfo: + if backing.Network != nil { + networkID = backing.Network.Value + } + case *types.VirtualEthernetCardOpaqueNetworkBackingInfo: + networkID = backing.OpaqueNetworkId + case *types.VirtualEthernetCardDistributedVirtualPortBackingInfo: + networkID = backing.Port.PortgroupKey + default: + } + + // Set properties + + m["adapter_type"] = virtualEthernetCardString(device.(types.BaseVirtualEthernetCard)) + m["bandwidth_limit"] = ethernetCard.ResourceAllocation.Limit + m["bandwidth_reservation"] = ethernetCard.ResourceAllocation.Reservation + m["bandwidth_share_level"] = ethernetCard.ResourceAllocation.Share.Level + m["bandwidth_share_count"] = ethernetCard.ResourceAllocation.Share.Shares + m["mac_address"] = ethernetCard.MacAddress + m["network_id"] = networkID + + out = append(out, m) + } + log.Printf("[DEBUG] ReadNetworkInterfaces: Network interfaces returned: %+v", out) + return out, nil +} + // baseVirtualEthernetCardToBaseVirtualDevice converts a // BaseVirtualEthernetCard value into a BaseVirtualDevice. func baseVirtualEthernetCardToBaseVirtualDevice(v types.BaseVirtualEthernetCard) types.BaseVirtualDevice { From d2079b625a56d39a301bdc346d21f7e8e1aa87a8 Mon Sep 17 00:00:00 2001 From: brian57860 <53904715+brian57860@users.noreply.github.com> Date: Tue, 8 Dec 2020 08:26:20 +0000 Subject: [PATCH 2/4] Added network_interfaces test to VM data source --- .../data_source_vsphere_virtual_machine_test.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/vsphere/data_source_vsphere_virtual_machine_test.go b/vsphere/data_source_vsphere_virtual_machine_test.go index 975269362..b29f70264 100644 --- a/vsphere/data_source_vsphere_virtual_machine_test.go +++ b/vsphere/data_source_vsphere_virtual_machine_test.go @@ -41,6 +41,14 @@ func TestAccDataSourceVSphereVirtualMachine_basic(t *testing.T) { resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.template", "disks.0.unit_number"), resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.template", "disks.0.label"), resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.template", "network_interface_types.#"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.template", "network_interfaces.#"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.template", "network_interfaces.0.adapter_type"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.template", "network_interfaces.0.bandwidth_limit"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.template", "network_interfaces.0.bandwidth_reservation"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.template", "network_interfaces.0.bandwidth_share_level"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.template", "network_interfaces.0.bandwidth_share_count"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.template", "network_interfaces.0.mac_address"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.template", "network_interfaces.0.network_id"), resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.template", "firmware"), ), }, @@ -78,6 +86,14 @@ func TestAccDataSourceVSphereVirtualMachine_noDatacenterAndAbsolutePath(t *testi resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.template", "disks.0.unit_number"), resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.template", "disks.0.label"), resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.template", "network_interface_types.#"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.template", "network_interfaces.#"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.template", "network_interfaces.0.adapter_type"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.template", "network_interfaces.0.bandwidth_limit"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.template", "network_interfaces.0.bandwidth_reservation"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.template", "network_interfaces.0.bandwidth_share_level"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.template", "network_interfaces.0.bandwidth_share_count"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.template", "network_interfaces.0.mac_address"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.template", "network_interfaces.0.network_id"), resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.template", "firmware"), ), }, From a5b14396ee11d8637d7619009751e76f03b7bee8 Mon Sep 17 00:00:00 2001 From: brian57860 <53904715+brian57860@users.noreply.github.com> Date: Tue, 8 Dec 2020 08:58:11 +0000 Subject: [PATCH 3/4] Added network_interfaces to documentation --- website/docs/d/virtual_machine.html.markdown | 21 ++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/website/docs/d/virtual_machine.html.markdown b/website/docs/d/virtual_machine.html.markdown index a83a8c75a..29e75c647 100644 --- a/website/docs/d/virtual_machine.html.markdown +++ b/website/docs/d/virtual_machine.html.markdown @@ -95,6 +95,27 @@ The following attributes are exported: * `network_interface_types` - The network interface types for each network interface found on the virtual machine, in device bus order. Will be one of `e1000`, `e1000e`, `pcnet32`, `sriov`, `vmxnet2`, or `vmxnet3`. +* `network_interfaces` - Information about each of the network interfaces on this + virtual machine or template. These are sorted by device bus order so that they + can be applied to a `vsphere_virtual_machine` resource in the order the resource + expects while cloning. This is useful for discovering certain network interface + settings while performing a linked clone, as all settings that are output by this + data source must be the same on the destination virtual machine as the source. + The sub-attributes are: + * `adapter_type` - The network interface types for each network interface found + on the virtual machine, in device bus order. Will be one of `e1000`, `e1000e` or + `vmxnet3`. + * `bandwidth_limit` - The upper bandwidth limit of this network interface, + in Mbits/sec. + * `bandwidth_reservation` - The bandwidth reservation of this network interface, + in Mbits/sec. + * `bandwidth_share_level` - The bandwidth share allocation level for this interface. + Can be one of `low`, `normal`, `high`, or `custom`. + * `bandwidth_share_count` - The share count for this network interface when the + share level is custom. + * `mac_address` - The MAC address of this network interface. + * `network_id` - The managed object reference ID of the network this interface is + connected to. * `firmware` - The firmware type for this virtual machine. Can be `bios` or `efi`. * `guest_ip_addresses` - A list of IP addresses as reported by VMWare tools. From c73fd6dbe4ecab2191143c496e34cc00c6905cf2 Mon Sep 17 00:00:00 2001 From: brian57860 <53904715+brian57860@users.noreply.github.com> Date: Tue, 8 Dec 2020 13:53:40 +0000 Subject: [PATCH 4/4] Set network_interfaces in data source --- vsphere/data_source_vsphere_virtual_machine.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vsphere/data_source_vsphere_virtual_machine.go b/vsphere/data_source_vsphere_virtual_machine.go index 6f8c798df..1219b83c2 100644 --- a/vsphere/data_source_vsphere_virtual_machine.go +++ b/vsphere/data_source_vsphere_virtual_machine.go @@ -212,6 +212,9 @@ func dataSourceVSphereVirtualMachineRead(d *schema.ResourceData, meta interface{ if err := d.Set("network_interface_types", nics); err != nil { return fmt.Errorf("error setting network interface types: %s", err) } + if err := d.Set("network_interfaces", networkInterfaces); err != nil { + return fmt.Errorf("error setting network interfaces: %s", err) + } if props.Guest != nil { if err := buildAndSelectGuestIPs(d, *props.Guest); err != nil { return fmt.Errorf("error setting guest IP addresses: %s", err)