Skip to content

Commit

Permalink
r/distributed_virtual_switch: Refactor - new resource
Browse files Browse the repository at this point in the history
This commit is a major refactor the DVS resoruce provided in PR #135.

More options have been added, the DVS has been fixed so that it uses the
VMware DVS object instead of the generic DVS object, which is more or
less just used for 3rd party DVS switches. This meant that the DVS was
missing a number of features that more than likely would have been
expected in the DVS.

The breadth of the features added can be seen in the documentation. It
should be noted that this does not include the ability to set private
VLANs, filtering policies, or port mirroring sessions, which will be
added at a later date and pending business case.

This work also contains a bunch of up front work that will be necessary
for the vsphere_distributed_port_group resource, which will be following
not too long after this resource.
  • Loading branch information
vancluever committed Oct 8, 2017
1 parent a87c84a commit 8a42c90
Show file tree
Hide file tree
Showing 12 changed files with 3,281 additions and 735 deletions.
585 changes: 585 additions & 0 deletions vsphere/distributed_virtual_port_setting_structure.go

Large diffs are not rendered by default.

169 changes: 106 additions & 63 deletions vsphere/distributed_virtual_switch_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"fmt"

"github.com/hashicorp/terraform/helper/schema"
"github.com/vmware/govmomi"
"github.com/vmware/govmomi/find"
"github.com/vmware/govmomi/object"
Expand All @@ -13,97 +12,141 @@ import (
"github.com/vmware/govmomi/vim25/types"
)

