Fix for Support selection of datastore for dynamic provisioning in vSphere

This commit is contained in:
Balu Dontu
2017-02-16 16:12:01 -08:00
committed by Ritesh H Shukla
parent b201ac2f8f
commit 12f75f0b86
83 changed files with 8640 additions and 504 deletions

View File

@@ -17,15 +17,17 @@ limitations under the License.
package object
import (
"context"
"errors"
"fmt"
"net"
"path"
"github.com/vmware/govmomi/property"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/methods"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
"golang.org/x/net/context"
)
const (
@@ -227,9 +229,12 @@ func (v VirtualMachine) WaitForIP(ctx context.Context) (string, error) {
// WaitForNetIP waits for the VM guest.net property to report an IP address for all VM NICs.
// Only consider IPv4 addresses if the v4 param is true.
// By default, wait for all NICs to get an IP address, unless 1 or more device is given.
// A device can be specified by the MAC address or the device name, e.g. "ethernet-0".
// Returns a map with MAC address as the key and IP address list as the value.
func (v VirtualMachine) WaitForNetIP(ctx context.Context, v4 bool) (map[string][]string, error) {
func (v VirtualMachine) WaitForNetIP(ctx context.Context, v4 bool, device ...string) (map[string][]string, error) {
macs := make(map[string][]string)
eths := make(map[string]string)
p := property.DefaultCollector(v.c)
@@ -240,14 +245,15 @@ func (v VirtualMachine) WaitForNetIP(ctx context.Context, v4 bool) (map[string][
continue
}
devices := c.Val.(types.ArrayOfVirtualDevice).VirtualDevice
for _, device := range devices {
if nic, ok := device.(types.BaseVirtualEthernetCard); ok {
devices := VirtualDeviceList(c.Val.(types.ArrayOfVirtualDevice).VirtualDevice)
for _, d := range devices {
if nic, ok := d.(types.BaseVirtualEthernetCard); ok {
mac := nic.GetVirtualEthernetCard().MacAddress
if mac == "" {
return false
}
macs[mac] = nil
eths[devices.Name(d)] = mac
}
}
}
@@ -255,6 +261,17 @@ func (v VirtualMachine) WaitForNetIP(ctx context.Context, v4 bool) (map[string][
return true
})
if len(device) != 0 {
// Only wait for specific NIC(s)
macs = make(map[string][]string)
for _, mac := range device {
if eth, ok := eths[mac]; ok {
mac = eth // device name, e.g. "ethernet-0"
}
macs[mac] = nil
}
}
err = property.Wait(ctx, p, v.Reference(), []string{"guest.net"}, func(pc []types.PropertyChange) bool {
for _, c := range pc {
if c.Op != types.PropertyChangeOpAssign {
@@ -300,18 +317,28 @@ func (v VirtualMachine) WaitForNetIP(ctx context.Context, v4 bool) (map[string][
func (v VirtualMachine) Device(ctx context.Context) (VirtualDeviceList, error) {
var o mo.VirtualMachine
err := v.Properties(ctx, v.Reference(), []string{"config.hardware.device"}, &o)
err := v.Properties(ctx, v.Reference(), []string{"config.hardware.device", "summary.runtime.connectionState"}, &o)
if err != nil {
return nil, err
}
// Quoting the SDK doc:
// The virtual machine configuration is not guaranteed to be available.
// For example, the configuration information would be unavailable if the server
// is unable to access the virtual machine files on disk, and is often also unavailable
// during the initial phases of virtual machine creation.
if o.Config == nil {
return nil, fmt.Errorf("%s Config is not available, connectionState=%s",
v.Reference(), o.Summary.Runtime.ConnectionState)
}
return VirtualDeviceList(o.Config.Hardware.Device), nil
}
func (v VirtualMachine) HostSystem(ctx context.Context) (*HostSystem, error) {
var o mo.VirtualMachine
err := v.Properties(ctx, v.Reference(), []string{"summary"}, &o)
err := v.Properties(ctx, v.Reference(), []string{"summary.runtime.host"}, &o)
if err != nil {
return nil, err
}
@@ -470,24 +497,102 @@ func (v VirtualMachine) RemoveAllSnapshot(ctx context.Context, consolidate *bool
return NewTask(v.c, res.Returnval), nil
}
// RevertToSnapshot reverts to a named snapshot
func (v VirtualMachine) RevertToSnapshot(ctx context.Context, name string, suppressPowerOn bool) (*Task, error) {
type snapshotMap map[string][]Reference
func (m snapshotMap) add(parent string, tree []types.VirtualMachineSnapshotTree) {
for i, st := range tree {
sname := st.Name
names := []string{sname, st.Snapshot.Value}
if parent != "" {
sname = path.Join(parent, sname)
// Add full path as an option to resolve duplicate names
names = append(names, sname)
}
for _, name := range names {
m[name] = append(m[name], &tree[i].Snapshot)
}
m.add(sname, st.ChildSnapshotList)
}
}
// findSnapshot supports snapshot lookup by name, where name can be:
// 1) snapshot ManagedObjectReference.Value (unique)
// 2) snapshot name (may not be unique)
// 3) snapshot tree path (may not be unique)
func (v VirtualMachine) findSnapshot(ctx context.Context, name string) (Reference, error) {
var o mo.VirtualMachine
err := v.Properties(ctx, v.Reference(), []string{"snapshot"}, &o)
if err != nil {
return nil, err
}
snapshotTree := o.Snapshot.RootSnapshotList
if len(snapshotTree) < 1 {
if o.Snapshot == nil || len(o.Snapshot.RootSnapshotList) == 0 {
return nil, errors.New("No snapshots for this VM")
}
snapshot, err := traverseSnapshotInTree(snapshotTree, name)
m := make(snapshotMap)
m.add("", o.Snapshot.RootSnapshotList)
s := m[name]
switch len(s) {
case 0:
return nil, fmt.Errorf("snapshot %q not found", name)
case 1:
return s[0], nil
default:
return nil, fmt.Errorf("%q resolves to %d snapshots", name, len(s))
}
}
// RemoveSnapshot removes a named snapshot
func (v VirtualMachine) RemoveSnapshot(ctx context.Context, name string, removeChildren bool, consolidate *bool) (*Task, error) {
snapshot, err := v.findSnapshot(ctx, name)
if err != nil {
return nil, err
}
req := types.RemoveSnapshot_Task{
This: snapshot.Reference(),
RemoveChildren: removeChildren,
Consolidate: consolidate,
}
res, err := methods.RemoveSnapshot_Task(ctx, v.c, &req)
if err != nil {
return nil, err
}
return NewTask(v.c, res.Returnval), nil
}
// RevertToCurrentSnapshot reverts to the current snapshot
func (v VirtualMachine) RevertToCurrentSnapshot(ctx context.Context, suppressPowerOn bool) (*Task, error) {
req := types.RevertToCurrentSnapshot_Task{
This: v.Reference(),
SuppressPowerOn: types.NewBool(suppressPowerOn),
}
res, err := methods.RevertToCurrentSnapshot_Task(ctx, v.c, &req)
if err != nil {
return nil, err
}
return NewTask(v.c, res.Returnval), nil
}
// RevertToSnapshot reverts to a named snapshot
func (v VirtualMachine) RevertToSnapshot(ctx context.Context, name string, suppressPowerOn bool) (*Task, error) {
snapshot, err := v.findSnapshot(ctx, name)
if err != nil {
return nil, err
}
req := types.RevertToSnapshot_Task{
This: snapshot,
This: snapshot.Reference(),
SuppressPowerOn: types.NewBool(suppressPowerOn),
}
@@ -499,32 +604,6 @@ func (v VirtualMachine) RevertToSnapshot(ctx context.Context, name string, suppr
return NewTask(v.c, res.Returnval), nil
}
// traverseSnapshotInTree is a recursive function that will traverse a snapshot tree to find a given snapshot
func traverseSnapshotInTree(tree []types.VirtualMachineSnapshotTree, name string) (types.ManagedObjectReference, error) {
var o types.ManagedObjectReference
if tree == nil {
return o, errors.New("Snapshot tree is empty")
}
for _, s := range tree {
if s.Name == name {
o = s.Snapshot
break
} else {
childTree := s.ChildSnapshotList
var err error
o, err = traverseSnapshotInTree(childTree, name)
if err != nil {
return o, err
}
}
}
if o.Value == "" {
return o, errors.New("Snapshot not found")
}
return o, nil
}
// IsToolsRunning returns true if VMware Tools is currently running in the guest OS, and false otherwise.
func (v VirtualMachine) IsToolsRunning(ctx context.Context) (bool, error) {
var o mo.VirtualMachine
@@ -591,3 +670,58 @@ func (v VirtualMachine) MarkAsVirtualMachine(ctx context.Context, pool ResourceP
return nil
}
func (v VirtualMachine) Migrate(ctx context.Context, pool *ResourcePool, host *HostSystem, priority types.VirtualMachineMovePriority, state types.VirtualMachinePowerState) (*Task, error) {
req := types.MigrateVM_Task{
This: v.Reference(),
Priority: priority,
State: state,
}
if pool != nil {
ref := pool.Reference()
req.Pool = &ref
}
if host != nil {
ref := host.Reference()
req.Host = &ref
}
res, err := methods.MigrateVM_Task(ctx, v.c, &req)
if err != nil {
return nil, err
}
return NewTask(v.c, res.Returnval), nil
}
func (v VirtualMachine) Unregister(ctx context.Context) error {
req := types.UnregisterVM{
This: v.Reference(),
}
_, err := methods.UnregisterVM(ctx, v.Client(), &req)
return err
}
// QueryEnvironmentBrowser is a helper to get the environmentBrowser property.
func (v VirtualMachine) QueryConfigTarget(ctx context.Context) (*types.ConfigTarget, error) {
var vm mo.VirtualMachine
err := v.Properties(ctx, v.Reference(), []string{"environmentBrowser"}, &vm)
if err != nil {
return nil, err
}
req := types.QueryConfigTarget{
This: vm.EnvironmentBrowser,
}
res, err := methods.QueryConfigTarget(ctx, v.Client(), &req)
if err != nil {
return nil, err
}
return res.Returnval, nil
}