func expandCustomizationIPSettingsIPV6AddressSpec(d *schema.ResourceData, n int, gwAdd bool) (*types.CustomizationIPSettingsIpV6AddressSpec, bool) {
	v, ok := d.GetOk(netifKey("ipv6_address", n))
	var gwFound bool
	if !ok {
		return nil, gwFound
	}
	addr := v.(string)
	mask := d.Get(netifKey("ipv6_netmask", n)).(int)
	gw, gwOk := d.Get(cKeyPrefix + "." + "ipv6_gateway").(string)
	obj := &types.CustomizationIPSettingsIpV6AddressSpec{
		Ip: []types.BaseCustomizationIpV6Generator{
			&types.CustomizationFixedIpV6{
				IpAddress:  addr,
				SubnetMask: int32(mask),
			},
		},
	}
	if gwAdd && gwOk && matchGateway(addr, mask, gw) {
		obj.Gateway = []string{gw}
		gwFound = true
	}
	return obj, gwFound
}

// expandCustomizationIPSettingsIPV6AddressSpec reads certain ResourceData keys and
// returns a CustomizationIPSettingsIpV6AddressSpec.


func expandCustomizationIPSettings(d *schema.ResourceData, n int, v4gwAdd, v6gwAdd bool) (types.CustomizationIPSettings, bool, bool) {
	var v4gwFound, v6gwFound bool
	v4addr, v4addrOk := d.GetOk(netifKey("ipv4_address", n))
	v4mask := d.Get(netifKey("ipv4_netmask", n)).(int)
	v4gw, v4gwOk := d.Get(cKeyPrefix + "." + "ipv4_gateway").(string)
	var obj types.CustomizationIPSettings
	switch {
	case v4addrOk:
		obj.Ip = &types.CustomizationFixedIp{
			IpAddress: v4addr.(string),
		}
		obj.SubnetMask = v4CIDRMaskToDotted(v4mask)
		// Check for the gateway
		if v4gwAdd && v4gwOk && matchGateway(v4addr.(string), v4mask, v4gw) {
			obj.Gateway = []string{v4gw}
			v4gwFound = true
		}
	default:
		obj.Ip = &types.CustomizationDhcpIpGenerator{}
	}
	obj.DnsServerList = structure.SliceInterfacesToStrings(d.Get(netifKey("dns_server_list", n)).([]interface{}))
	obj.DnsDomain = d.Get(netifKey("dns_domain", n)).(string)
	obj.IpV6Spec, v6gwFound = expandCustomizationIPSettingsIPV6AddressSpec(d, n, v6gwAdd)
	return obj, v4gwFound, v6gwFound
}

// expandCustomizationIPSettings reads certain ResourceData keys and
// returns a CustomizationIPSettings.

expandCustomizationIPSettings reads certain ResourceData keys and returns a CustomizationIPSettings .


func expandSliceOfCustomizationAdapterMapping(d *schema.ResourceData) []types.CustomizationAdapterMapping {
	s := d.Get(cKeyPrefix + "." + "network_interface").([]interface{})
	if len(s) < 1 {
		return nil
	}
	result := make([]types.CustomizationAdapterMapping, len(s))
	var v4gwFound, v6gwFound bool
	for i := range s {
		var adapter types.CustomizationIPSettings
		adapter, v4gwFound, v6gwFound = expandCustomizationIPSettings(d, i, !v4gwFound, !v6gwFound)
		obj := types.CustomizationAdapterMapping{
			Adapter: adapter,
		}
		result[i] = obj
	}
	return result
}

// expandSliceOfCustomizationAdapterMapping reads certain ResourceData keys and
// returns a CustomizationAdapterMapping slice.


func ExpandCustomizationSpec(d *schema.ResourceData, family string) types.CustomizationSpec {
	obj := types.CustomizationSpec{
		Identity:         expandBaseCustomizationIdentitySettings(d, family),
		GlobalIPSettings: expandCustomizationGlobalIPSettings(d),
		NicSettingMap:    expandSliceOfCustomizationAdapterMapping(d),
	}
	return obj
}

// ExpandCustomizationSpec reads certain ResourceData keys and
// returns a CustomizationSpec.

ExpandCustomizationSpec reads certain ResourceData keys and returns a CustomizationSpec .


func ValidateCustomizationSpec(d *schema.ResourceDiff, family string) error {
	// Validate that the proper section exists for OS family suboptions.
	linuxExists := len(d.Get(cKeyPrefix+"."+"linux_options").([]interface{})) > 0
	windowsExists := len(d.Get(cKeyPrefix+"."+"windows_options").([]interface{})) > 0
	sysprepExists := d.Get(cKeyPrefix+"."+"windows_sysprep_text").(string) != ""
	switch {
	case family == string(types.VirtualMachineGuestOsFamilyLinuxGuest) && !linuxExists:
		return errors.New("linux_options must exist in VM customization options for Linux operating systems")
	case family == string(types.VirtualMachineGuestOsFamilyWindowsGuest) && !windowsExists && !sysprepExists:
		return errors.New("one of windows_options or windows_sysprep_text must exist in VM customization options for Windows operating systems")
	}
	return nil
}

// ValidateCustomizationSpec checks the validity of the supplied customization
// spec. It should be called during diff customization to veto invalid configs.

ValidateCustomizationSpec checks the validity of the supplied customization spec . It should be called during diff customization to veto invalid configs .


func schemaHostVirtualSwitchBondBridge() map[string]*schema.Schema {
	return map[string]*schema.Schema{
		// HostVirtualSwitchBeaconConfig
		"beacon_interval": {
			Type:         schema.TypeInt,
			Optional:     true,
			Description:  "Determines how often, in seconds, a beacon should be sent to probe for the validity of a link.",
			Default:      1,
			ValidateFunc: validation.IntAtLeast(0),
		},

		// LinkDiscoveryProtocolConfig
		"link_discovery_operation": {
			Type:         schema.TypeString,
			Optional:     true,
			Description:  "Whether to advertise or listen for link discovery. Valid values are advertise, both, listen, and none.",
			Default:      string(types.LinkDiscoveryProtocolConfigOperationTypeListen),
			ValidateFunc: validation.StringInSlice(linkDiscoveryProtocolConfigOperationAllowedValues, false),
		},
		"link_discovery_protocol": {
			Type:         schema.TypeString,
			Optional:     true,
			Description:  "The discovery protocol type. Valid values are cdp and lldp.",
			Default:      string(types.LinkDiscoveryProtocolConfigProtocolTypeCdp),
			ValidateFunc: validation.StringInSlice(linkDiscoveryProtocolConfigProtocolAllowedValues, false),
		},

		// HostVirtualSwitchBondBridge
		"network_adapters": {
			Type:        schema.TypeList,
			Required:    true,
			Description: "The list of network adapters to bind to this virtual switch.",
			Elem:        &schema.Schema{Type: schema.TypeString},
		},
	}
}

// schemaHostVirtualSwitchBondBridge returns schema items for resources that
// need to work with a HostVirtualSwitchBondBridge, such as virtual switches.

schemaHostVirtualSwitchBondBridge returns schema items for resources that need to work with a HostVirtualSwitchBondBridge such as virtual switches .


func expandHostVirtualSwitchBeaconConfig(d *schema.ResourceData) *types.HostVirtualSwitchBeaconConfig {
	obj := &types.HostVirtualSwitchBeaconConfig{
		Interval: int32(d.Get("beacon_interval").(int)),
	}
	return obj
}

func expandHostVirtualSwitchBeaconConfig ( d * schema . ResourceData ) * types . HostVirtualSwitchBeaconConfig { obj := & types . HostVirtualSwitchBeaconConfig { Interval : int32 ( d . Get ( " " ) . ( int ) ) , } return obj }

// expandHostVirtualSwitchBeaconConfig reads certain ResourceData keys and
// returns a HostVirtualSwitchBeaconConfig.

expandHostVirtualSwitchBeaconConfig reads certain ResourceData keys and returns a HostVirtualSwitchBeaconConfig .


func flattenHostVirtualSwitchBeaconConfig(d *schema.ResourceData, obj *types.HostVirtualSwitchBeaconConfig) error {
	d.Set("beacon_interval", obj.Interval)
	return nil
}

func flattenHostVirtualSwitchBeaconConfig ( d * schema . ResourceData , obj * types . HostVirtualSwitchBeaconConfig ) error { d . Set ( " " , obj . Interval ) return nil }

// flattenHostVirtualSwitchBeaconConfig reads various fields from a
// HostVirtualSwitchBeaconConfig into the passed in ResourceData.

flattenHostVirtualSwitchBeaconConfig reads various fields from a HostVirtualSwitchBeaconConfig into the passed in ResourceData .


func expandLinkDiscoveryProtocolConfig(d *schema.ResourceData) *types.LinkDiscoveryProtocolConfig {
	obj := &types.LinkDiscoveryProtocolConfig{
		Operation: d.Get("link_discovery_operation").(string),
		Protocol:  d.Get("link_discovery_protocol").(string),
	}
	return obj
}

func expandLinkDiscoveryProtocolConfig ( d * schema . ResourceData ) * types . LinkDiscoveryProtocolConfig { obj := & types . LinkDiscoveryProtocolConfig { Operation : d . Get ( " " ) . ( string ) , Protocol : d . Get ( " " ) . ( string ) , } return obj }

// expandLinkDiscoveryProtocolConfig reads certain ResourceData keys and
// returns a LinkDiscoveryProtocolConfig.

expandLinkDiscoveryProtocolConfig reads certain ResourceData keys and returns a LinkDiscoveryProtocolConfig .


func flattenLinkDiscoveryProtocolConfig(d *schema.ResourceData, obj *types.LinkDiscoveryProtocolConfig) error {
	d.Set("link_discovery_operation", obj.Operation)
	d.Set("link_discovery_protocol", obj.Protocol)
	return nil
}

func flattenLinkDiscoveryProtocolConfig ( d * schema . ResourceData , obj * types . LinkDiscoveryProtocolConfig ) error { d . Set ( " " , obj . Operation ) d . Set ( " " , obj . Protocol ) return nil }

// flattenLinkDiscoveryProtocolConfig reads various fields from a
// LinkDiscoveryProtocolConfig into the passed in ResourceData.

flattenLinkDiscoveryProtocolConfig reads various fields from a LinkDiscoveryProtocolConfig into the passed in ResourceData .


func expandHostVirtualSwitchBondBridge(d *schema.ResourceData) *types.HostVirtualSwitchBondBridge {
	obj := &types.HostVirtualSwitchBondBridge{
		NicDevice: structure.SliceInterfacesToStrings(d.Get("network_adapters").([]interface{})),
	}
	obj.Beacon = expandHostVirtualSwitchBeaconConfig(d)
	obj.LinkDiscoveryProtocolConfig = expandLinkDiscoveryProtocolConfig(d)
	return obj
}

func expandHostVirtualSwitchBondBridge ( d * schema . ResourceData ) * types . HostVirtualSwitchBondBridge { obj := & types . HostVirtualSwitchBondBridge { NicDevice : structure . SliceInterfacesToStrings ( d . Get ( " " ) . ( [ ] interface { } ) ) , } obj . Beacon = expandHostVirtualSwitchBeaconConfig ( d ) obj . LinkDiscoveryProtocolConfig = expandLinkDiscoveryProtocolConfig ( d ) return obj }

// expandHostVirtualSwitchBondBridge reads certain ResourceData keys and
// returns a HostVirtualSwitchBondBridge.

expandHostVirtualSwitchBondBridge reads certain ResourceData keys and returns a HostVirtualSwitchBondBridge .


func flattenHostVirtualSwitchBondBridge(d *schema.ResourceData, obj *types.HostVirtualSwitchBondBridge) error {
	if err := d.Set("network_adapters", structure.SliceStringsToInterfaces(obj.NicDevice)); err != nil {
		return err
	}
	if err := flattenHostVirtualSwitchBeaconConfig(d, obj.Beacon); err != nil {
		return err
	}
	if err := flattenLinkDiscoveryProtocolConfig(d, obj.LinkDiscoveryProtocolConfig); err != nil {
		return err
	}
	return nil
}

func flattenHostVirtualSwitchBondBridge ( d * schema . ResourceData , obj * types . HostVirtualSwitchBondBridge ) error { if err := d . Set ( " " , structure . SliceStringsToInterfaces ( obj . NicDevice ) ) ; err != nil { return err } if err := flattenHostVirtualSwitchBeaconConfig ( d , obj . Beacon ) ; err != nil { return err } if err := flattenLinkDiscoveryProtocolConfig ( d , obj . LinkDiscoveryProtocolConfig ) ; err != nil { return err } return nil }

// flattenHostVirtualSwitchBondBridge reads various fields from a
// HostVirtualSwitchBondBridge into the passed in ResourceData.

flattenHostVirtualSwitchBondBridge reads various fields from a HostVirtualSwitchBondBridge into the passed in ResourceData .