// Get a list of ManagedObjectReference to HostSystem to use in creating the uplinks for the DVS
func getHostSystemManagedObjectReference(d *schema.ResourceData, client *govmomi.Client) (map[string]types.ManagedObjectReference, error) {
mor := make(map[string]types.ManagedObjectReference)

if v, ok := d.GetOk("host"); ok {
for _, vi := range v.([]interface{}) {
hi := vi.(map[string]interface{})
hsID := hi["host_system_id"].(string)

h, err := hostSystemFromID(client, hsID)
if err != nil {
return nil, err
}
mor[hsID] = h.Common.Reference()
}
}
return mor, nil
var dvsVersions = []string{
"5.0.0",
"5.1.0",
"5.5.0",
"6.0.0",
"6.5.0",
}

// Check if a DVS exists and return a reference to it in case it does
func dvsExists(d *schema.ResourceData, meta interface{}) (object.NetworkReference, error) {
client := meta.(*govmomi.Client)
name := d.Get("name").(string)

dc, err := datacenterFromID(client, d.Get("datacenter_id").(string))
// dvsFromUUID gets a DVS object from its UUID.
func dvsFromUUID(client *govmomi.Client, uuid string) (*object.VmwareDistributedVirtualSwitch, error) {
dvsm := types.ManagedObjectReference{Type: "DistributedVirtualSwitchManager", Value: "DVSManager"}
req := &types.QueryDvsByUuid{
This: dvsm,
Uuid: uuid,
}
resp, err := methods.QueryDvsByUuid(context.TODO(), client, req)
if err != nil {
return nil, err
}

finder := find.NewFinder(client.Client, true)
finder = finder.SetDatacenter(dc)

dvs, err := finder.Network(context.TODO(), name)
return dvs, err
return dvsFromMOID(client, resp.Returnval.Reference().Value)
}

func dvsFromName(client *govmomi.Client, dId, name string) (*mo.DistributedVirtualSwitch, error) {
dc, err := datacenterFromID(client, dId)
// dvsFromMOID locates a DVS by its managed object reference ID.
func dvsFromMOID(client *govmomi.Client, id string) (*object.VmwareDistributedVirtualSwitch, error) {
finder := find.NewFinder(client.Client, false)

ref := types.ManagedObjectReference{
Type: "VmwareDistributedVirtualSwitch",
Value: id,
}

ctx, cancel := context.WithTimeout(context.Background(), defaultAPITimeout)
defer cancel()
ds, err := finder.ObjectReference(ctx, ref)
if err != nil {
return nil, err
}
// Should be safe to return here. If our reference returned here and is not a
// VmwareDistributedVirtualSwitch, then we have bigger problems and to be
// honest we should be panicking anyway.
return ds.(*object.VmwareDistributedVirtualSwitch), nil
}

finder := find.NewFinder(client.Client, true)
finder = finder.SetDatacenter(dc)
// dvsFromPath gets a DVS object from its path.
func dvsFromPath(client *govmomi.Client, name string, dc *object.Datacenter) (*object.VmwareDistributedVirtualSwitch, error) {
finder := find.NewFinder(client.Client, false)
if dc != nil {
finder.SetDatacenter(dc)
}

dvs, err := finder.Network(context.TODO(), name)
ctx, cancel := context.WithTimeout(context.Background(), defaultAPITimeout)
defer cancel()
net, err := finder.Network(ctx, name)
if err != nil {
return nil, err
}
if net.Reference().Type != "VmwareDistributedVirtualSwitch" {
return nil, fmt.Errorf("network at path %q is not a VMware distributed virtual switch (type %s)", name, net.Reference().Type)
}
return dvsFromMOID(client, net.Reference().Value)
}

var mdvs mo.DistributedVirtualSwitch
pc := client.PropertyCollector()
// dvsProperties is a convenience method that wraps fetching the DVS MO from
// its higher-level object.
func dvsProperties(dvs *object.VmwareDistributedVirtualSwitch) (*mo.VmwareDistributedVirtualSwitch, error) {
ctx, cancel := context.WithTimeout(context.Background(), defaultAPITimeout)
defer cancel()
if err := pc.RetrieveOne(ctx, dvs.Reference(), nil, &mdvs); err != nil {
return nil, fmt.Errorf("error fetching uuid property: %s", err)
var props mo.VmwareDistributedVirtualSwitch
if err := dvs.Properties(ctx, dvs.Reference(), nil, &props); err != nil {
return nil, err
}
return &mdvs, nil
return &props, nil
}

func dvsFromUuid(client *govmomi.Client, uuid string) (*mo.DistributedVirtualSwitch, error) {
dvsm := types.ManagedObjectReference{Type: "DistributedVirtualSwitchManager", Value: "DVSManager"}
req := &types.QueryDvsByUuid{
This: dvsm,
Uuid: uuid,
// upgradeDVS upgrades a DVS to a specific version. Downgrades are not
// supported and will result in an error. This should be checked before running
// this function.
func upgradeDVS(client *govmomi.Client, dvs *object.VmwareDistributedVirtualSwitch, version string) error {
req := &types.PerformDvsProductSpecOperation_Task{
This: dvs.Reference(),
Operation: "upgrade",
ProductSpec: &types.DistributedVirtualSwitchProductSpec{
Version: version,
},
}
dvs, err := methods.QueryDvsByUuid(context.TODO(), client, req)

ctx, cancel := context.WithTimeout(context.Background(), defaultAPITimeout)
defer cancel()
resp, err := methods.PerformDvsProductSpecOperation_Task(ctx, client, req)
if err != nil {
return nil, fmt.Errorf("error fetching dvs from uuid: %s", err)
return err
}
task := object.NewTask(client.Client, resp.Returnval)
tctx, tcancel := context.WithTimeout(context.Background(), defaultAPITimeout)
defer tcancel()
if err := task.Wait(tctx); err != nil {
return err
}

var mdvs mo.DistributedVirtualSwitch
pc := client.PropertyCollector()
return nil
}

// updateDVSConfiguration contains the atomic update/wait operation for a DVS.
func updateDVSConfiguration(client *govmomi.Client, dvs *object.VmwareDistributedVirtualSwitch, spec *types.VMwareDVSConfigSpec) error {
ctx, cancel := context.WithTimeout(context.Background(), defaultAPITimeout)
defer cancel()
if err := pc.RetrieveOne(ctx, dvs.Returnval.Reference(), nil, &mdvs); err != nil {
return nil, fmt.Errorf("error fetching distributed virtual switch: %s", err)
task, err := dvs.Reconfigure(ctx, spec)
if err != nil {
return err
}
return &mdvs, nil
tctx, tcancel := context.WithTimeout(context.Background(), defaultAPITimeout)
defer tcancel()
if err := task.Wait(tctx); err != nil {
return err
}
return nil
}

// check if host is in refs with the help of hosts
// not very efficient, but the number of entries is usually pretty small
func isHostPartOfDVS(hosts []interface{}, refs map[string]types.ManagedObjectReference, host *types.ManagedObjectReference) map[string]interface{} {
if hosts == nil {
return nil
// enableDVSNetworkResourceManagement exposes the
// EnableNetworkResourceManagement method of the DistributedVirtualSwitch MO.
// This local implementation may go away if this is exposed in the higher-level
// object upstream.
func enableDVSNetworkResourceManagement(client *govmomi.Client, dvs *object.VmwareDistributedVirtualSwitch, enabled bool) error {
req := &types.EnableNetworkResourceManagement{
This: dvs.Reference(),
Enable: enabled,
}
for _, h := range hosts {
hi := h.(map[string]interface{})
if val, ok := refs[hi["host_system_id"].(string)]; ok {
if val == *host {
return hi
}
}

ctx, cancel := context.WithTimeout(context.Background(), defaultAPITimeout)
defer cancel()
_, err := methods.EnableNetworkResourceManagement(ctx, client, req)
if err != nil {
return err
}

return nil
}
Loading

0 comments on commit 8a42c90

Please sign in to comment.