func schemaHostVirtualSwitchSpec() map[string]*schema.Schema {
	s := map[string]*schema.Schema{
		// HostVirtualSwitchSpec
		"mtu": {
			Type:         schema.TypeInt,
			Optional:     true,
			Description:  "The maximum transmission unit (MTU) of the virtual switch in bytes.",
			Default:      1500,
			ValidateFunc: validation.IntBetween(1, 9000),
		},
		"number_of_ports": {
			Type:         schema.TypeInt,
			Optional:     true,
			Description:  "The number of ports that this virtual switch is configured to use.",
			Default:      128,
			ValidateFunc: validation.IntBetween(0, 1024),
		},
	}
	structure.MergeSchema(s, schemaHostVirtualSwitchBondBridge())
	structure.MergeSchema(s, schemaHostNetworkPolicy())
	return s
}

func
schemaHostVirtualSwitchSpec
(
)
map
[
string
]
*
schema
.
Schema
{
s
:=
map
[
string
]
*
schema
.
Schema
{
// HostVirtualSwitchSpec
"
"
:
{
Type
:
schema
.
TypeInt
,
Optional
:
true
,
Description
:
"
"
,
Default
:
1500
,
ValidateFunc
:
validation
.
IntBetween
(
1
,
9000
)
,
}
,
"
"
:
{
Type
:
schema
.
TypeInt
,
Optional
:
true
,
Description
:
"
"
,
Default
:
128
,
ValidateFunc
:
validation
.
IntBetween
(
0
,
1024
)
,
}
,
}
structure
.
MergeSchema
(
s
,
schemaHostVirtualSwitchBondBridge
(
)
)
structure
.
MergeSchema
(
s
,
schemaHostNetworkPolicy
(
)
)
return
s
}

// schemaHostVirtualSwitchSpec returns schema items for resources that need to
// work with a HostVirtualSwitchSpec, such as virtual switches.

schemaHostVirtualSwitchSpec returns schema items for resources that need to work with a HostVirtualSwitchSpec such as virtual switches .


func expandHostVirtualSwitchSpec(d *schema.ResourceData) *types.HostVirtualSwitchSpec {
	obj := &types.HostVirtualSwitchSpec{
		Mtu:      int32(d.Get("mtu").(int)),
		NumPorts: int32(d.Get("number_of_ports").(int)),
		Bridge:   expandHostVirtualSwitchBondBridge(d),
		Policy:   expandHostNetworkPolicy(d),
	}
	// If there are no NICs, we need to nil-out Bridge, as a
	// HostVirtualSwitchBondBridge with no NICs is an invalid config.
	if len(obj.Bridge.(*types.HostVirtualSwitchBondBridge).NicDevice) < 1 {
		obj.Bridge = nil
	}
	return obj
}

// expandHostVirtualSwitchSpec reads certain ResourceData keys and returns a
// HostVirtualSwitchSpec.

expandHostVirtualSwitchSpec reads certain ResourceData keys and returns a HostVirtualSwitchSpec .


func flattenHostVirtualSwitchSpec(d *schema.ResourceData, obj *types.HostVirtualSwitchSpec) error {
	d.Set("mtu", obj.Mtu)
	d.Set("number_of_ports", obj.NumPorts)
	if obj.Bridge != nil {
		if err := flattenHostVirtualSwitchBondBridge(d, obj.Bridge.(*types.HostVirtualSwitchBondBridge)); err != nil {
			return err
		}
	}
	if err := flattenHostNetworkPolicy(d, obj.Policy); err != nil {
		return err
	}
	return nil
}

func flattenHostVirtualSwitchSpec ( d * schema . ResourceData , obj * types . HostVirtualSwitchSpec ) error { d . Set ( " " , obj . Mtu ) d . Set ( " " , obj . NumPorts ) if obj . Bridge != nil { if err := flattenHostVirtualSwitchBondBridge ( d , obj . Bridge . ( * types . HostVirtualSwitchBondBridge ) ) ; err != nil { return err } } if err := flattenHostNetworkPolicy ( d , obj . Policy ) ; err != nil { return err } return nil }

// flattenHostVirtualSwitchSpec reads various fields from a
// HostVirtualSwitchSpec into the passed in ResourceData.

flattenHostVirtualSwitchSpec reads various fields from a HostVirtualSwitchSpec into the passed in ResourceData .


func saveHostVirtualSwitchID(d *schema.ResourceData, hsID, name string) {
	d.SetId(fmt.Sprintf("%s:%s:%s", hostVirtualSwitchIDPrefix, hsID, name))
}

func saveHostVirtualSwitchID ( d * schema . ResourceData , hsID , name string ) { d . SetId ( fmt . Sprintf ( " " , hostVirtualSwitchIDPrefix , hsID , name ) ) }

// saveHostVirtualSwitchID sets a special ID for a host virtual switch,
// composed of the MOID for the concerned HostSystem and the virtual switch's
// key.

saveHostVirtualSwitchID sets a special ID for a host virtual switch composed of the MOID for the concerned HostSystem and the virtual switch s key .


func virtualSwitchIDsFromResourceID(d *schema.ResourceData) (string, string, error) {
	return splitHostVirtualSwitchID(d.Id())
}

func virtualSwitchIDsFromResourceID ( d * schema . ResourceData ) ( string , string , error ) { return splitHostVirtualSwitchID ( d . Id ( ) ) }

// virtualSwitchIDsFromResourceID passes a resource's ID through
// splitHostVirtualSwitchID.

virtualSwitchIDsFromResourceID passes a resource s ID through splitHostVirtualSwitchID .


func expandStorageDrsVMConfigInfo(d *schema.ResourceData, vm *object.VirtualMachine) (*types.StorageDrsVmConfigInfo, error) {
	enabled, err := structure.GetBoolStringPtr(d, "sdrs_enabled")
	if err != nil {
		return nil, fmt.Errorf("error parsing field \"sdrs_enabled\": %s", err)
	}
	intraVMAffinity, err := structure.GetBoolStringPtr(d, "sdrs_intra_vm_affinity")
	if err != nil {
		return nil, fmt.Errorf("error parsing field \"sdrs_intra_vm_affinity\": %s", err)
	}

	obj := &types.StorageDrsVmConfigInfo{
		Behavior:        d.Get("sdrs_automation_level").(string),
		Enabled:         enabled,
		IntraVmAffinity: intraVMAffinity,
		Vm:              types.NewReference(vm.Reference()),
	}

	return obj, nil
}

func expandStorageDrsVMConfigInfo ( d * schema . ResourceData , vm * object . VirtualMachine ) ( * types . StorageDrsVmConfigInfo , error ) { enabled , err := structure . GetBoolStringPtr ( d , " " ) if err != nil { return nil , fmt . Errorf ( " \" \" " , err ) } intraVMAffinity , err := structure . GetBoolStringPtr ( d , " " ) if err != nil { return nil , fmt . Errorf ( " \" \" " , err ) } obj := & types . StorageDrsVmConfigInfo { Behavior : d . Get ( " " ) . ( string ) , Enabled : enabled , IntraVmAffinity : intraVMAffinity , Vm : types . NewReference ( vm . Reference ( ) ) , } return obj , nil }

// expandStorageDrsVMConfigInfo reads certain ResourceData keys and returns a
// StorageDrsVmConfigInfo.

expandStorageDrsVMConfigInfo reads certain ResourceData keys and returns a StorageDrsVmConfigInfo .


func flattenStorageDrsVMConfigInfo(d *schema.ResourceData, obj *types.StorageDrsVmConfigInfo) error {
	if err := d.Set("sdrs_automation_level", obj.Behavior); err != nil {
		return fmt.Errorf("error setting attribute \"sdrs_automation_level\": %s", err)
	}
	if err := structure.SetBoolStringPtr(d, "sdrs_enabled", obj.Enabled); err != nil {
		return fmt.Errorf("error setting attribute \"sdrs_enabled\": %s", err)
	}
	if err := structure.SetBoolStringPtr(d, "sdrs_intra_vm_affinity", obj.IntraVmAffinity); err != nil {
		return fmt.Errorf("error setting attribute \"sdrs_automation_level\": %s", err)
	}

	return nil
}

func flattenStorageDrsVMConfigInfo ( d * schema . ResourceData , obj * types . StorageDrsVmConfigInfo ) error { if err := d . Set ( " " , obj . Behavior ) ; err != nil { return fmt . Errorf ( " \" \" " , err ) } if err := structure . SetBoolStringPtr ( d , " " , obj . Enabled ) ; err != nil { return fmt . Errorf ( " \" \" " , err ) } if err := structure . SetBoolStringPtr ( d , " " , obj . IntraVmAffinity ) ; err != nil { return fmt . Errorf ( " \" \" " , err ) } return nil }

// flattenStorageDrsVmConfigInfo saves a StorageDrsVmConfigInfo into the
// supplied ResourceData.

flattenStorageDrsVmConfigInfo saves a StorageDrsVmConfigInfo into the supplied ResourceData .


func resourceVSphereStorageDrsVMOverrideFlattenID(pod *object.StoragePod, vm *object.VirtualMachine) (string, error) {
	podID := pod.Reference().Value
	props, err := virtualmachine.Properties(vm)
	if err != nil {
		return "", fmt.Errorf("cannot compute ID off of properties of virtual machine: %s", err)
	}
	vmID := props.Config.Uuid
	return strings.Join([]string{podID, vmID}, ":"), nil
}

// resourceVSphereStorageDrsVMOverrideFlattenID makes an ID for the
// vsphere_storage_drs_vm_override resource.


func resourceVSphereStorageDrsVMOverrideFindEntry(
	pod *object.StoragePod,
	vm *object.VirtualMachine,
) (*types.StorageDrsVmConfigInfo, error) {
	props, err := storagepod.Properties(pod)
	if err != nil {
		return nil, fmt.Errorf("error fetching datastore cluster properties: %s", err)
	}

	for _, info := range props.PodStorageDrsEntry.StorageDrsConfig.VmConfig {
		if *info.Vm == vm.Reference() {
			log.Printf("[DEBUG] Found storage DRS config info for VM %q in datastore cluster %q", vm.Name(), pod.Name())
			return &info, nil
		}
	}

	log.Printf("[DEBUG] No storage DRS config info found for VM %q in datastore cluster %q", vm.Name(), pod.Name())
	return nil, nil
}

// resourceVSphereStorageDrsVMOverrideFindEntry attempts to locate an existing VM
// config in a Storage Pod's DRS configuration. It's used by the resource's
// read functionality and tests. nil is returned if the entry cannot be found.


func NetworkInterfaceSubresourceSchema() map[string]*schema.Schema {
	s := map[string]*schema.Schema{
		// VirtualEthernetCardResourceAllocation
		"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),
		},

		// VirtualEthernetCard and friends
		"network_id": {
			Type:         schema.TypeString,
			Required:     true,
			Description:  "The ID of the network to connect this network interface to.",
			ValidateFunc: validation.NoZeroValues,
		},
		"adapter_type": {
			Type:         schema.TypeString,
			Optional:     true,
			Default:      networkInterfaceSubresourceTypeVmxnet3,
			Description:  "The controller type. Can be one of e1000, e1000e, or vmxnet3.",
			ValidateFunc: validation.StringInSlice(networkInterfaceSubresourceTypeAllowedValues, false),
		},
		"use_static_mac": {
			Type:        schema.TypeBool,
			Optional:    true,
			Description: "If true, the mac_address field is treated as a static MAC address and set accordingly.",
		},
		"mac_address": {
			Type:        schema.TypeString,
			Optional:    true,
			Computed:    true,
			Description: "The MAC address of this network interface. Can only be manually set if use_static_mac is true.",
		},
	}
	structure.MergeSchema(s, subresourceSchema())
	return s
}

// NetworkInterfaceSubresourceSchema returns the schema for the disk
// sub-resource.

NetworkInterfaceSubresourceSchema returns the schema for the disk sub - resource .


func NewNetworkInterfaceSubresource(client *govmomi.Client, rdd resourceDataDiff, d, old map[string]interface{}, idx int) *NetworkInterfaceSubresource {
	sr := &NetworkInterfaceSubresource{
		Subresource: &Subresource{
			schema:  NetworkInterfaceSubresourceSchema(),
			client:  client,
			srtype:  subresourceTypeNetworkInterface,
			data:    d,
			olddata: old,
			rdd:     rdd,
		},
	}
	sr.Index = idx
	return sr
}

func NewNetworkInterfaceSubresource ( client * govmomi . Client , rdd resourceDataDiff , d , old map [ string ] interface { } , idx int ) * NetworkInterfaceSubresource { sr := & NetworkInterfaceSubresource { Subresource : & Subresource { schema : NetworkInterfaceSubresourceSchema ( ) , client : client , srtype : subresourceTypeNetworkInterface , data : d , olddata : old , rdd : rdd , } , } sr . Index = idx return sr }

// NewNetworkInterfaceSubresource returns a network_interface subresource
// populated with all of the necessary fields.

NewNetworkInterfaceSubresource returns a network_interface subresource populated with all of the necessary fields .


func NetworkInterfaceDiffOperation(d *schema.ResourceDiff, c *govmomi.Client) error {
	// We just need the new values for now, as all we are doing is validating some values based on API version
	n := d.Get(subresourceTypeNetworkInterface)
	log.Printf("[DEBUG] NetworkInterfaceDiffOperation: Beginning diff validation")
	for ni, ne := range n.([]interface{}) {
		nm := ne.(map[string]interface{})
		r := NewNetworkInterfaceSubresource(c, d, nm, nil, ni)
		if err := r.ValidateDiff(); err != nil {
			return fmt.Errorf("%s: %s", r.Addr(), err)
		}
	}
	log.Printf("[DEBUG] NetworkInterfaceDiffOperation: Diff validation complete")
	return nil
}

// NetworkInterfaceDiffOperation performs operations relevant to managing the
// diff on network_interface sub-resources.

NetworkInterfaceDiffOperation performs operations relevant to managing the diff on network_interface sub - resources .


func ReadNetworkInterfaceTypes(l object.VirtualDeviceList) ([]string, error) {
	log.Printf("[DEBUG] ReadNetworkInterfaceTypes: Fetching interface types")
	devices := l.Select(func(device types.BaseVirtualDevice) bool {
		if _, ok := device.(types.BaseVirtualEthernetCard); ok {
			return true
		}
		return false
	})
	log.Printf("[DEBUG] ReadNetworkInterfaceTypes: 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 []string
	for _, device := range devices {
		out = append(out, virtualEthernetCardString(device.(types.BaseVirtualEthernetCard)))
	}
	log.Printf("[DEBUG] ReadNetworkInterfaceTypes: Network types returned: %+v", out)
	return out, nil
}

// ReadNetworkInterfaceTypes returns a list of network interface types. This is used
// in the VM data source to discover the types of the NIC drivers on the
// virtual machine. The list is sorted by the order that they would be added in
// if a clone were to be done.

ReadNetworkInterfaceTypes returns a list of network interface types . This is used in the VM data source to discover the types of the NIC drivers 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 baseVirtualEthernetCardToBaseVirtualDevice(v types.BaseVirtualEthernetCard) types.BaseVirtualDevice {
	switch t := v.(type) {
	case *types.VirtualE1000:
		return types.BaseVirtualDevice(t)
	case *types.VirtualE1000e:
		return types.BaseVirtualDevice(t)
	case *types.VirtualPCNet32:
		return types.BaseVirtualDevice(t)
	case *types.VirtualSriovEthernetCard:
		return types.BaseVirtualDevice(t)
	case *types.VirtualVmxnet2:
		return types.BaseVirtualDevice(t)
	case *types.VirtualVmxnet3:
		return types.BaseVirtualDevice(t)
	}
	panic(fmt.Errorf("unknown ethernet card type %T", v))
}

// baseVirtualEthernetCardToBaseVirtualDevice converts a
// BaseVirtualEthernetCard value into a BaseVirtualDevice.


func baseVirtualDeviceToBaseVirtualEthernetCard(v types.BaseVirtualDevice) (types.BaseVirtualEthernetCard, error) {
	if bve, ok := v.(types.BaseVirtualEthernetCard); ok {
		return bve, nil
	}
	return nil, fmt.Errorf("device is not a network device (%T)", v)
}

// baseVirtualDeviceToBaseVirtualEthernetCard converts a BaseVirtualDevice
// value into a BaseVirtualEthernetCard.


func virtualEthernetCardString(d types.BaseVirtualEthernetCard) string {
	switch d.(type) {
	case *types.VirtualE1000:
		return networkInterfaceSubresourceTypeE1000
	case *types.VirtualE1000e:
		return networkInterfaceSubresourceTypeE1000e
	case *types.VirtualPCNet32:
		return networkInterfaceSubresourceTypePCNet32
	case *types.VirtualSriovEthernetCard:
		return networkInterfaceSubresourceTypeSriov
	case *types.VirtualVmxnet2:
		return networkInterfaceSubresourceTypeVmxnet2
	case *types.VirtualVmxnet3:
		return networkInterfaceSubresourceTypeVmxnet3
	}
	return networkInterfaceSubresourceTypeUnknown
}

func virtualEthernetCardString ( d types . BaseVirtualEthernetCard ) string { switch d . ( type ) { case * types . VirtualE1000 : return networkInterfaceSubresourceTypeE1000 case * types . VirtualE1000e : return networkInterfaceSubresourceTypeE1000e case * types . VirtualPCNet32 : return networkInterfaceSubresourceTypePCNet32 case * types . VirtualSriovEthernetCard : return networkInterfaceSubresourceTypeSriov case * types . VirtualVmxnet2 : return networkInterfaceSubresourceTypeVmxnet2 case * types . VirtualVmxnet3 : return networkInterfaceSubresourceTypeVmxnet3 } return networkInterfaceSubresourceTypeUnknown }

// virtualEthernetCardString prints a string representation of the ethernet device passed in.

virtualEthernetCardString prints a string representation of the ethernet device passed in .


func (r *NetworkInterfaceSubresource) Create(l object.VirtualDeviceList) ([]types.BaseVirtualDeviceConfigSpec, error) {
	log.Printf("[DEBUG] %s: Running create", r)
	var spec []types.BaseVirtualDeviceConfigSpec
	ctlr, err := r.ControllerForCreateUpdate(l, SubresourceControllerTypePCI, 0)
	if err != nil {
		return nil, err
	}

	// govmomi has helpers that allow the easy fetching of a network's backing
	// info, once we actually know what that backing is. Set all of that stuff up
	// now.
	net, err := network.FromID(r.client, r.Get("network_id").(string))
	if err != nil {
		return nil, err
	}
	bctx, bcancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
	defer bcancel()
	backing, err := net.EthernetCardBackingInfo(bctx)
	if err != nil {
		return nil, err
	}
	device, err := l.CreateEthernetCard(r.Get("adapter_type").(string), backing)
	if err != nil {
		return nil, err
	}

	// CreateEthernetCard does not attach stuff, however, assuming that you will
	// let vSphere take care of the attachment and what not, as there is usually
	// only one PCI device per virtual machine and their tools don't really care
	// about state. Terraform does though, so we need to not only set but also
	// track that stuff.
	if err := r.assignEthernetCard(l, device, ctlr); err != nil {
		return nil, err
	}
	// Ensure the device starts connected
	l.Connect(device)

	// Set base-level card bits now
	card := device.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard()
	card.Key = l.NewKey()

	// Set the rest of the settings here.
	if r.Get("use_static_mac").(bool) {
		card.AddressType = string(types.VirtualEthernetCardMacTypeManual)
		card.MacAddress = r.Get("mac_address").(string)
	}
	version := viapi.ParseVersionFromClient(r.client)
	if version.Newer(viapi.VSphereVersion{Product: version.Product, Major: 6}) {
		alloc := &types.VirtualEthernetCardResourceAllocation{
			Limit:       structure.Int64Ptr(int64(r.Get("bandwidth_limit").(int))),
			Reservation: structure.Int64Ptr(int64(r.Get("bandwidth_reservation").(int))),
			Share: types.SharesInfo{
				Shares: int32(r.Get("bandwidth_share_count").(int)),
				Level:  types.SharesLevel(r.Get("bandwidth_share_level").(string)),
			},
		}
		card.ResourceAllocation = alloc
	}

	// Done here. Save ID, push the device to the new device list and return.
	if err := r.SaveDevIDs(device, ctlr); err != nil {
		return nil, err
	}
	dspec, err := object.VirtualDeviceList{device}.ConfigSpec(types.VirtualDeviceConfigSpecOperationAdd)
	if err != nil {
		return nil, err
	}
	spec = append(spec, dspec...)
	log.Printf("[DEBUG] %s: Device config operations from create: %s", r, DeviceChangeString(spec))
	log.Printf("[DEBUG] %s: Create finished", r)
	return spec, nil
}

// Create creates a vsphere_virtual_machine network_interface sub-resource.

Create creates a vsphere_virtual_machine network_interface sub - resource .


func (r *NetworkInterfaceSubresource) Read(l object.VirtualDeviceList) error {
	log.Printf("[DEBUG] %s: Reading state", r)
	vd, err := r.FindVirtualDevice(l)
	if err != nil {
		return fmt.Errorf("cannot find network device: %s", err)
	}
	device, err := baseVirtualDeviceToBaseVirtualEthernetCard(vd)
	if err != nil {
		return err
	}

	// Determine the interface type, and set the field appropriately. As a fallback,
	// we actually set adapter_type here to "unknown" if we don't support the NIC
	// type, as we can determine all of the other settings without having to
	// worry about the adapter type, and on update, the adapter type will be
	// rectified by removing the existing NIC and replacing it with a new one.
	r.Set("adapter_type", virtualEthernetCardString(device))

	// The rest of the information we need to get by reading the attributes off
	// the base card object.
	card := device.GetVirtualEthernetCard()

	// Determine the network
	var netID string
	switch backing := card.Backing.(type) {
	case *types.VirtualEthernetCardNetworkBackingInfo:
		if backing.Network == nil {
			return fmt.Errorf("could not determine network information from NIC backing")
		}
		netID = backing.Network.Value
	case *types.VirtualEthernetCardOpaqueNetworkBackingInfo:
		onet, err := nsx.OpaqueNetworkFromNetworkID(r.client, backing.OpaqueNetworkId)
		if err != nil {
			return err
		}
		netID = onet.Reference().Value
	case *types.VirtualEthernetCardDistributedVirtualPortBackingInfo:
		pg, err := dvportgroup.FromKey(r.client, backing.Port.SwitchUuid, backing.Port.PortgroupKey)
		if err != nil {
			return err
		}
		netID = pg.Reference().Value
	default:
		return fmt.Errorf("unknown network interface backing %T", card.Backing)
	}
	r.Set("network_id", netID)

	r.Set("use_static_mac", card.AddressType == string(types.VirtualEthernetCardMacTypeManual))
	r.Set("mac_address", card.MacAddress)

	version := viapi.ParseVersionFromClient(r.client)
	if version.Newer(viapi.VSphereVersion{Product: version.Product, Major: 6}) {
		if card.ResourceAllocation != nil {
			r.Set("bandwidth_limit", card.ResourceAllocation.Limit)
			r.Set("bandwidth_reservation", card.ResourceAllocation.Reservation)
			r.Set("bandwidth_share_count", card.ResourceAllocation.Share.Shares)
			r.Set("bandwidth_share_level", card.ResourceAllocation.Share.Level)
		}
	}

	// Save the device key and address data
	ctlr, err := findControllerForDevice(l, vd)
	if err != nil {
		return err
	}
	if err := r.SaveDevIDs(vd, ctlr); err != nil {
		return err
	}
	log.Printf("[DEBUG] %s: Read finished (key and device address may have changed)", r)
	return nil
}

// Read reads a vsphere_virtual_machine network_interface sub-resource.

Read reads a vsphere_virtual_machine network_interface sub - resource .


func (r *NetworkInterfaceSubresource) Delete(l object.VirtualDeviceList) ([]types.BaseVirtualDeviceConfigSpec, error) {
	log.Printf("[DEBUG] %s: Beginning delete", r)
	vd, err := r.FindVirtualDevice(l)
	if err != nil {
		return nil, fmt.Errorf("cannot find network device: %s", err)
	}
	device, err := baseVirtualDeviceToBaseVirtualEthernetCard(vd)
	if err != nil {
		return nil, err
	}
	// If VMware tools is not running, this operation requires a reboot
	if r.rdd.Get("vmware_tools_status").(string) != string(types.VirtualMachineToolsRunningStatusGuestToolsRunning) {
		r.SetRestart("<device delete>")
	}
	bvd := baseVirtualEthernetCardToBaseVirtualDevice(device)
	spec, err := object.VirtualDeviceList{bvd}.ConfigSpec(types.VirtualDeviceConfigSpecOperationRemove)
	if err != nil {
		return nil, err
	}
	log.Printf("[DEBUG] %s: Device config operations from update: %s", r, DeviceChangeString(spec))
	log.Printf("[DEBUG] %s: Delete completed", r)
	return spec, nil
}

// Delete deletes a vsphere_virtual_machine network_interface sub-resource.

Delete deletes a vsphere_virtual_machine network_interface sub - resource .


func (r *NetworkInterfaceSubresource) ValidateDiff() error {
	log.Printf("[DEBUG] %s: Beginning diff validation", r)

	// Ensure that network resource allocation options are only set on vSphere
	// 6.0 and higher.
	version := viapi.ParseVersionFromClient(r.client)
	if version.Older(viapi.VSphereVersion{Product: version.Product, Major: 6}) {
		if err := r.restrictResourceAllocationSettings(); err != nil {
			return err
		}
	}

	log.Printf("[DEBUG] %s: Diff validation complete", r)
	return nil
}

// ValidateDiff performs any complex validation of an individual
// network_interface sub-resource that can't be done in schema alone.

ValidateDiff performs any complex validation of an individual network_interface sub - resource that can t be done in schema alone .


func nicUnitRange(l object.VirtualDeviceList) (int, error) {
	// No NICs means no range
	if len(l) < 1 {
		return 0, nil
	}

	high := int32(networkInterfacePciDeviceOffset)

	for _, v := range l {
		d := v.GetVirtualDevice()
		if d.UnitNumber == nil {
			return 0, fmt.Errorf("device at key %d has no unit number", d.Key)
		}
		if *d.UnitNumber > high {
			high = *d.UnitNumber
		}
	}
	return int(high - networkInterfacePciDeviceOffset + 1), nil
}

func
nicUnitRange
(
l
object
.
VirtualDeviceList
)
(
int
,
error
)
{
// No NICs means no range
if
len
(
l
)
<
1
{
return
0
,
}
high
:=
int32
(
networkInterfacePciDeviceOffset
)
for
_
,
v
:=
range
l
{
d
:=
v
.
GetVirtualDevice
(
)
if
d
.
UnitNumber
==
{
return
0
,
fmt
.
Errorf
(
"
"
,
d
.
Key
)
}
if
*
d
.
UnitNumber
>
high
{
high
=
*
d
.
UnitNumber
}
}
return
int
(
high
networkInterfacePciDeviceOffset
+
1
)
,
}

// nicUnitRange calculates a range of units given a certain VirtualDeviceList,
// which should be network interfaces.  It's used in network interface refresh
// logic to determine how many subresources may end up in state.

nicUnitRange calculates a range of units given a certain VirtualDeviceList which should be network interfaces . It s used in network interface refresh logic to determine how many subresources may end up in state .


func hostStorageSystemFromHostSystemID(client *govmomi.Client, hsID string) (*object.HostStorageSystem, error) {
	hs, err := hostsystem.FromID(client, hsID)
	if err != nil {
		return nil, err
	}
	ctx, cancel := context.WithTimeout(context.Background(), defaultAPITimeout)
	defer cancel()
	return hs.ConfigManager().StorageSystem(ctx)
}

func hostStorageSystemFromHostSystemID ( client * govmomi . Client , hsID string ) ( * object . HostStorageSystem , error ) { hs , err := hostsystem . FromID ( client , hsID ) if err != nil { return nil , err } ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultAPITimeout ) defer cancel ( ) return hs . ConfigManager ( ) . StorageSystem ( ctx ) }

// hostStorageSystemFromHostSystemID locates a HostStorageSystem from a
// specified HostSystem managed object ID.

hostStorageSystemFromHostSystemID locates a HostStorageSystem from a specified HostSystem managed object ID .


func FromUUID(client *govmomi.Client, uuid string) (*object.VirtualMachine, error) {
	log.Printf("[DEBUG] Locating virtual machine with UUID %q", uuid)

	ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
	defer cancel()

	var result object.Reference
	var err error
	version := viapi.ParseVersionFromClient(client)
	expected := vmUUIDSearchIndexVersion
	expected.Product = version.Product
	if version.Older(expected) {
		result, err = virtualMachineFromContainerView(ctx, client, uuid)
	} else {
		result, err = virtualMachineFromSearchIndex(ctx, client, uuid)
	}

	if err != nil {
		return nil, err
	}

	// We need to filter our object through finder to ensure that the
	// InventoryPath field is populated, or else functions that depend on this
	// being present will fail.
	finder := find.NewFinder(client.Client, false)

	vm, err := finder.ObjectReference(ctx, result.Reference())
	if err != nil {
		return nil, err
	}

	// Should be safe to return here. If our reference returned here and is not a
	// VM, then we have bigger problems and to be honest we should be panicking
	// anyway.
	log.Printf("[DEBUG] VM %q found for UUID %q", vm.(*object.VirtualMachine).InventoryPath, uuid)
	return vm.(*object.VirtualMachine), nil
}

// FromUUID locates a virtualMachine by its UUID.

FromUUID locates a virtualMachine by its UUID .


func virtualMachineFromSearchIndex(ctx context.Context, client *govmomi.Client, uuid string) (object.Reference, error) {
	log.Printf("[DEBUG] Using SearchIndex to look up UUID %q", uuid)
	search := object.NewSearchIndex(client.Client)
	result, err := search.FindByUuid(ctx, nil, uuid, true, structure.BoolPtr(false))
	if err != nil {
		return nil, err
	}

	if result == nil {
		return nil, newUUIDNotFoundError(fmt.Sprintf("virtual machine with UUID %q not found", uuid))
	}

	return result, nil
}

func virtualMachineFromSearchIndex ( ctx context . Context , client * govmomi . Client , uuid string ) ( object . Reference , error ) { log . Printf ( " " , uuid ) search := object . NewSearchIndex ( client . Client ) result , err := search . FindByUuid ( ctx , nil , uuid , true , structure . BoolPtr ( false ) ) if err != nil { return nil , err } if result == nil { return nil , newUUIDNotFoundError ( fmt . Sprintf ( " " , uuid ) ) } return result , nil }

// virtualMachineFromSearchIndex gets the virtual machine reference via the
// SearchIndex MO and is the method used to fetch UUIDs on newer versions of
// vSphere.

virtualMachineFromSearchIndex gets the virtual machine reference via the SearchIndex MO and is the method used to fetch UUIDs on newer versions of vSphere .


func virtualMachineFromContainerView(ctx context.Context, client *govmomi.Client, uuid string) (object.Reference, error) {
	log.Printf("[DEBUG] Using ContainerView to look up UUID %q", uuid)
	m := view.NewManager(client.Client)

	v, err := m.CreateContainerView(ctx, client.ServiceContent.RootFolder, []string{"VirtualMachine"}, true)
	if err != nil {
		return nil, err
	}

	defer func() {
		if err = v.Destroy(ctx); err != nil {
			log.Printf("[DEBUG] virtualMachineFromContainerView: Unexpected error destroying container view: %s", err)
		}
	}()

	var vms, results []mo.VirtualMachine
	err = v.Retrieve(ctx, []string{"VirtualMachine"}, []string{"config.uuid"}, &results)
	if err != nil {
		return nil, err
	}

	for _, result := range results {
		if result.Config == nil {
			continue
		}
		if result.Config.Uuid == uuid {
			vms = append(vms, result)
		}
	}

	switch {
	case len(vms) < 1:
		return nil, newUUIDNotFoundError(fmt.Sprintf("virtual machine with UUID %q not found", uuid))
	case len(vms) > 1:
		return nil, fmt.Errorf("multiple virtual machines with UUID %q found", uuid)
	}

	return object.NewReference(client.Client, vms[0].Self), nil
}

func virtualMachineFromContainerView ( ctx context . Context , client * govmomi . Client , uuid string ) ( object . Reference , error ) { log . Printf ( " " , uuid ) m := view . NewManager ( client . Client ) v , err := m . CreateContainerView ( ctx , client . ServiceContent . RootFolder , [ ] string { " " } , true ) if err != nil { return nil , err } defer func ( ) { if err = v . Destroy ( ctx ) ; err != nil { log . Printf ( " " , err ) } } ( ) var vms , results [ ] mo . VirtualMachine err = v . Retrieve ( ctx , [ ] string { " " } , [ ] string { " " } , & results ) if err != nil { return nil , err } for _ , result := range results { if result . Config == nil { continue } if result . Config . Uuid == uuid { vms = append ( vms , result ) } } switch { case len ( vms ) < 1 : return nil , newUUIDNotFoundError ( fmt . Sprintf ( " " , uuid ) ) case len ( vms ) > 1 : return nil , fmt . Errorf ( " " , uuid ) } return object . NewReference ( client . Client , vms [ 0 ] . Self ) , nil }

// virtualMachineFromContainerView is a compatability method that is
// used when the version of vSphere is too old to support using SearchIndex's
// FindByUuid method correctly. This is mainly to facilitate the ability to use
// FromUUID to find both templates in addition to virtual machines, which
// historically was not supported by FindByUuid.

virtualMachineFromContainerView is a compatability method that is used when the version of vSphere is too old to support using SearchIndex s FindByUuid method correctly . This is mainly to facilitate the ability to use FromUUID to find both templates in addition to virtual machines which historically was not supported by FindByUuid .


func Properties(vm *object.VirtualMachine) (*mo.VirtualMachine, error) {
	log.Printf("[DEBUG] Fetching properties for VM %q", vm.InventoryPath)
	ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
	defer cancel()
	var props mo.VirtualMachine
	if err := vm.Properties(ctx, vm.Reference(), nil, &props); err != nil {
		return nil, err
	}
	return &props, nil
}

func Properties ( vm * object . VirtualMachine ) ( * mo . VirtualMachine , error ) { log . Printf ( " " , vm . InventoryPath ) ctx , cancel := context . WithTimeout ( context . Background ( ) , provider . DefaultAPITimeout ) defer cancel ( ) var props mo . VirtualMachine if err := vm . Properties ( ctx , vm . Reference ( ) , nil , & props ) ; err != nil { return nil , err } return & props , nil }

// Properties is a convenience method that wraps fetching the
// VirtualMachine MO from its higher-level object.

Properties is a convenience method that wraps fetching the VirtualMachine MO from its higher - level object .


func WaitForGuestIP(client *govmomi.Client, vm *object.VirtualMachine, timeout int, ignoredGuestIPs []interface{}) error {
	if timeout < 1 {
		log.Printf("[DEBUG] Skipping IP waiter for VM %q", vm.InventoryPath)
		return nil
	}
	log.Printf(
		"[DEBUG] Waiting for an available IP address on VM %q (timeout = %dm)",
		vm.InventoryPath,
		timeout,
	)

	p := client.PropertyCollector()
	ctx, cancel := context.WithTimeout(context.Background(), time.Minute*time.Duration(timeout))
	defer cancel()

	err := property.Wait(ctx, p, vm.Reference(), []string{"guest.ipAddress"}, func(pc []types.PropertyChange) bool {
		for _, c := range pc {
			if c.Op != types.PropertyChangeOpAssign {
				continue
			}

			if c.Val == nil {
				continue
			}

			ip := net.ParseIP(c.Val.(string))
			if skipIPAddrForWaiter(ip, ignoredGuestIPs) {
				continue
			}

			return true
		}

		return false
	})

	if err != nil {
		// Provide a friendly error message if we timed out waiting for a routable IP.
		if ctx.Err() == context.DeadlineExceeded {
			return errors.New("timeout waiting for an available IP address")
		}
		return err
	}

	log.Printf("[DEBUG] IP address is now available for VM %q", vm.InventoryPath)
	return nil
}

// WaitForGuestIP waits for a virtual machine to have an IP address.
//
// The timeout is specified in minutes. If zero or a negative value is passed,
// the waiter returns without error immediately.

WaitForGuestIP waits for a virtual machine to have an IP address . The timeout is specified in minutes . If zero or a negative value is passed the waiter returns without error immediately .


func WaitForGuestNet(client *govmomi.Client, vm *object.VirtualMachine, routable bool, timeout int, ignoredGuestIPs []interface{}) error {
	if timeout < 1 {
		log.Printf("[DEBUG] Skipping network waiter for VM %q", vm.InventoryPath)
		return nil
	}
	log.Printf(
		"[DEBUG] Waiting for an available IP address on VM %q (routable= %t, timeout = %dm)",
		vm.InventoryPath,
		routable,
		timeout,
	)
	var v4gw, v6gw net.IP

	p := client.PropertyCollector()
	ctx, cancel := context.WithTimeout(context.Background(), time.Minute*time.Duration(timeout))
	defer cancel()

	err := property.Wait(ctx, p, vm.Reference(), []string{"guest.net", "guest.ipStack"}, func(pc []types.PropertyChange) bool {
		for _, c := range pc {
			if c.Op != types.PropertyChangeOpAssign {
				continue
			}

			switch v := c.Val.(type) {
			case types.ArrayOfGuestStackInfo:
				for _, s := range v.GuestStackInfo {
					if s.IpRouteConfig != nil {
						for _, r := range s.IpRouteConfig.IpRoute {
							switch r.Network {
							case "0.0.0.0":
								v4gw = net.ParseIP(r.Gateway.IpAddress)
							case "::":
								v6gw = net.ParseIP(r.Gateway.IpAddress)
							}
						}
					}
				}
			case types.ArrayOfGuestNicInfo:
				for _, n := range v.GuestNicInfo {
					if n.IpConfig != nil {
						for _, addr := range n.IpConfig.IpAddress {
							ip := net.ParseIP(addr.IpAddress)
							if skipIPAddrForWaiter(ip, ignoredGuestIPs) {
								continue
							}
							if !routable {
								// We are done. The rest of this block concerns itself with
								// checking for a routable address, but the waiter has been
								// flagged to not wait for one.
								return true
							}
							var mask net.IPMask
							if ip.To4() != nil {
								mask = net.CIDRMask(int(addr.PrefixLength), 32)
							} else {
								mask = net.CIDRMask(int(addr.PrefixLength), 128)
							}
							if ip.Mask(mask).Equal(v4gw.Mask(mask)) || ip.Mask(mask).Equal(v6gw.Mask(mask)) {
								return true
							}
						}
					}
				}
			}
		}

		return false
	})

	if err != nil {
		// Provide a friendly error message if we timed out waiting for a routable IP.
		if ctx.Err() == context.DeadlineExceeded {
			return errors.New("timeout waiting for an available IP address")
		}
		return err
	}

	log.Printf("[DEBUG] IP address(es) is/are now available for VM %q", vm.InventoryPath)
	return nil
}

// WaitForGuestNet waits for a virtual machine to have routable network
// access. This is denoted as a gateway, and at least one IP address that can
// reach that gateway. This function supports both IPv4 and IPv6, and returns
// the moment either stack is routable - it doesn't wait for both.
//
// The timeout is specified in minutes. If zero or a negative value is passed,
// the waiter returns without error immediately.

WaitForGuestNet waits for a virtual machine to have routable network access . This is denoted as a gateway and at least one IP address that can reach that gateway . This function supports both IPv4 and IPv6 and returns the moment either stack is routable - it doesn t wait for both . The timeout is specified in minutes . If zero or a negative value is passed the waiter returns without error immediately .


func Create(c *govmomi.Client, f *object.Folder, s types.VirtualMachineConfigSpec, p *object.ResourcePool, h *object.HostSystem) (*object.VirtualMachine, error) {
	log.Printf("[DEBUG] Creating virtual machine %q", fmt.Sprintf("%s/%s", f.InventoryPath, s.Name))
	ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
	defer cancel()
	var task *object.Task
	// Check to see if the resource pool is a vApp
	vc, err := vappcontainer.FromID(c, p.Reference().Value)
	if err != nil {
		if !viapi.IsManagedObjectNotFoundError(err) {
			return nil, err
		}
		task, err = f.CreateVM(ctx, s, p, h)
	} else {
		task, err = vc.CreateChildVM(ctx, s, h)
	}
	if err != nil {
		return nil, err
	}
	tctx, tcancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
	defer tcancel()
	result, err := task.WaitForResult(tctx, nil)
	if err != nil {
		return nil, err
	}
	log.Printf("[DEBUG] Virtual machine %q: creation complete (MOID: %q)", fmt.Sprintf("%s/%s", f.InventoryPath, s.Name), result.Result.(types.ManagedObjectReference).Value)
	return FromMOID(c, result.Result.(types.ManagedObjectReference).Value)
}

// Create wraps the creation of a virtual machine and the subsequent waiting of
// the task. A higher-level virtual machine object is returned.

Create wraps the creation of a virtual machine and the subsequent waiting of the task . A higher - level virtual machine object is returned .


func Clone(c *govmomi.Client, src *object.VirtualMachine, f *object.Folder, name string, spec types.VirtualMachineCloneSpec, timeout int) (*object.VirtualMachine, error) {
	log.Printf("[DEBUG] Cloning virtual machine %q", fmt.Sprintf("%s/%s", f.InventoryPath, name))
	ctx, cancel := context.WithTimeout(context.Background(), time.Minute*time.Duration(timeout))
	defer cancel()
	task, err := src.Clone(ctx, f, name, spec)
	if err != nil {
		if ctx.Err() == context.DeadlineExceeded {
			err = errors.New("timeout waiting for clone to complete")
		}
		return nil, err
	}
	result, err := task.WaitForResult(ctx, nil)
	if err != nil {
		if ctx.Err() == context.DeadlineExceeded {
			err = errors.New("timeout waiting for clone to complete")
		}
		return nil, err
	}
	log.Printf("[DEBUG] Virtual machine %q: clone complete (MOID: %q)", fmt.Sprintf("%s/%s", f.InventoryPath, name), result.Result.(types.ManagedObjectReference).Value)
	return FromMOID(c, result.Result.(types.ManagedObjectReference).Value)
}

func Clone ( c * govmomi . Client , src * object . VirtualMachine , f * object . Folder , name string , spec types . VirtualMachineCloneSpec , timeout int ) ( * object . VirtualMachine , error ) { log . Printf ( " " , fmt . Sprintf ( " " , f . InventoryPath , name ) ) ctx , cancel := context . WithTimeout ( context . Background ( ) , time . Minute * time . Duration ( timeout ) ) defer cancel ( ) task , err := src . Clone ( ctx , f , name , spec ) if err != nil { if ctx . Err ( ) == context . DeadlineExceeded { err = errors . New ( " " ) } return nil , err } result , err := task . WaitForResult ( ctx , nil ) if err != nil { if ctx . Err ( ) == context . DeadlineExceeded { err = errors . New ( " " ) } return nil , err } log . Printf ( " " , fmt . Sprintf ( " " , f . InventoryPath , name ) , result . Result . ( types . ManagedObjectReference ) . Value ) return FromMOID ( c , result . Result . ( types . ManagedObjectReference ) . Value ) }

// Clone wraps the creation of a virtual machine and the subsequent waiting of
// the task. A higher-level virtual machine object is returned.

Clone wraps the creation of a virtual machine and the subsequent waiting of the task . A higher - level virtual machine object is returned .


func Customize(vm *object.VirtualMachine, spec types.CustomizationSpec) error {
	log.Printf("[DEBUG] Sending customization spec to virtual machine %q", vm.InventoryPath)
	ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
	defer cancel()
	task, err := vm.Customize(ctx, spec)
	if err != nil {
		return err
	}
	tctx, tcancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
	defer tcancel()
	return task.Wait(tctx)
}

func Customize ( vm * object . VirtualMachine , spec types . CustomizationSpec ) error { log . Printf ( " " , vm . InventoryPath ) ctx , cancel := context . WithTimeout ( context . Background ( ) , provider . DefaultAPITimeout ) defer cancel ( ) task , err := vm . Customize ( ctx , spec ) if err != nil { return err } tctx , tcancel := context . WithTimeout ( context . Background ( ) , provider . DefaultAPITimeout ) defer tcancel ( ) return task . Wait ( tctx ) }

// Customize wraps the customization of a virtual machine and the subsequent
// waiting of the task.

Customize wraps the customization of a virtual machine and the subsequent waiting of the task .


func MoveToFolder(client *govmomi.Client, vm *object.VirtualMachine, relative string) error {
	log.Printf("[DEBUG] Moving virtual %q to VM path %q", vm.InventoryPath, relative)
	f, err := folder.VirtualMachineFolderFromObject(client, vm, relative)
	if err != nil {
		return err
	}
	return folder.MoveObjectTo(vm.Reference(), f)
}

func MoveToFolder ( client * govmomi . Client , vm * object . VirtualMachine , relative string ) error { log . Printf ( " " , vm . InventoryPath , relative ) f , err := folder . VirtualMachineFolderFromObject ( client , vm , relative ) if err != nil { return err } return folder . MoveObjectTo ( vm . Reference ( ) , f ) }

// MoveToFolder moves a virtual machine to the specified folder.

MoveToFolder moves a virtual machine to the specified folder .


func Relocate(vm *object.VirtualMachine, spec types.VirtualMachineRelocateSpec, timeout int) error {
	log.Printf("[DEBUG] Beginning migration of virtual machine %q (timeout %d)", vm.InventoryPath, timeout)
	ctx, cancel := context.WithTimeout(context.Background(), time.Minute*time.Duration(timeout))
	defer cancel()
	task, err := vm.Relocate(ctx, spec, "")
	if err != nil {
		return err
	}
	if err := task.Wait(ctx); err != nil {
		// Provide a friendly error message if we timed out waiting for the migration.
		if ctx.Err() == context.DeadlineExceeded {
			return errors.New("timeout waiting for migration to complete")
		}
	}
	return nil
}

// Relocate wraps the Relocate task and the subsequent waiting for the task to
// complete.

Relocate wraps the Relocate task and the subsequent waiting for the task to complete .


func MOIDForUUID(client *govmomi.Client, uuid string) (MOIDForUUIDResult, error) {
	vm, err := FromUUID(client, uuid)
	if err != nil {
		return MOIDForUUIDResult{}, err
	}
	return MOIDForUUIDResult{
		UUID: uuid,
		MOID: vm.Reference().Value,
	}, nil
}

func MOIDForUUID ( client * govmomi . Client , uuid string ) ( MOIDForUUIDResult , error ) { vm , err := FromUUID ( client , uuid ) if err != nil { return MOIDForUUIDResult { } , err } return MOIDForUUIDResult { UUID : uuid , MOID : vm . Reference ( ) . Value , } , nil }

// MOIDForUUID returns the managed object reference ID for a specific virtual
// machine UUID and returns a MOIDForUUIDResult with the appropriate
// association.

MOIDForUUID returns the managed object reference ID for a specific virtual machine UUID and returns a MOIDForUUIDResult with the appropriate association .


func UUIDForMOID(client *govmomi.Client, moid string) (MOIDForUUIDResult, error) {
	vm, err := FromMOID(client, moid)
	if err != nil {
		return MOIDForUUIDResult{}, err
	}
	props, err := Properties(vm)
	if err != nil {
		return MOIDForUUIDResult{}, err
	}
	return MOIDForUUIDResult{
		UUID: props.Config.Uuid,
		MOID: vm.Reference().Value,
	}, nil
}

func UUIDForMOID ( client * govmomi . Client , moid string ) ( MOIDForUUIDResult , error ) { vm , err := FromMOID ( client , moid ) if err != nil { return MOIDForUUIDResult { } , err } props , err := Properties ( vm ) if err != nil { return MOIDForUUIDResult { } , err } return MOIDForUUIDResult { UUID : props . Config . Uuid , MOID : vm . Reference ( ) . Value , } , nil }

// UUIDForMOID returns the managed object reference ID for a specific virtual
// machine MOID and returns a MOIDForUUIDResult with the appropriate
// association.

UUIDForMOID returns the managed object reference ID for a specific virtual machine MOID and returns a MOIDForUUIDResult with the appropriate association .


func MOIDsForUUIDs(client *govmomi.Client, uuids []string) (MOIDForUUIDResults, error) {
	var results MOIDForUUIDResults
	for _, uuid := range uuids {
		result, err := MOIDForUUID(client, uuid)
		if err != nil {
			return nil, err
		}
		results = append(results, result)
	}
	return results, nil
}

func MOIDsForUUIDs ( client * govmomi . Client , uuids [ ] string ) ( MOIDForUUIDResults , error ) { var results MOIDForUUIDResults for _ , uuid := range uuids { result , err := MOIDForUUID ( client , uuid ) if err != nil { return nil , err } results = append ( results , result ) } return results , nil }

// MOIDsForUUIDs returns a MOIDForUUIDResults for a list of UUIDs. If one UUID
// cannot be found, an error is returned. There are no partial results
// returned.

MOIDsForUUIDs returns a MOIDForUUIDResults for a list of UUIDs . If one UUID cannot be found an error is returned . There are no partial results returned .


func UUIDsForMOIDs(client *govmomi.Client, moids []string) (MOIDForUUIDResults, error) {
	var results MOIDForUUIDResults
	for _, uuid := range moids {
		result, err := UUIDForMOID(client, uuid)
		if err != nil {
			return nil, err
		}
		results = append(results, result)
	}
	return results, nil
}

func UUIDsForMOIDs ( client * govmomi . Client , moids [ ] string ) ( MOIDForUUIDResults , error ) { var results MOIDForUUIDResults for _ , uuid := range moids { result , err := UUIDForMOID ( client , uuid ) if err != nil { return nil , err } results = append ( results , result ) } return results , nil }

// UUIDsForMOIDs returns a MOIDForUUIDResults for a list of MOIDs. If one MOID
// cannot be found, an error is returned. There are no partial results
// returned.

UUIDsForMOIDs returns a MOIDForUUIDResults for a list of MOIDs . If one MOID cannot be found an error is returned . There are no partial results returned .


func UUIDsForManagedObjectReferences(client *govmomi.Client, refs []types.ManagedObjectReference) (MOIDForUUIDResults, error) {
	var moids []string
	for _, ref := range refs {
		moids = append(moids, ref.Value)
	}
	return UUIDsForMOIDs(client, moids)
}

func UUIDsForManagedObjectReferences ( client * govmomi . Client , refs [ ] types . ManagedObjectReference ) ( MOIDForUUIDResults , error ) { var moids [ ] string for _ , ref := range refs { moids = append ( moids , ref . Value ) } return UUIDsForMOIDs ( client , moids ) }

// UUIDsForManagedObjectReferences returns a MOIDForUUIDResults for a list of
// ManagedObjectReferences. If one cannot be found, an error is returned. There
// are no partial results returned.

UUIDsForManagedObjectReferences returns a MOIDForUUIDResults for a list of ManagedObjectReferences . If one cannot be found an error is returned . There are no partial results returned .


func (r MOIDForUUIDResults) MOIDs() []string {
	var moids []string
	for _, result := range r {
		moids = append(moids, result.MOID)
	}
	return moids
}

func ( r MOIDForUUIDResults ) MOIDs ( ) [ ] string { var moids [ ] string for _ , result := range r { moids = append ( moids , result . MOID ) } return moids }

// MOIDs returns all MOIDs in a MOIDForUUIDResults.

MOIDs returns all MOIDs in a MOIDForUUIDResults .


func (r MOIDForUUIDResults) ManagedObjectReferences() []types.ManagedObjectReference {
	var refs []types.ManagedObjectReference
	for _, result := range r {
		refs = append(refs, types.ManagedObjectReference{
			Type:  "VirtualMachine",
			Value: result.MOID,
		})
	}
	return refs
}

func ( r MOIDForUUIDResults ) ManagedObjectReferences ( ) [ ] types . ManagedObjectReference { var refs [ ] types . ManagedObjectReference for _ , result := range r { refs = append ( refs , types . ManagedObjectReference { Type : " " , Value : result . MOID , } ) } return refs }

// ManagedObjectReferences returns all MOIDs in a MOIDForUUIDResults, as
// ManagedObjectReferences as type VirtualMachine.

ManagedObjectReferences returns all MOIDs in a MOIDForUUIDResults as ManagedObjectReferences as type VirtualMachine .


func (r MOIDForUUIDResults) UUIDs() []string {
	var uuids []string
	for _, result := range r {
		uuids = append(uuids, result.UUID)
	}
	return uuids
}

func ( r MOIDForUUIDResults ) UUIDs ( ) [ ] string { var uuids [ ] string for _ , result := range r { uuids = append ( uuids , result . UUID ) } return uuids }

// UUIDs returns all UUIDs in a MOIDForUUIDResults.

UUIDs returns all UUIDs in a MOIDForUUIDResults .


func FromKey(client *govmomi.Client, dvsUUID, pgKey string) (*object.DistributedVirtualPortgroup, error) {
	dvsm := types.ManagedObjectReference{Type: "DistributedVirtualSwitchManager", Value: "DVSManager"}
	req := &types.DVSManagerLookupDvPortGroup{
		This:         dvsm,
		SwitchUuid:   dvsUUID,
		PortgroupKey: pgKey,
	}
	ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
	defer cancel()
	resp, err := methods.DVSManagerLookupDvPortGroup(ctx, client, req)
	if err != nil {
		return nil, err
	}

	if resp.Returnval == nil {
		return nil, NewMissingPortGroupReferenceError(
			fmt.Sprintf(
				"portgroup lookup by key returned nil result for DVS UUID %q and portgroup key %q",
				dvsUUID,
				pgKey,
			),
		)
	}

	return FromMOID(client, resp.Returnval.Reference().Value)
}

func FromKey ( client * govmomi . Client , dvsUUID , pgKey string ) ( * object . DistributedVirtualPortgroup , error ) { dvsm := types . ManagedObjectReference { Type : " " , Value : " " } req := & types . DVSManagerLookupDvPortGroup { This : dvsm , SwitchUuid : dvsUUID , PortgroupKey : pgKey , } ctx , cancel := context . WithTimeout ( context . Background ( ) , provider . DefaultAPITimeout ) defer cancel ( ) resp , err := methods . DVSManagerLookupDvPortGroup ( ctx , client , req ) if err != nil { return nil , err } if resp . Returnval == nil { return nil , NewMissingPortGroupReferenceError ( fmt . Sprintf ( " " , dvsUUID , pgKey , ) , ) } return FromMOID ( client , resp . Returnval . Reference ( ) . Value ) }

// FromKey gets a portgroup object from its key.

FromKey gets a portgroup object from its key .


func FromMOID(client *govmomi.Client, id string) (*object.DistributedVirtualPortgroup, error) {
	finder := find.NewFinder(client.Client, false)

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

	ctx, cancel := context.WithTimeout(context.Background(), provider.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
	// DistributedVirtualPortgroup, then we have bigger problems and to be
	// honest we should be panicking anyway.
	return ds.(*object.DistributedVirtualPortgroup), nil
}

// FromMOID locates a portgroup by its managed object reference ID.

FromMOID locates a portgroup by its managed object reference ID .


func FromPath(client *govmomi.Client, name string, dc *object.Datacenter) (*object.DistributedVirtualPortgroup, error) {
	finder := find.NewFinder(client.Client, false)
	if dc != nil {
		finder.SetDatacenter(dc)
	}

	ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
	defer cancel()
	net, err := finder.Network(ctx, name)
	if err != nil {
		return nil, err
	}
	if net.Reference().Type != "DistributedVirtualPortgroup" {
		return nil, fmt.Errorf("network at path %q is not a portgroup (type %s)", name, net.Reference().Type)
	}
	return FromMOID(client, net.Reference().Value)
}

func FromPath ( client * govmomi . Client , name string , dc * object . Datacenter ) ( * object . DistributedVirtualPortgroup , error ) { finder := find . NewFinder ( client . Client , false ) if dc != nil { finder . SetDatacenter ( dc ) } ctx , cancel := context . WithTimeout ( context . Background ( ) , provider . DefaultAPITimeout ) defer cancel ( ) net , err := finder . Network ( ctx , name ) if err != nil { return nil , err } if net . Reference ( ) . Type != " " { return nil , fmt . Errorf ( " " , name , net . Reference ( ) . Type ) } return FromMOID ( client , net . Reference ( ) . Value ) }

// FromPath gets a portgroup object from its path.

FromPath gets a portgroup object from its path .


func Properties(pg *object.DistributedVirtualPortgroup) (*mo.DistributedVirtualPortgroup, error) {
	ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
	defer cancel()
	var props mo.DistributedVirtualPortgroup
	if err := pg.Properties(ctx, pg.Reference(), nil, &props); err != nil {
		return nil, err
	}
	return &props, nil
}

func Properties ( pg * object . DistributedVirtualPortgroup ) ( * mo . DistributedVirtualPortgroup , error ) { ctx , cancel := context . WithTimeout ( context . Background ( ) , provider . DefaultAPITimeout ) defer cancel ( ) var props mo . DistributedVirtualPortgroup if err := pg . Properties ( ctx , pg . Reference ( ) , nil , & props ) ; err != nil { return nil , err } return & props , nil }

// Properties is a convenience method that wraps fetching the
// portgroup MO from its higher-level object.

Properties is a convenience method that wraps fetching the portgroup MO from its higher - level object .


func Create(client *govmomi.Client, dvs *object.VmwareDistributedVirtualSwitch, spec types.DVPortgroupConfigSpec) (*object.Task, error) {
	req := &types.CreateDVPortgroup_Task{
		This: dvs.Reference(),
		Spec: spec,
	}

	ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
	defer cancel()
	resp, err := methods.CreateDVPortgroup_Task(ctx, client, req)
	if err != nil {
		return nil, err
	}

	return object.NewTask(client.Client, resp.Returnval.Reference()), nil
}

func Create ( client * govmomi . Client , dvs * object . VmwareDistributedVirtualSwitch , spec types . DVPortgroupConfigSpec ) ( * object . Task , error ) { req := & types . CreateDVPortgroup_Task { This : dvs . Reference ( ) , Spec : spec , } ctx , cancel := context . WithTimeout ( context . Background ( ) , provider . DefaultAPITimeout ) defer cancel ( ) resp , err := methods . CreateDVPortgroup_Task ( ctx , client , req ) if err != nil { return nil , err } return object . NewTask ( client . Client , resp . Returnval . Reference ( ) ) , nil }

// Create exposes the CreateDVPortgroup_Task method of the
// DistributedVirtualSwitch MO.  This local implementation may go away if this
// is exposed in the higher-level object upstream.

Create exposes the CreateDVPortgroup_Task method of the DistributedVirtualSwitch MO . This local implementation may go away if this is exposed in the higher - level object upstream .


func Properties(ds *object.Datastore) (*mo.Datastore, error) {
	ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
	defer cancel()
	var props mo.Datastore
	if err := ds.Properties(ctx, ds.Reference(), nil, &props); err != nil {
		return nil, err
	}
	return &props, nil
}

func Properties ( ds * object . Datastore ) ( * mo . Datastore , error ) { ctx , cancel := context . WithTimeout ( context . Background ( ) , provider . DefaultAPITimeout ) defer cancel ( ) var props mo . Datastore if err := ds . Properties ( ctx , ds . Reference ( ) , nil , & props ) ; err != nil { return nil , err } return & props , nil }

// Properties is a convenience method that wraps fetching the
// Datastore MO from its higher-level object.

Properties is a convenience method that wraps fetching the Datastore MO from its higher - level object .


func MoveToFolder(client *govmomi.Client, ds *object.Datastore, relative string) error {
	f, err := folder.DatastoreFolderFromObject(client, ds, relative)
	if err != nil {
		return err
	}
	return folder.MoveObjectTo(ds.Reference(), f)
}

func MoveToFolder ( client * govmomi . Client , ds * object . Datastore , relative string ) error { f , err := folder . DatastoreFolderFromObject ( client , ds , relative ) if err != nil { return err } return folder . MoveObjectTo ( ds . Reference ( ) , f ) }

// MoveToFolder is a complex method that moves a datastore to a given
// relative datastore folder path. "Relative" here means relative to a
// datacenter, which is discovered from the current datastore path.

MoveToFolder is a complex method that moves a datastore to a given relative datastore folder path . Relative here means relative to a datacenter which is discovered from the current datastore path .


func MoveToFolderRelativeHostSystemID(client *govmomi.Client, ds *object.Datastore, hsID, relative string) error {
	hs, err := hostsystem.FromID(client, hsID)
	if err != nil {
		return err
	}
	f, err := folder.DatastoreFolderFromObject(client, hs, relative)
	if err != nil {
		return err
	}
	return folder.MoveObjectTo(ds.Reference(), f)
}

func MoveToFolderRelativeHostSystemID ( client * govmomi . Client , ds * object . Datastore , hsID , relative string ) error { hs , err := hostsystem . FromID ( client , hsID ) if err != nil { return err } f , err := folder . DatastoreFolderFromObject ( client , hs , relative ) if err != nil { return err } return folder . MoveObjectTo ( ds . Reference ( ) , f ) }

// MoveToFolderRelativeHostSystemID is a complex method that moves a
// datastore to a given datastore path, similar to MoveToFolder,
// except the path is relative to a HostSystem supplied by ID instead of the
// datastore.

MoveToFolderRelativeHostSystemID is a complex method that moves a datastore to a given datastore path similar to MoveToFolder except the path is relative to a HostSystem supplied by ID instead of the datastore .


func Browser(ds *object.Datastore) (*object.HostDatastoreBrowser, error) {
	ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
	defer cancel()
	return ds.Browser(ctx)
}

func Browser ( ds * object . Datastore ) ( * object . HostDatastoreBrowser , error ) { ctx , cancel := context . WithTimeout ( context . Background ( ) , provider . DefaultAPITimeout ) defer cancel ( ) return ds . Browser ( ctx ) }

// Browser returns the HostDatastoreBrowser for a certain datastore. This is a
// convenience method that exists to abstract the context.

Browser returns the HostDatastoreBrowser for a certain datastore . This is a convenience method that exists to abstract the context .


func SearchDatastore(ds *object.Datastore, name string) ([]*types.FileInfo, error) {
	result, err := searchDatastore(ds, name)
	if err != nil {
		return nil, err
	}
	var files []*types.FileInfo
	for _, bfi := range result.File {
		files = append(files, bfi.GetFileInfo())
	}
	return files, nil
}

func SearchDatastore ( ds * object . Datastore , name string ) ( [ ] * types . FileInfo , error ) { result , err := searchDatastore ( ds , name ) if err != nil { return nil , err } var files [ ] * types . FileInfo for _ , bfi := range result . File { files = append ( files , bfi . GetFileInfo ( ) ) } return files , nil }

// SearchDatastore searches a datastore using the supplied HostDatastoreBrowser
// and a supplied path. The current implementation only returns the basic
// information, so all FileQueryFlags set, but not any flags for specific types
// of files.

SearchDatastore searches a datastore using the supplied HostDatastoreBrowser and a supplied path . The current implementation only returns the basic information so all FileQueryFlags set but not any flags for specific types of files .


func FileExists(ds *object.Datastore, name string) (bool, error) {
	files, err := SearchDatastore(ds, name)
	if err != nil {
		return false, err
	}
	if len(files) > 1 {
		return false, fmt.Errorf("multiple results returned for %q in datastore %q, use a more specific search", name, ds)
	}
	if len(files) < 1 {
		return false, nil
	}
	return path.Base(name) == files[0].Path, nil
}

func FileExists ( ds * object . Datastore , name string ) ( bool , error ) { files , err := SearchDatastore ( ds , name ) if err != nil { return false , err } if len ( files ) > 1 { return false , fmt . Errorf ( " " , name , ds ) } if len ( files ) < 1 { return false , nil } return path . Base ( name ) == files [ 0 ] . Path , nil }

// FileExists takes a path in the datastore and checks to see if it exists.
//
// The path should be a bare path, not a datastore path. Globs are not allowed.

FileExists takes a path in the datastore and checks to see if it exists . The path should be a bare path not a datastore path . Globs are not allowed .


func FromPath(client *govmomi.Client, name string, dc *object.Datacenter) (*object.VirtualApp, error) {
	finder := find.NewFinder(client.Client, false)

	ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
	defer cancel()
	if dc != nil {
		finder.SetDatacenter(dc)
	}
	return finder.VirtualApp(ctx, name)
}

func FromPath ( client * govmomi . Client , name string , dc * object . Datacenter ) ( * object . VirtualApp , error ) { finder := find . NewFinder ( client . Client , false ) ctx , cancel := context . WithTimeout ( context . Background ( ) , provider . DefaultAPITimeout ) defer cancel ( ) if dc != nil { finder . SetDatacenter ( dc ) } return finder . VirtualApp ( ctx , name ) }

// FromPath returns a VirtualApp via its supplied path.

FromPath returns a VirtualApp via its supplied path .


func FromID(client *govmomi.Client, id string) (*object.VirtualApp, error) {
	log.Printf("[DEBUG] Locating vApp container with ID %s", id)
	finder := find.NewFinder(client.Client, false)

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

	ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
	defer cancel()
	obj, err := finder.ObjectReference(ctx, ref)
	if err != nil {
		return nil, err
	}
	log.Printf("[DEBUG] vApp container found: %s", obj.Reference().Value)
	return obj.(*object.VirtualApp), nil
}

func FromID ( client * govmomi . Client , id string ) ( * object . VirtualApp , error ) { log . Printf ( " " , id ) finder := find . NewFinder ( client . Client , false ) ref := types . ManagedObjectReference { Type : " " , Value : id , } ctx , cancel := context . WithTimeout ( context . Background ( ) , provider . DefaultAPITimeout ) defer cancel ( ) obj , err := finder . ObjectReference ( ctx , ref ) if err != nil { return nil , err } log . Printf ( " " , obj . Reference ( ) . Value ) return obj . ( * object . VirtualApp ) , nil }

// FromID locates a VirtualApp by its managed object reference ID.

FromID locates a VirtualApp by its managed object reference ID .


func IsVApp(client *govmomi.Client, rp string) bool {
	_, err := FromID(client, rp)
	if err != nil {
		return false
	}
	return true
}

func IsVApp ( client * govmomi . Client , rp string ) bool { _ , err := FromID ( client , rp ) if err != nil { return false } return true }

// IsVApp checks if a given managed object ID is a vApp. This is useful
// deciding if a given resource pool is a vApp or a standard resource pool.

IsVApp checks if a given managed object ID is a vApp . This is useful deciding if a given resource pool is a vApp or a standard resource pool .


func Create(rp *object.ResourcePool, name string, resSpec *types.ResourceConfigSpec, vSpec *types.VAppConfigSpec, folder *object.Folder) (*object.VirtualApp, error) {
	log.Printf("[DEBUG] Creating vApp container %s/%s", rp.InventoryPath, name)
	ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
	defer cancel()
	nva, err := rp.CreateVApp(ctx, name, *resSpec, *vSpec, folder)
	if err != nil {
		return nil, err
	}
	return nva, nil
}

func Create ( rp * object . ResourcePool , name string , resSpec * types . ResourceConfigSpec , vSpec * types . VAppConfigSpec , folder * object . Folder ) ( * object . VirtualApp , error ) { log . Printf ( " " , rp . InventoryPath , name ) ctx , cancel := context . WithTimeout ( context . Background ( ) , provider . DefaultAPITimeout ) defer cancel ( ) nva , err := rp . CreateVApp ( ctx , name , * resSpec , * vSpec , folder ) if err != nil { return nil , err } return nva , nil }


func Update(vc *object.VirtualApp, spec types.VAppConfigSpec) error {
	log.Printf("[DEBUG] Updating vApp container %q", vc.InventoryPath)
	ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
	defer cancel()
	return vc.UpdateConfig(ctx, spec)
}

func Update ( vc * object . VirtualApp , spec types . VAppConfigSpec ) error { log . Printf ( " " , vc . InventoryPath ) ctx , cancel := context . WithTimeout ( context . Background ( ) , provider . DefaultAPITimeout ) defer cancel ( ) return vc . UpdateConfig ( ctx , spec ) }


func ResourceIDString(d ResourceIDStringer, name string) string {
	id := d.Id()
	if id == "" {
		id = "<new resource>"
	}
	return fmt.Sprintf("%s (ID = %s)", name, id)
}

func ResourceIDString ( d ResourceIDStringer , name string ) string { id := d . Id ( ) if id == " " { id = " " } return fmt . Sprintf ( " " , name , id ) }

// ResourceIDString prints a friendly string for a resource, supplied by name.

ResourceIDString prints a friendly string for a resource supplied by name .


func SliceInterfacesToStrings(s []interface{}) []string {
	var d []string
	for _, v := range s {
		if o, ok := v.(string); ok {
			d = append(d, o)
		}
	}
	return d
}

func SliceInterfacesToStrings ( s [ ] interface { } ) [ ] string { var d [ ] string for _ , v := range s { if o , ok := v . ( string ) ; ok { d = append ( d , o ) } } return d }

// SliceInterfacesToStrings converts an interface slice to a string slice. The
// function does not attempt to do any sanity checking and will panic if one of
// the items in the slice is not a string.

SliceInterfacesToStrings converts an interface slice to a string slice . The function does not attempt to do any sanity checking and will panic if one of the items in the slice is not a string .


func SliceStringsToInterfaces(s []string) []interface{} {
	var d []interface{}
	for _, v := range s {
		d = append(d, v)
	}
	return d
}

func SliceStringsToInterfaces ( s [ ] string ) [ ] interface { } { var d [ ] interface { } for _ , v := range s { d = append ( d , v ) } return d }

// SliceStringsToInterfaces converts a string slice to an interface slice.

SliceStringsToInterfaces converts a string slice to an interface slice .


func SliceInterfacesToManagedObjectReferences(s []interface{}, t string) []types.ManagedObjectReference {
	var d []types.ManagedObjectReference
	for _, v := range s {
		d = append(d, types.ManagedObjectReference{
			Type:  t,
			Value: v.(string),
		})
	}
	return d
}

// SliceInterfacesToManagedObjectReferences converts an interface slice into a
// slice of ManagedObjectReferences with the type of t.


func BoolStringPtrState(v interface{}) string {
	b, err := strconv.ParseBool(v.(string))
	if err != nil {
		return ""
	}
	return strconv.FormatBool(b)
}

func BoolStringPtrState ( v interface { } ) string { b , err := strconv . ParseBool ( v . ( string ) ) if err != nil { return " " } return strconv . FormatBool ( b ) }

// BoolStringPtrState is a state normalization function for stringified 3-state
// bool pointers.
//
// The function silently drops any result that can't be parsed with ParseBool,
// and will return an empty string for these cases.
//
// This is designed to address the current lack of HCL and Terraform to be able
// to distinguish between nil states and zero values properly. This is a
// systemic issue that affects reading, writing, and diffing of these values.
// These issues will eventually be addressed in HCL2.

BoolStringPtrState is a state normalization function for stringified 3 - state bool pointers . The function silently drops any result that can t be parsed with ParseBool and will return an empty string for these cases . This is designed to address the current lack of HCL and Terraform to be able to distinguish between nil states and zero values properly . This is a systemic issue that affects reading writing and diffing of these values . These issues will eventually be addressed in HCL2 .


func ValidateBoolStringPtr() schema.SchemaValidateFunc {
	return func(i interface{}, k string) (s []string, es []error) {
		v := i.(string)
		if v == "" {
			return
		}
		if _, err := strconv.ParseBool(v); err != nil {
			es = append(es, err)
		}
		return
	}
}

func ValidateBoolStringPtr ( ) schema . SchemaValidateFunc { return func ( i interface { } , k string ) ( s [ ] string , es [ ] error ) { v := i . ( string ) if v == " " { return } if _ , err := strconv . ParseBool ( v ) ; err != nil { es = append ( es , err ) } return } }

// ValidateBoolStringPtr validates that the input value can be parsed by
// ParseBool. It also succeeds on empty strings.
//
// This is designed to address the current lack of HCL and Terraform to be able
// to distinguish between nil states and zero values properly. This is a
// systemic issue that affects reading, writing, and diffing of these values.
// These issues will eventually be addressed in HCL2.

ValidateBoolStringPtr validates that the input value can be parsed by ParseBool . It also succeeds on empty strings . This is designed to address the current lack of HCL and Terraform to be able to distinguish between nil states and zero values properly . This is a systemic issue that affects reading writing and diffing of these values . These issues will eventually be addressed in HCL2 .


func BoolPolicy(b bool) *types.BoolPolicy {
	bp := &types.BoolPolicy{
		Value: BoolPtr(b),
	}
	return bp
}

func BoolPolicy ( b bool ) * types . BoolPolicy { bp := & types . BoolPolicy { Value : BoolPtr ( b ) , } return bp }

// BoolPolicy converts a bool into a VMware BoolPolicy value.

BoolPolicy converts a bool into a VMware BoolPolicy value .


func GetBoolPolicy(d *schema.ResourceData, key string) *types.BoolPolicy {
	v, e := d.GetOkExists(key)
	if e {
		return BoolPolicy(v.(bool))
	}
	return nil
}

func GetBoolPolicy ( d * schema . ResourceData , key string ) * types . BoolPolicy { v , e := d . GetOkExists ( key ) if e { return BoolPolicy ( v . ( bool ) ) } return nil }

// GetBoolPolicy reads a ResourceData and returns an appropriate BoolPolicy for
// the state of the definition. nil is returned if it does not exist.

GetBoolPolicy reads a ResourceData and returns an appropriate BoolPolicy for the state of the definition . nil is returned if it does not exist .


func SetBoolPolicy(d *schema.ResourceData, key string, val *types.BoolPolicy) error {
	if val == nil {
		return nil
	}
	err := d.Set(key, val.Value)
	return err
}

func SetBoolPolicy ( d * schema . ResourceData , key string , val * types . BoolPolicy ) error { if val == nil { return nil } err := d . Set ( key , val . Value ) return err }

// SetBoolPolicy sets a ResourceData field depending on if a BoolPolicy exists
// or not. The field is not set if it's nil.

SetBoolPolicy sets a ResourceData field depending on if a BoolPolicy exists or not . The field is not set if it s nil .


func StringPolicy(s string) *types.StringPolicy {
	sp := &types.StringPolicy{
		Value: s,
	}
	return sp
}

func StringPolicy ( s string ) * types . StringPolicy { sp := & types . StringPolicy { Value : s , } return sp }

// StringPolicy converts a string into a VMware StringPolicy value.

StringPolicy converts a string into a VMware StringPolicy value .


func GetStringPolicy(d *schema.ResourceData, key string) *types.StringPolicy {
	v, e := d.GetOkExists(key)
	if e {
		return StringPolicy(v.(string))
	}
	return nil
}

func GetStringPolicy ( d * schema . ResourceData , key string ) * types . StringPolicy { v , e := d . GetOkExists ( key ) if e { return StringPolicy ( v . ( string ) ) } return nil }

// GetStringPolicy reads a ResourceData and returns an appropriate StringPolicy
// for the state of the definition. nil is returned if it does not exist.

GetStringPolicy reads a ResourceData and returns an appropriate StringPolicy for the state of the definition . nil is returned if it does not exist .


func SetStringPolicy(d *schema.ResourceData, key string, val *types.StringPolicy) error {
	if val == nil {
		return nil
	}
	err := d.Set(key, val.Value)
	return err
}

func SetStringPolicy ( d * schema . ResourceData , key string , val * types . StringPolicy ) error { if val == nil { return nil } err := d . Set ( key , val . Value ) return err }

// SetStringPolicy sets a ResourceData field depending on if a StringPolicy
// exists or not. The field is not set if it's nil.

SetStringPolicy sets a ResourceData field depending on if a StringPolicy exists or not . The field is not set if it s nil .


func LongPolicy(n interface{}) *types.LongPolicy {
	lp := &types.LongPolicy{}
	switch v := n.(type) {
	case int:
		lp.Value = int64(v)
	case int8:
		lp.Value = int64(v)
	case int16:
		lp.Value = int64(v)
	case int32:
		lp.Value = int64(v)
	case uint:
		lp.Value = int64(v)
	case uint8:
		lp.Value = int64(v)
	case uint16:
		lp.Value = int64(v)
	case uint32:
		lp.Value = int64(v)
	case int64:
		lp.Value = v
	default:
		panic(fmt.Errorf("non-convertible type %T for value", n))
	}
	return lp
}

func LongPolicy ( n interface { } ) * types . LongPolicy { lp := & types . LongPolicy { } switch v := n . ( type ) { case int : lp . Value = int64 ( v ) case int8 : lp . Value = int64 ( v ) case int16 : lp . Value = int64 ( v ) case int32 : lp . Value = int64 ( v ) case uint : lp . Value = int64 ( v ) case uint8 : lp . Value = int64 ( v ) case uint16 : lp . Value = int64 ( v ) case uint32 : lp . Value = int64 ( v ) case int64 : lp . Value = v default : panic ( fmt . Errorf ( " " , n ) ) } return lp }

// LongPolicy converts a supported number into a VMware LongPolicy value. This
// will panic if there is no implicit conversion of the value into an int64.

LongPolicy converts a supported number into a VMware LongPolicy value . This will panic if there is no implicit conversion of the value into an int64 .


func GetLongPolicy(d *schema.ResourceData, key string) *types.LongPolicy {
	v, e := d.GetOkExists(key)
	if e {
		return LongPolicy(v)
	}
	return nil
}

func GetLongPolicy ( d * schema . ResourceData , key string ) * types . LongPolicy { v , e := d . GetOkExists ( key ) if e { return LongPolicy ( v ) } return nil }

// GetLongPolicy reads a ResourceData and returns an appropriate LongPolicy
// for the state of the definition. nil is returned if it does not exist.

GetLongPolicy reads a ResourceData and returns an appropriate LongPolicy for the state of the definition . nil is returned if it does not exist .


func SetLongPolicy(d *schema.ResourceData, key string, val *types.LongPolicy) error {
	if val == nil {
		return nil
	}
	err := d.Set(key, val.Value)
	return err
}

func SetLongPolicy ( d * schema . ResourceData , key string , val * types . LongPolicy ) error { if val == nil { return nil } err := d . Set ( key , val . Value ) return err }

// SetLongPolicy sets a ResourceData field depending on if a LongPolicy
// exists or not. The field is not set if it's nil.

SetLongPolicy sets a ResourceData field depending on if a LongPolicy exists or not . The field is not set if it s nil .


func AllFieldsEmpty(v interface{}) bool {
	if v == nil {
		return true
	}

	t := reflect.TypeOf(v)
	if t.Kind() != reflect.Struct && (t.Kind() == reflect.Ptr && t.Elem().Kind() != reflect.Struct) {
		if reflect.Zero(t).Interface() != reflect.ValueOf(v).Interface() {
			return false
		}
		return true
	}
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	for i := 0; i < t.NumField(); i++ {
		var fv reflect.Value
		if reflect.ValueOf(v).Kind() == reflect.Ptr {
			fv = reflect.ValueOf(v).Elem().Field(i)
		} else {
			fv = reflect.ValueOf(v).Elem().Field(i)
		}

		ft := t.Field(i).Type
		fz := reflect.Zero(ft)
		switch ft.Kind() {
		case reflect.Map, reflect.Slice:
			if fv.Len() > 0 {
				return false
			}
		default:
			if fz.Interface() != fv.Interface() {
				return false
			}
		}
	}

	return true
}

func AllFieldsEmpty ( v interface { } ) bool { if v == nil { return true } t := reflect . TypeOf ( v ) if t . Kind ( ) != reflect . Struct && ( t . Kind ( ) == reflect . Ptr && t . Elem ( ) . Kind ( ) != reflect . Struct ) { if reflect . Zero ( t ) . Interface ( ) != reflect . ValueOf ( v ) . Interface ( ) { return false } return true } if t . Kind ( ) == reflect . Ptr { t = t . Elem ( ) } for i := 0 ; i < t . NumField ( ) ; i ++ { var fv reflect . Value if reflect . ValueOf ( v ) . Kind ( ) == reflect . Ptr { fv = reflect . ValueOf ( v ) . Elem ( ) . Field ( i ) } else { fv = reflect . ValueOf ( v ) . Elem ( ) . Field ( i ) } ft := t . Field ( i ) . Type fz := reflect . Zero ( ft ) switch ft . Kind ( ) { case reflect . Map , reflect . Slice : if fv . Len ( ) > 0 { return false } default : if fz . Interface ( ) != fv . Interface ( ) { return false } } } return true }

// AllFieldsEmpty checks to see if all fields in a given struct are zero
// values. It does not recurse, so finer-grained checking should be done for
// deep accuracy when necessary. It also does not dereference pointers, except
// if the value itself is a pointer and is not nil.

AllFieldsEmpty checks to see if all fields in a given struct are zero values . It does not recurse so finer - grained checking should be done for deep accuracy when necessary . It also does not dereference pointers except if the value itself is a pointer and is not nil .


func DeRef(v interface{}) interface{} {
	if v == nil {
		return nil
	}
	k := reflect.TypeOf(v).Kind()
	if k != reflect.Ptr {
		return v
	}
	if reflect.ValueOf(v) == reflect.Zero(reflect.TypeOf(v)) {
		// All zero-value pointers are nil
		return nil
	}
	return reflect.ValueOf(v).Elem().Interface()
}

func
DeRef
(
v
interface
{
}
)
interface
{
}
{
if
v
==
{
return
}
k
:=
reflect
.
TypeOf
(
v
)
.
Kind
(
)
if
k
!=
reflect
.
Ptr
{
return
v
}
if
reflect
.
ValueOf
(
v
)
==
reflect
.
Zero
(
reflect
.
TypeOf
(
v
)
)
{
// All zero-value pointers are nil
return
}
return
reflect
.
ValueOf
(
v
)
.
Elem
(
)
.
Interface
(
)
}

// DeRef returns the value pointed to by the interface if the interface is a
// pointer and is not nil, otherwise returns nil, or the direct value if it's
// not a pointer.

DeRef returns the value pointed to by the interface if the interface is a pointer and is not nil otherwise returns nil or the direct value if it s not a pointer .


func (s MoRefSorter) Less(i, j int) bool {
	return s[i].Value < s[j].Value
}

func ( s MoRefSorter ) Less ( i , j int ) bool { return s [ i ] . Value < s [ j ] . Value }

// Less helps implement sort.Interface for MoRefSorter.

Less helps implement sort . Interface for MoRefSorter .


func (s MoRefSorter) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func ( s MoRefSorter ) Swap ( i , j int ) { s [ i ] , s [ j ] = s [ j ] , s [ i ] }

// Swap helps implement sort.Interface for MoRefSorter.

Swap helps implement sort . Interface for MoRefSorter .


func hostDatastoreSystemFromHostSystemID(client *govmomi.Client, hsID string) (*object.HostDatastoreSystem, error) {
	hs, err := hostsystem.FromID(client, hsID)
	if err != nil {
		return nil, err
	}
	ctx, cancel := context.WithTimeout(context.Background(), defaultAPITimeout)
	defer cancel()
	return hs.ConfigManager().DatastoreSystem(ctx)
}

func hostDatastoreSystemFromHostSystemID ( client * govmomi . Client , hsID string ) ( * object . HostDatastoreSystem , error ) { hs , err := hostsystem . FromID ( client , hsID ) if err != nil { return nil , err } ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultAPITimeout ) defer cancel ( ) return hs . ConfigManager ( ) . DatastoreSystem ( ctx ) }

// hostDatastoreSystemFromHostSystemID locates a HostDatastoreSystem from a
// specified HostSystem managed object ID.

hostDatastoreSystemFromHostSystemID locates a HostDatastoreSystem from a specified HostSystem managed object ID .


func availableScsiDisk(dss *object.HostDatastoreSystem, name string) (*types.HostScsiDisk, error) {
	ctx, cancel := context.WithTimeout(context.Background(), defaultAPITimeout)
	defer cancel()
	disks, err := dss.QueryAvailableDisksForVmfs(ctx)
	if err != nil {
		return nil, fmt.Errorf("cannot query available disks: %s", err)
	}

	var disk *types.HostScsiDisk
	for _, d := range disks {
		if d.CanonicalName == name {
			disk = &d
			break
		}
	}
	if disk == nil {
		return nil, fmt.Errorf("%s does not seem to be a disk available for VMFS", name)
	}
	return disk, nil
}

func availableScsiDisk ( dss * object . HostDatastoreSystem , name string ) ( * types . HostScsiDisk , error ) { ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultAPITimeout ) defer cancel ( ) disks , err := dss . QueryAvailableDisksForVmfs ( ctx ) if err != nil { return nil , fmt . Errorf ( " " , err ) } var disk * types . HostScsiDisk for _ , d := range disks { if d . CanonicalName == name { disk = & d break } } if disk == nil { return nil , fmt . Errorf ( " " , name ) } return disk , nil }

// availableScsiDisk checks to make sure that a disk is available for use in a
// VMFS datastore, and returns the ScsiDisk.

availableScsiDisk checks to make sure that a disk is available for use in a VMFS datastore and returns the ScsiDisk .


func diskSpecForCreate(dss *object.HostDatastoreSystem, name string) (*types.VmfsDatastoreCreateSpec, error) {
	disk, err := availableScsiDisk(dss, name)
	if err != nil {
		return nil, err
	}

	ctx, cancel := context.WithTimeout(context.Background(), defaultAPITimeout)
	defer cancel()
	options, err := dss.QueryVmfsDatastoreCreateOptions(ctx, disk.DevicePath)
	if err != nil {
		return nil, fmt.Errorf("could not get disk creation options for %q: %s", name, err)
	}
	var option *types.VmfsDatastoreOption
	for _, o := range options {
		if _, ok := o.Info.(*types.VmfsDatastoreAllExtentOption); ok {
			option = &o
			break
		}
	}
	if option == nil {
		return nil, fmt.Errorf("device %q is not available as a new whole-disk device for datastore", name)
	}
	return option.Spec.(*types.VmfsDatastoreCreateSpec), nil
}

func diskSpecForCreate ( dss * object . HostDatastoreSystem , name string ) ( * types . VmfsDatastoreCreateSpec , error ) { disk , err := availableScsiDisk ( dss , name ) if err != nil { return nil , err } ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultAPITimeout ) defer cancel ( ) options , err := dss . QueryVmfsDatastoreCreateOptions ( ctx , disk . DevicePath ) if err != nil { return nil , fmt . Errorf ( " " , name , err ) } var option * types . VmfsDatastoreOption for _ , o := range options { if _ , ok := o . Info . ( * types . VmfsDatastoreAllExtentOption ) ; ok { option = & o break } } if option == nil { return nil , fmt . Errorf ( " " , name ) } return option . Spec . ( * types . VmfsDatastoreCreateSpec ) , nil }

// diskSpecForCreate checks to make sure that a disk is available to be used to
// create a VMFS datastore, specifically in its entirety, and returns a
// respective VmfsDatastoreCreateSpec.

diskSpecForCreate checks to make sure that a disk is available to be used to create a VMFS datastore specifically in its entirety and returns a respective VmfsDatastoreCreateSpec .


func diskSpecForExtend(dss *object.HostDatastoreSystem, ds *object.Datastore, name string) (*types.VmfsDatastoreExtendSpec, error) {
	disk, err := availableScsiDisk(dss, name)
	if err != nil {
		return nil, err
	}

	props, err := datastore.Properties(ds)
	if err != nil {
		return nil, fmt.Errorf("error getting properties for datastore ID %q: %s", ds.Reference().Value, err)
	}

	ctx, cancel := context.WithTimeout(context.Background(), defaultAPITimeout)
	defer cancel()
	options, err := queryVmfsDatastoreExtendOptions(ctx, dss, ds, disk.DevicePath, true)
	if err != nil {
		return nil, fmt.Errorf("could not get disk extension options for %q: %s", name, err)
	}
	var option *types.VmfsDatastoreOption
	for _, o := range options {
		if _, ok := o.Info.(*types.VmfsDatastoreAllExtentOption); ok {
			option = &o
			break
		}
	}
	if option == nil {
		return nil, fmt.Errorf("device %q cannot be used as a new whole-disk device for datastore %q", name, props.Summary.Name)
	}
	return option.Spec.(*types.VmfsDatastoreExtendSpec), nil
}

func diskSpecForExtend ( dss * object . HostDatastoreSystem , ds * object . Datastore , name string ) ( * types . VmfsDatastoreExtendSpec , error ) { disk , err := availableScsiDisk ( dss , name ) if err != nil { return nil , err } props , err := datastore . Properties ( ds ) if err != nil { return nil , fmt . Errorf ( " " , ds . Reference ( ) . Value , err ) } ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultAPITimeout ) defer cancel ( ) options , err := queryVmfsDatastoreExtendOptions ( ctx , dss , ds , disk . DevicePath , true ) if err != nil { return nil , fmt . Errorf ( " " , name , err ) } var option * types . VmfsDatastoreOption for _ , o := range options { if _ , ok := o . Info . ( * types . VmfsDatastoreAllExtentOption ) ; ok { option = & o break } } if option == nil { return nil , fmt . Errorf ( " " , name , props . Summary . Name ) } return option . Spec . ( * types . VmfsDatastoreExtendSpec ) , nil }

// diskSpecForExtend checks to make sure that a disk is available to be
// used to extend a VMFS datastore, specifically in its entirety, and returns a
// respective VmfsDatastoreExtendSpec if it is. An error is returned if it's
// not.

diskSpecForExtend checks to make sure that a disk is available to be used to extend a VMFS datastore specifically in its entirety and returns a respective VmfsDatastoreExtendSpec if it is . An error is returned if it s not .


func removeDatastore(s *object.HostDatastoreSystem, ds *object.Datastore) error {
	ctx, cancel := context.WithTimeout(context.Background(), defaultAPITimeout)
	defer cancel()
	return s.Remove(ctx, ds)
}

func removeDatastore ( s * object . HostDatastoreSystem , ds * object . Datastore ) error { ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultAPITimeout ) defer cancel ( ) return s . Remove ( ctx , ds ) }

// removeDatastore is a convenience method for removing a referenced datastore.

removeDatastore is a convenience method for removing a referenced datastore .