func expandVmwareDistributedVirtualSwitchTrunkVlanSpec(d *schema.ResourceData) *types.VmwareDistributedVirtualSwitchTrunkVlanSpec {
	var ranges []types.NumericRange
	data := d.Get("vlan_range").(*schema.Set).List()
	for _, v := range data {
		log.Printf("[DEBUG] processing range: %#v", v)
		r := v.(map[string]interface{})
		min := r["min_vlan"].(int)
		max := r["max_vlan"].(int)
		rng := types.NumericRange{
			Start: int32(min),
			End:   int32(max),
		}
		ranges = append(ranges, rng)
	}

	if len(ranges) < 1 {
		return nil
	}

	obj := &types.VmwareDistributedVirtualSwitchTrunkVlanSpec{
		VlanId: ranges,
	}
	return obj
}

// expandVmwareDistributedVirtualSwitchTrunkVlanSpec reads certain ResourceData keys and
// returns a VmwareDistributedVirtualSwitchTrunkVlanSpec.


func flattenVmwareDistributedVirtualSwitchTrunkVlanSpec(d *schema.ResourceData, obj *types.VmwareDistributedVirtualSwitchTrunkVlanSpec) error {
	var s []interface{}
	for _, rng := range obj.VlanId {
		m := make(map[string]interface{})
		m["min_vlan"] = rng.Start
		m["max_vlan"] = rng.End
		s = append(s, m)
	}
	if err := d.Set("vlan_range", s); err != nil {
		return err
	}
	return nil
}

// flattenVmwareDistributedVirtualSwitchTrunkVlanSpec reads various fields from a
// VmwareDistributedVirtualSwitchTrunkVlanSpec into the passed in ResourceData.


func expandVmwareDistributedVirtualSwitchPvlanSpec(d *schema.ResourceData) *types.VmwareDistributedVirtualSwitchPvlanSpec {
	obj := &types.VmwareDistributedVirtualSwitchPvlanSpec{
		PvlanId: int32(d.Get("port_private_secondary_vlan_id").(int)),
	}
	return obj
}

// expandVmwareDistributedVirtualSwitchPvlanSpec reads certain ResourceData keys and
// returns a VmwareDistributedVirtualSwitchPvlanSpec.


func flattenVmwareDistributedVirtualSwitchPvlanSpec(d *schema.ResourceData, obj *types.VmwareDistributedVirtualSwitchPvlanSpec) error {
	d.Set("port_private_secondary_vlan_id", obj.PvlanId)
	return nil
}

// flattenVmwareDistributedVirtualSwitchPvlanSpec reads various fields from a
// VmwareDistributedVirtualSwitchPvlanSpec into the passed in ResourceData.


func expandBaseVmwareDistributedVirtualSwitchVlanSpec(d *schema.ResourceData) types.BaseVmwareDistributedVirtualSwitchVlanSpec {
	var obj types.BaseVmwareDistributedVirtualSwitchVlanSpec

	_, ide := d.GetOkExists("vlan_id")
	_, pvid := d.GetOkExists("port_private_secondary_vlan_id")
	vteList, vteOK := d.GetOkExists("vlan_range")
	vte := vteOK && len(vteList.(*schema.Set).List()) > 0
	switch {
	case vte:
		obj = expandVmwareDistributedVirtualSwitchTrunkVlanSpec(d)
	case pvid:
		obj = expandVmwareDistributedVirtualSwitchPvlanSpec(d)
	case ide:
		obj = expandVmwareDistributedVirtualSwitchVlanIDSpec(d)
	}

	return obj
}

// expandBaseVmwareDistributedVirtualSwitchVlanSpec reads certain ResourceData keys and
// returns a BaseVmwareDistributedVirtualSwitchVlanSpec.


func flattenBaseVmwareDistributedVirtualSwitchVlanSpec(d *schema.ResourceData, obj types.BaseVmwareDistributedVirtualSwitchVlanSpec) error {
	if obj == nil {
		return nil
	}

	var err error

	switch t := obj.(type) {
	case *types.VmwareDistributedVirtualSwitchVlanIdSpec:
		err = flattenVmwareDistributedVirtualSwitchVlanIDSpec(d, t)
	case *types.VmwareDistributedVirtualSwitchTrunkVlanSpec:
		err = flattenVmwareDistributedVirtualSwitchTrunkVlanSpec(d, t)
	case *types.VmwareDistributedVirtualSwitchPvlanSpec:
		err = flattenVmwareDistributedVirtualSwitchPvlanSpec(d, t)
	}

	return err
}

// flattenBaseVmwareDistributedVirtualSwitchVlanSpec reads various fields from a
// BaseVmwareDistributedVirtualSwitchVlanSpec into the passed in ResourceData.


func expandDVSFailureCriteria(d *schema.ResourceData) *types.DVSFailureCriteria {
	obj := &types.DVSFailureCriteria{
		CheckBeacon: structure.GetBoolPolicy(d, "check_beacon"),
	}

	if structure.AllFieldsEmpty(obj) {
		return nil
	}
	return obj
}

func expandDVSFailureCriteria ( d * schema . ResourceData ) * types . DVSFailureCriteria { obj := & types . DVSFailureCriteria { CheckBeacon : structure . GetBoolPolicy ( d , " " ) , } if structure . AllFieldsEmpty ( obj ) { return nil } return obj }

// expandDVSFailureCriteria reads certain ResourceData keys and
// returns a DVSFailureCriteria.

expandDVSFailureCriteria reads certain ResourceData keys and returns a DVSFailureCriteria .


func flattenDVSFailureCriteria(d *schema.ResourceData, obj *types.DVSFailureCriteria) error {
	if obj == nil {
		return nil
	}

	structure.SetBoolPolicy(d, "check_beacon", obj.CheckBeacon)
	return nil
}

func flattenDVSFailureCriteria ( d * schema . ResourceData , obj * types . DVSFailureCriteria ) error { if obj == nil { return nil } structure . SetBoolPolicy ( d , " " , obj . CheckBeacon ) return nil }

// flattenDVSFailureCriteria reads various fields from a
// DVSFailureCriteria into the passed in ResourceData.

flattenDVSFailureCriteria reads various fields from a DVSFailureCriteria into the passed in ResourceData .


func expandVMwareUplinkPortOrderPolicy(d *schema.ResourceData) *types.VMwareUplinkPortOrderPolicy {
	obj := &types.VMwareUplinkPortOrderPolicy{
		ActiveUplinkPort:  structure.SliceInterfacesToStrings(d.Get("active_uplinks").([]interface{})),
		StandbyUplinkPort: structure.SliceInterfacesToStrings(d.Get("standby_uplinks").([]interface{})),
	}

	if structure.AllFieldsEmpty(obj) {
		return nil
	}
	return obj
}

func expandVMwareUplinkPortOrderPolicy ( d * schema . ResourceData ) * types . VMwareUplinkPortOrderPolicy { obj := & types . VMwareUplinkPortOrderPolicy { ActiveUplinkPort : structure . SliceInterfacesToStrings ( d . Get ( " " ) . ( [ ] interface { } ) ) , StandbyUplinkPort : structure . SliceInterfacesToStrings ( d . Get ( " " ) . ( [ ] interface { } ) ) , } if structure . AllFieldsEmpty ( obj ) { return nil } return obj }

// expandVMwareUplinkPortOrderPolicy reads certain ResourceData keys and
// returns a VMwareUplinkPortOrderPolicy.

expandVMwareUplinkPortOrderPolicy reads certain ResourceData keys and returns a VMwareUplinkPortOrderPolicy .


func flattenVMwareUplinkPortOrderPolicy(d *schema.ResourceData, obj *types.VMwareUplinkPortOrderPolicy) error {
	if obj == nil {
		return nil
	}

	if err := d.Set("active_uplinks", obj.ActiveUplinkPort); err != nil {
		return err
	}
	if err := d.Set("standby_uplinks", obj.StandbyUplinkPort); err != nil {
		return err
	}
	return nil
}

func flattenVMwareUplinkPortOrderPolicy ( d * schema . ResourceData , obj * types . VMwareUplinkPortOrderPolicy ) error { if obj == nil { return nil } if err := d . Set ( " " , obj . ActiveUplinkPort ) ; err != nil { return err } if err := d . Set ( " " , obj . StandbyUplinkPort ) ; err != nil { return err } return nil }

// flattenVMwareUplinkPortOrderPolicy reads various fields from a
// VMwareUplinkPortOrderPolicy into the passed in ResourceData.

flattenVMwareUplinkPortOrderPolicy reads various fields from a VMwareUplinkPortOrderPolicy into the passed in ResourceData .


func expandVmwareUplinkPortTeamingPolicy(d *schema.ResourceData) *types.VmwareUplinkPortTeamingPolicy {
	obj := &types.VmwareUplinkPortTeamingPolicy{
		Policy:          structure.GetStringPolicy(d, "teaming_policy"),
		NotifySwitches:  structure.GetBoolPolicy(d, "notify_switches"),
		RollingOrder:    structure.GetBoolPolicyReverse(d, "failback"),
		FailureCriteria: expandDVSFailureCriteria(d),
		UplinkPortOrder: expandVMwareUplinkPortOrderPolicy(d),
	}

	if structure.AllFieldsEmpty(obj) {
		return nil
	}
	return obj
}

func expandVmwareUplinkPortTeamingPolicy ( d * schema . ResourceData ) * types . VmwareUplinkPortTeamingPolicy { obj := & types . VmwareUplinkPortTeamingPolicy { Policy : structure . GetStringPolicy ( d , " " ) , NotifySwitches : structure . GetBoolPolicy ( d , " " ) , RollingOrder : structure . GetBoolPolicyReverse ( d , " " ) , FailureCriteria : expandDVSFailureCriteria ( d ) , UplinkPortOrder : expandVMwareUplinkPortOrderPolicy ( d ) , } if structure . AllFieldsEmpty ( obj ) { return nil } return obj }

// expandVmwareUplinkPortTeamingPolicy reads certain ResourceData keys and
// returns a VmwareUplinkPortTeamingPolicy.

expandVmwareUplinkPortTeamingPolicy reads certain ResourceData keys and returns a VmwareUplinkPortTeamingPolicy .


func flattenVmwareUplinkPortTeamingPolicy(d *schema.ResourceData, obj *types.VmwareUplinkPortTeamingPolicy) error {
	if obj == nil {
		return nil
	}

	structure.SetStringPolicy(d, "teaming_policy", obj.Policy)
	structure.SetBoolPolicy(d, "notify_switches", obj.NotifySwitches)
	structure.SetBoolPolicyReverse(d, "failback", obj.RollingOrder)

	if err := flattenDVSFailureCriteria(d, obj.FailureCriteria); err != nil {
		return err
	}
	if err := flattenVMwareUplinkPortOrderPolicy(d, obj.UplinkPortOrder); err != nil {
		return err
	}
	return nil
}

func flattenVmwareUplinkPortTeamingPolicy ( d * schema . ResourceData , obj * types . VmwareUplinkPortTeamingPolicy ) error { if obj == nil { return nil } structure . SetStringPolicy ( d , " " , obj . Policy ) structure . SetBoolPolicy ( d , " " , obj . NotifySwitches ) structure . SetBoolPolicyReverse ( d , " " , obj . RollingOrder ) if err := flattenDVSFailureCriteria ( d , obj . FailureCriteria ) ; err != nil { return err } if err := flattenVMwareUplinkPortOrderPolicy ( d , obj . UplinkPortOrder ) ; err != nil { return err } return nil }

// flattenVmwareUplinkPortTeamingPolicy reads various fields from a
// VmwareUplinkPortTeamingPolicy into the passed in ResourceData.

flattenVmwareUplinkPortTeamingPolicy reads various fields from a VmwareUplinkPortTeamingPolicy into the passed in ResourceData .


func expandDVSSecurityPolicy(d *schema.ResourceData) *types.DVSSecurityPolicy {
	obj := &types.DVSSecurityPolicy{
		AllowPromiscuous: structure.GetBoolPolicy(d, "allow_promiscuous"),
		MacChanges:       structure.GetBoolPolicy(d, "allow_mac_changes"),
		ForgedTransmits:  structure.GetBoolPolicy(d, "allow_forged_transmits"),
	}

	if structure.AllFieldsEmpty(obj) {
		return nil
	}
	return obj
}

func expandDVSSecurityPolicy ( d * schema . ResourceData ) * types . DVSSecurityPolicy { obj := & types . DVSSecurityPolicy { AllowPromiscuous : structure . GetBoolPolicy ( d , " " ) , MacChanges : structure . GetBoolPolicy ( d , " " ) , ForgedTransmits : structure . GetBoolPolicy ( d , " " ) , } if structure . AllFieldsEmpty ( obj ) { return nil } return obj }

// expandDVSSecurityPolicy reads certain ResourceData keys and
// returns a DVSSecurityPolicy.

expandDVSSecurityPolicy reads certain ResourceData keys and returns a DVSSecurityPolicy .


func flattenDVSSecurityPolicy(d *schema.ResourceData, obj *types.DVSSecurityPolicy) error {
	if obj == nil {
		return nil
	}

	structure.SetBoolPolicy(d, "allow_promiscuous", obj.AllowPromiscuous)
	structure.SetBoolPolicy(d, "allow_mac_changes", obj.MacChanges)
	structure.SetBoolPolicy(d, "allow_forged_transmits", obj.ForgedTransmits)
	return nil
}

func flattenDVSSecurityPolicy ( d * schema . ResourceData , obj * types . DVSSecurityPolicy ) error { if obj == nil { return nil } structure . SetBoolPolicy ( d , " " , obj . AllowPromiscuous ) structure . SetBoolPolicy ( d , " " , obj . MacChanges ) structure . SetBoolPolicy ( d , " " , obj . ForgedTransmits ) return nil }

// flattenDVSSecurityPolicy reads various fields from a
// DVSSecurityPolicy into the passed in ResourceData.

flattenDVSSecurityPolicy reads various fields from a DVSSecurityPolicy into the passed in ResourceData .


func expandVMwareUplinkLacpPolicy(d *schema.ResourceData) *types.VMwareUplinkLacpPolicy {
	obj := &types.VMwareUplinkLacpPolicy{
		Enable: structure.GetBoolPolicy(d, "lacp_enabled"),
		Mode:   structure.GetStringPolicy(d, "lacp_mode"),
	}

	if structure.AllFieldsEmpty(obj) {
		return nil
	}
	return obj
}

func expandVMwareUplinkLacpPolicy ( d * schema . ResourceData ) * types . VMwareUplinkLacpPolicy { obj := & types . VMwareUplinkLacpPolicy { Enable : structure . GetBoolPolicy ( d , " " ) , Mode : structure . GetStringPolicy ( d , " " ) , } if structure . AllFieldsEmpty ( obj ) { return nil } return obj }

// expandVMwareUplinkLacpPolicy reads certain ResourceData keys and
// returns a VMwareUplinkLacpPolicy.

expandVMwareUplinkLacpPolicy reads certain ResourceData keys and returns a VMwareUplinkLacpPolicy .


func flattenVMwareUplinkLacpPolicy(d *schema.ResourceData, obj *types.VMwareUplinkLacpPolicy) error {
	if obj == nil {
		return nil
	}

	structure.SetBoolPolicy(d, "lacp_enabled", obj.Enable)
	structure.SetStringPolicy(d, "lacp_mode", obj.Mode)
	return nil
}

func flattenVMwareUplinkLacpPolicy ( d * schema . ResourceData , obj * types . VMwareUplinkLacpPolicy ) error { if obj == nil { return nil } structure . SetBoolPolicy ( d , " " , obj . Enable ) structure . SetStringPolicy ( d , " " , obj . Mode ) return nil }

// flattenVMwareUplinkLacpPolicy reads various fields from a
// VMwareUplinkLacpPolicy into the passed in ResourceData.

flattenVMwareUplinkLacpPolicy reads various fields from a VMwareUplinkLacpPolicy into the passed in ResourceData .


func expandDVSTrafficShapingPolicyIngress(d *schema.ResourceData) *types.DVSTrafficShapingPolicy {
	obj := &types.DVSTrafficShapingPolicy{
		Enabled:          structure.GetBoolPolicy(d, "ingress_shaping_enabled"),
		AverageBandwidth: structure.GetLongPolicy(d, "ingress_shaping_average_bandwidth"),
		PeakBandwidth:    structure.GetLongPolicy(d, "ingress_shaping_peak_bandwidth"),
		BurstSize:        structure.GetLongPolicy(d, "ingress_shaping_burst_size"),
	}

	if structure.AllFieldsEmpty(obj) {
		return nil
	}
	return obj
}

func expandDVSTrafficShapingPolicyIngress ( d * schema . ResourceData ) * types . DVSTrafficShapingPolicy { obj := & types . DVSTrafficShapingPolicy { Enabled : structure . GetBoolPolicy ( d , " " ) , AverageBandwidth : structure . GetLongPolicy ( d , " " ) , PeakBandwidth : structure . GetLongPolicy ( d , " " ) , BurstSize : structure . GetLongPolicy ( d , " " ) , } if structure . AllFieldsEmpty ( obj ) { return nil } return obj }

// expandDVSTrafficShapingPolicyIngress reads certain ResourceData keys and
// returns a DVSTrafficShapingPolicy for ingress traffic.

expandDVSTrafficShapingPolicyIngress reads certain ResourceData keys and returns a DVSTrafficShapingPolicy for ingress traffic .


func flattenDVSTrafficShapingPolicyIngress(d *schema.ResourceData, obj *types.DVSTrafficShapingPolicy) error {
	if obj == nil {
		return nil
	}

	structure.SetBoolPolicy(d, "ingress_shaping_enabled", obj.Enabled)
	structure.SetLongPolicy(d, "ingress_shaping_average_bandwidth", obj.AverageBandwidth)
	structure.SetLongPolicy(d, "ingress_shaping_peak_bandwidth", obj.PeakBandwidth)
	structure.SetLongPolicy(d, "ingress_shaping_burst_size", obj.BurstSize)

	return nil
}

func flattenDVSTrafficShapingPolicyIngress ( d * schema . ResourceData , obj * types . DVSTrafficShapingPolicy ) error { if obj == nil { return nil } structure . SetBoolPolicy ( d , " " , obj . Enabled ) structure . SetLongPolicy ( d , " " , obj . AverageBandwidth ) structure . SetLongPolicy ( d , " " , obj . PeakBandwidth ) structure . SetLongPolicy ( d , " " , obj . BurstSize ) return nil }

// flattenDVSTrafficShapingPolicyIngress reads various fields from the
// DVSTrafficShapingPolicy ingress policy into the passed in ResourceData.

flattenDVSTrafficShapingPolicyIngress reads various fields from the DVSTrafficShapingPolicy ingress policy into the passed in ResourceData .


func expandVMwareDVSPortSetting(d *schema.ResourceData) *types.VMwareDVSPortSetting {
	obj := &types.VMwareDVSPortSetting{
		DVPortSetting: types.DVPortSetting{
			Blocked:                 structure.GetBoolPolicy(d, "block_all_ports"),
			InShapingPolicy:         expandDVSTrafficShapingPolicyIngress(d),
			OutShapingPolicy:        expandDVSTrafficShapingPolicyEgress(d),
			VmDirectPathGen2Allowed: structure.GetBoolPolicy(d, "directpath_gen2_allowed"),
		},
		Vlan:                expandBaseVmwareDistributedVirtualSwitchVlanSpec(d),
		UplinkTeamingPolicy: expandVmwareUplinkPortTeamingPolicy(d),
		SecurityPolicy:      expandDVSSecurityPolicy(d),
		IpfixEnabled:        structure.GetBoolPolicy(d, "netflow_enabled"),
		TxUplink:            structure.GetBoolPolicy(d, "tx_uplink"),
		LacpPolicy:          expandVMwareUplinkLacpPolicy(d),
	}

	if structure.AllFieldsEmpty(obj) {
		return nil
	}
	return obj
}

// expandVMwareDVSPortSetting reads certain ResourceData keys and
// returns a VMwareDVSPortSetting.

expandVMwareDVSPortSetting reads certain ResourceData keys and returns a VMwareDVSPortSetting .


func flattenVMwareDVSPortSetting(d *schema.ResourceData, obj *types.VMwareDVSPortSetting) error {
	if obj == nil {
		return nil
	}

	structure.SetBoolPolicy(d, "block_all_ports", obj.Blocked)
	structure.SetBoolPolicy(d, "netflow_enabled", obj.IpfixEnabled)
	structure.SetBoolPolicy(d, "tx_uplink", obj.TxUplink)
	structure.SetBoolPolicy(d, "directpath_gen2_allowed", obj.VmDirectPathGen2Allowed)

	if err := flattenDVSTrafficShapingPolicyIngress(d, obj.InShapingPolicy); err != nil {
		return err
	}
	if err := flattenDVSTrafficShapingPolicyEgress(d, obj.OutShapingPolicy); err != nil {
		return err
	}
	if err := flattenBaseVmwareDistributedVirtualSwitchVlanSpec(d, obj.Vlan); err != nil {
		return err
	}
	if err := flattenVmwareUplinkPortTeamingPolicy(d, obj.UplinkTeamingPolicy); err != nil {
		return err
	}
	if err := flattenDVSSecurityPolicy(d, obj.SecurityPolicy); err != nil {
		return err
	}
	if err := flattenVMwareUplinkLacpPolicy(d, obj.LacpPolicy); err != nil {
		return err
	}
	return nil
}

// flattenVMwareDVSPortSetting reads various fields from a
// VMwareDVSPortSetting into the passed in ResourceData.

flattenVMwareDVSPortSetting reads various fields from a VMwareDVSPortSetting into the passed in ResourceData .


func expandClusterDrsVMConfigInfo(d *schema.ResourceData, vm *object.VirtualMachine) (*types.ClusterDrsVmConfigInfo, error) {
	obj := &types.ClusterDrsVmConfigInfo{
		Behavior: types.DrsBehavior(d.Get("drs_automation_level").(string)),
		Enabled:  structure.GetBool(d, "drs_enabled"),
		Key:      vm.Reference(),
	}

	return obj, nil
}

func expandClusterDrsVMConfigInfo ( d * schema . ResourceData , vm * object . VirtualMachine ) ( * types . ClusterDrsVmConfigInfo , error ) { obj := & types . ClusterDrsVmConfigInfo { Behavior : types . DrsBehavior ( d . Get ( " " ) . ( string ) ) , Enabled : structure . GetBool ( d , " " ) , Key : vm . Reference ( ) , } return obj , nil }

// expandClusterDrsVMConfigInfo reads certain ResourceData keys and returns a
// ClusterDrsVmConfigInfo.

expandClusterDrsVMConfigInfo reads certain ResourceData keys and returns a ClusterDrsVmConfigInfo .


func flattenClusterDrsVMConfigInfo(d *schema.ResourceData, obj *types.ClusterDrsVmConfigInfo) error {
	return structure.SetBatch(d, map[string]interface{}{
		"drs_automation_level": obj.Behavior,
		"drs_enabled":          obj.Enabled,
	})
}

func flattenClusterDrsVMConfigInfo ( d * schema . ResourceData , obj * types . ClusterDrsVmConfigInfo ) error { return structure . SetBatch ( d , map [ string ] interface { } { " " : obj . Behavior , " " : obj . Enabled , } ) }

// flattenClusterDrsVmConfigInfo saves a ClusterDrsVmConfigInfo into the
// supplied ResourceData.

flattenClusterDrsVmConfigInfo saves a ClusterDrsVmConfigInfo into the supplied ResourceData .


func resourceVSphereDRSVMOverrideParseID(id string) (string, string, error) {
	parts := strings.SplitN(id, ":", 3)
	if len(parts) < 2 {
		return "", "", fmt.Errorf("bad ID %q", id)
	}
	return parts[0], parts[1], nil
}

func resourceVSphereDRSVMOverrideParseID ( id string ) ( string , string , error ) { parts := strings . SplitN ( id , " " , 3 ) if len ( parts ) < 2 { return " " , " " , fmt . Errorf ( " " , id ) } return parts [ 0 ] , parts [ 1 ] , nil }

// resourceVSphereDRSVMOverrideParseID parses an ID for the
// vsphere_drs_vm_override and outputs its parts.

resourceVSphereDRSVMOverrideParseID parses an ID for the vsphere_drs_vm_override and outputs its parts .


func resourceVSphereDRSVMOverrideFindEntry(
	cluster *object.ClusterComputeResource,
	vm *object.VirtualMachine,
) (*types.ClusterDrsVmConfigInfo, error) {
	props, err := clustercomputeresource.Properties(cluster)
	if err != nil {
		return nil, fmt.Errorf("error fetching cluster properties: %s", err)
	}

	for _, info := range props.ConfigurationEx.(*types.ClusterConfigInfoEx).DrsVmConfig {
		if info.Key == vm.Reference() {
			log.Printf("[DEBUG] Found DRS config info for VM %q in cluster %q", vm.Name(), cluster.Name())
			return &info, nil
		}
	}

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

func resourceVSphereDRSVMOverrideFindEntry ( cluster * object . ClusterComputeResource , vm * object . VirtualMachine , ) ( * types . ClusterDrsVmConfigInfo , error ) { props , err := clustercomputeresource . Properties ( cluster ) if err != nil { return nil , fmt . Errorf ( " " , err ) } for _ , info := range props . ConfigurationEx . ( * types . ClusterConfigInfoEx ) . DrsVmConfig { if info . Key == vm . Reference ( ) { log . Printf ( " " , vm . Name ( ) , cluster . Name ( ) ) return & info , nil } } log . Printf ( " " , vm . Name ( ) , cluster . Name ( ) ) return nil , nil }

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

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


func resourceVSphereComputeClusterVMAntiAffinityRuleFlattenID(cluster *object.ClusterComputeResource, key int32) (string, error) {
	clusterID := cluster.Reference().Value
	return strings.Join([]string{clusterID, strconv.Itoa(int(key))}, ":"), nil
}

// resourceVSphereComputeClusterVMAntiAffinityRuleFlattenID makes an ID for the
// vsphere_compute_cluster_vm_anti_affinity_rule resource.


func schemaDatastoreSummary() map[string]*schema.Schema {
	return map[string]*schema.Schema{
		// Note that the following fields are not represented in the schema here:
		// * Name (more than likely the ID attribute and will be represented in
		// resource schema)
		// * Type (redundant attribute as the datastore type will be represented by
		// the resource)
		"accessible": {
			Type:        schema.TypeBool,
			Description: "The connectivity status of the datastore. If this is false, some other computed attributes may be out of date.",
			Computed:    true,
		},
		"capacity": {
			Type:        schema.TypeInt,
			Description: "Maximum capacity of the datastore, in MB.",
			Computed:    true,
		},
		"free_space": {
			Type:        schema.TypeInt,
			Description: "Available space of this datastore, in MB.",
			Computed:    true,
		},
		"maintenance_mode": {
			Type:        schema.TypeString,
			Description: "The current maintenance mode state of the datastore.",
			Computed:    true,
		},
		"multiple_host_access": {
			Type:        schema.TypeBool,
			Description: "If true, more than one host in the datacenter has been configured with access to the datastore.",
			Computed:    true,
		},
		"uncommitted_space": {
			Type:        schema.TypeInt,
			Description: "Total additional storage space, in MB, potentially used by all virtual machines on this datastore.",
			Computed:    true,
		},
		"url": {
			Type:        schema.TypeString,
			Description: "The unique locator for the datastore.",
			Computed:    true,
		},
	}
}

// schemaDatastoreSummary returns schema items for resources that
// need to work with a DatastoreSummary.

schemaDatastoreSummary returns schema items for resources that need to work with a DatastoreSummary .


func flattenDatastoreSummary(d *schema.ResourceData, obj *types.DatastoreSummary) error {
	d.Set("accessible", obj.Accessible)
	d.Set("capacity", structure.ByteToMB(obj.Capacity))
	d.Set("free_space", structure.ByteToMB(obj.FreeSpace))
	d.Set("maintenance_mode", obj.MaintenanceMode)
	d.Set("multiple_host_access", obj.MultipleHostAccess)
	d.Set("uncommitted_space", structure.ByteToMB(obj.Uncommitted))
	d.Set("url", obj.Url)

	// Set the name attribute off of the name here - since we do not track this
	// here we check for errors
	if err := d.Set("name", obj.Name); err != nil {
		return err
	}
	return nil
}

// flattenDatastoreSummary reads various fields from a DatastoreSummary into
// the passed in ResourceData.

flattenDatastoreSummary reads various fields from a DatastoreSummary into the passed in ResourceData .


func resourceVSphereDatastoreApplyFolderOrStorageClusterPath(d *schema.ResourceData, meta interface{}) (string, error) {
	var path string
	fvalue, fok := d.GetOk("folder")
	cvalue, cok := d.GetOk("datastore_cluster_id")
	switch {
	case fok:
		path = fvalue.(string)
	case cok:
		return resourceVSphereDatastoreStorageClusterPathNormalized(meta, cvalue.(string))
	}
	return path, nil
}

// resourceVSphereDatastoreApplyFolderOrStorageClusterPath returns a path to a
// folder or a datastore cluster, depending on what has been selected in the
// resource.


func resourceVSphereDatastoreReadFolderOrStorageClusterPath(d *schema.ResourceData, ds *object.Datastore) error {
	props, err := datastore.Properties(ds)
	if err != nil {
		return fmt.Errorf("error fetching datastore properties while parsing path: %s", err)
	}
	switch props.Parent.Type {
	case "Folder":
		return resourceVSphereDatastoreReadFolderOrStorageClusterPathAsFolder(d, ds)
	case "StoragePod":
		return resourceVSphereDatastoreReadFolderOrStorageClusterPathSetAttributes(d, "", props.Parent.Value)
	}
	return fmt.Errorf("unknown datastore parent type %q while parsing inventory path", props.Parent.Type)
}

// resourceVSphereDatastoreReadFolderOrStorageClusterPath checks the inventory
// path of the supplied datastore and checks to see if it is a normal folder or
// if it's a datastore cluster, and saves the attributes accordingly.


func CdromSubresourceSchema() map[string]*schema.Schema {
	s := map[string]*schema.Schema{
		// VirtualDeviceFileBackingInfo
		"datastore_id": {
			Type:        schema.TypeString,
			Optional:    true,
			Description: "The datastore ID the ISO is located on.",
		},
		"path": {
			Type:        schema.TypeString,
			Optional:    true,
			Description: "The path to the ISO file on the datastore.",
		},
		// VirtualCdromRemoteAtapiBackingInfo
		"client_device": {
			Type:        schema.TypeBool,
			Optional:    true,
			Description: "Indicates whether the device should be mapped to a remote client device",
		},
	}
	structure.MergeSchema(s, subresourceSchema())
	return s
}

func
CdromSubresourceSchema
(
)
map
[
string
]
*
schema
.
Schema
{
s
:=
map
[
string
]
*
schema
.
Schema
{
// VirtualDeviceFileBackingInfo
"
"
:
{
Type
:
schema
.
TypeString
,
Optional
:
true
,
Description
:
"
"
,
}
,
"
"
:
{
Type
:
schema
.
TypeString
,
Optional
:
true
,
Description
:
"
"
,
}
,
// VirtualCdromRemoteAtapiBackingInfo
"
"
:
{
Type
:
schema
.
TypeBool
,
Optional
:
true
,
Description
:
"
"
,
}
,
}
structure
.
MergeSchema
(
s
,
subresourceSchema
(
)
)
return
s
}

// CdromSubresourceSchema represents the schema for the cdrom sub-resource.

CdromSubresourceSchema represents the schema for the cdrom sub - resource .


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

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

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

NewCdromSubresource returns a subresource populated with all of the necessary fields .


func CdromDiffOperation(d *schema.ResourceDiff, c *govmomi.Client) error {
	log.Printf("[DEBUG] CdromDiffOperation: Beginning diff validation")
	cr := d.Get(subresourceTypeCdrom)
	for ci, ce := range cr.([]interface{}) {
		cm := ce.(map[string]interface{})
		r := NewCdromSubresource(c, d, cm, nil, ci)
		if err := r.ValidateDiff(); err != nil {
			return fmt.Errorf("%s: %s", r.Addr(), err)
		}
	}
	log.Printf("[DEBUG] CdromDiffOperation: Diff validation complete")
	return nil
}

func CdromDiffOperation ( d * schema . ResourceDiff , c * govmomi . Client ) error { log . Printf ( " " ) cr := d . Get ( subresourceTypeCdrom ) for ci , ce := range cr . ( [ ] interface { } ) { cm := ce . ( map [ string ] interface { } ) r := NewCdromSubresource ( c , d , cm , nil , ci ) if err := r . ValidateDiff ( ) ; err != nil { return fmt . Errorf ( " " , r . Addr ( ) , err ) } } log . Printf ( " " ) return nil }

// CdromDiffOperation performs operations relevant to managing the
// diff on cdrom sub-resources

CdromDiffOperation performs operations relevant to managing the diff on cdrom sub - resources


func (r *CdromSubresource) ValidateDiff() error {
	log.Printf("[DEBUG] %s: Beginning CDROM configuration validation", r)
	dsID := r.Get("datastore_id").(string)
	path := r.Get("path").(string)
	clientDevice := r.Get("client_device").(bool)
	switch {
	case clientDevice && (dsID != "" || path != ""):
		return fmt.Errorf("Cannot have both client_device parameter and ISO file parameters (datastore_id, path) set")
	case !clientDevice && (dsID == "" || path == ""):
		return fmt.Errorf("Either client_device or datastore_id and path must be set")
	}
	log.Printf("[DEBUG] %s: Config validation complete", r)
	return nil
}

func ( r * CdromSubresource ) ValidateDiff ( ) error { log . Printf ( " " , r ) dsID := r . Get ( " " ) . ( string ) path := r . Get ( " " ) . ( string ) clientDevice := r . Get ( " " ) . ( bool ) switch { case clientDevice && ( dsID != " " || path != " " ) : return fmt . Errorf ( " " ) case ! clientDevice && ( dsID == " " || path == " " ) : return fmt . Errorf ( " " ) } log . Printf ( " " , r ) return nil }

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

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


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

	// We now have the controller on which we can create our device on.
	device, err := l.CreateCdrom(ctlr.(*types.VirtualIDEController))
	if err != nil {
		return nil, err
	}
	// Map the CDROM to the correct device
	r.mapCdrom(device, l)
	// Done here. Save IDs, 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 cdrom sub-resource.

Create creates a vsphere_virtual_machine cdrom sub - resource .


func (r *CdromSubresource) Read(l object.VirtualDeviceList) error {
	log.Printf("[DEBUG] %s: Reading state", r)
	d, err := r.FindVirtualDevice(l)
	if err != nil {
		return fmt.Errorf("cannot find disk device: %s", err)
	}
	device, ok := d.(*types.VirtualCdrom)
	if !ok {
		return fmt.Errorf("device at %q is not a virtual CDROM device", l.Name(d))
	}
	// Only read backing info if it's available.
	switch backing := device.Backing.(type) {
	case *types.VirtualCdromRemoteAtapiBackingInfo:
		r.Set("client_device", true)
	case *types.VirtualCdromIsoBackingInfo:
		dp := &object.DatastorePath{}
		if ok := dp.FromString(backing.FileName); !ok {
			return fmt.Errorf("could not read datastore path in backing %q", backing.FileName)
		}
		// If a vApp ISO was inserted, it will be removed if the VM is powered off
		// and cause backing.Datastore to be nil.
		if backing.Datastore != nil {
			r.Set("datastore_id", backing.Datastore.Value)
		}
		r.Set("path", dp.Path)
	default:
		// This is an unsupported entry, so we clear all attributes in the
		// subresource (except for the device address and key, of course).  In
		// addition to making sure correct diffs get created for these kinds of
		// devices, this ensures we don't fail on CDROM device types we don't
		// support right now, such as passthrough devices. We might support these
		// later.
		log.Printf("%s: [DEBUG] Unknown CDROM type %T, clearing all attributes", r, backing)
		r.Set("datastore_id", "")
		r.Set("path", "")
		r.Set("client_device", false)
	}
	// Save the device key and address data
	ctlr, err := findControllerForDevice(l, d)
	if err != nil {
		return err
	}
	if err := r.SaveDevIDs(d, 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 cdrom sub-resource.

Read reads a vsphere_virtual_machine cdrom sub - resource .


func (r *CdromSubresource) Update(l object.VirtualDeviceList) ([]types.BaseVirtualDeviceConfigSpec, error) {
	log.Printf("[DEBUG] %s: Beginning update", r)
	d, err := r.FindVirtualDevice(l)
	if err != nil {
		return nil, fmt.Errorf("cannot find disk device: %s", err)
	}
	device, ok := d.(*types.VirtualCdrom)
	if !ok {
		return nil, fmt.Errorf("device at %q is not a virtual CDROM device", l.Name(d))
	}

	// Map the CDROM to the correct device
	r.mapCdrom(device, l)
	spec, err := object.VirtualDeviceList{device}.ConfigSpec(types.VirtualDeviceConfigSpecOperationEdit)
	if err != nil {
		return nil, err
	}
	log.Printf("[DEBUG] %s: Device config operations from update: %s", r, DeviceChangeString(spec))
	log.Printf("[DEBUG] %s: Update complete", r)
	return spec, nil
}

func
(
r
*
CdromSubresource
)
Update
(
l
object
.
VirtualDeviceList
)
(
[
]
types
.
BaseVirtualDeviceConfigSpec
,
error
)
{
log
.
Printf
(
"
"
,
r
)
d
,
err
:=
r
.
FindVirtualDevice
(
l
)
if
err
!=
{
return
,
fmt
.
Errorf
(
"
"
,
err
)
}
device
,
ok
:=
d
.
(
*
types
.
VirtualCdrom
)
if
!
ok
{
return
,
fmt
.
Errorf
(
"
"
,
l
.
Name
(
d
)
)
}
// Map the CDROM to the correct device
r
.
mapCdrom
(
device
,
l
)
spec
,
err
:=
object
.
VirtualDeviceList
{
device
}
.
ConfigSpec
(
types
.
VirtualDeviceConfigSpecOperationEdit
)
if
err
!=
{
return
,
err
}
log
.
Printf
(
"
"
,
r
,
DeviceChangeString
(
spec
)
)
log
.
Printf
(
"
"
,
r
)
return
spec
,
}

// Update updates a vsphere_virtual_machine cdrom sub-resource.

Update updates a vsphere_virtual_machine cdrom sub - resource .


func (r *CdromSubresource) Delete(l object.VirtualDeviceList) ([]types.BaseVirtualDeviceConfigSpec, error) {
	log.Printf("[DEBUG] %s: Beginning delete", r)
	d, err := r.FindVirtualDevice(l)
	if err != nil {
		return nil, fmt.Errorf("cannot find disk device: %s", err)
	}
	device, ok := d.(*types.VirtualCdrom)
	if !ok {
		return nil, fmt.Errorf("device at %q is not a virtual CDROM device", l.Name(d))
	}
	deleteSpec, err := object.VirtualDeviceList{device}.ConfigSpec(types.VirtualDeviceConfigSpecOperationRemove)
	if err != nil {
		return nil, err
	}
	log.Printf("[DEBUG] %s: Device config operations from update: %s", r, DeviceChangeString(deleteSpec))
	log.Printf("[DEBUG] %s: Delete completed", r)
	return deleteSpec, nil
}

func ( r * CdromSubresource ) Delete ( l object . VirtualDeviceList ) ( [ ] types . BaseVirtualDeviceConfigSpec , error ) { log . Printf ( " " , r ) d , err := r . FindVirtualDevice ( l ) if err != nil { return nil , fmt . Errorf ( " " , err ) } device , ok := d . ( * types . VirtualCdrom ) if ! ok { return nil , fmt . Errorf ( " " , l . Name ( d ) ) } deleteSpec , err := object . VirtualDeviceList { device } . ConfigSpec ( types . VirtualDeviceConfigSpecOperationRemove ) if err != nil { return nil , err } log . Printf ( " " , r , DeviceChangeString ( deleteSpec ) ) log . Printf ( " " , r ) return deleteSpec , nil }

// Delete deletes a vsphere_virtual_machine cdrom sub-resource.

Delete deletes a vsphere_virtual_machine cdrom sub - resource .


func (r *CdromSubresource) mapCdrom(device *types.VirtualCdrom, l object.VirtualDeviceList) error {
	dsID := r.Get("datastore_id").(string)
	path := r.Get("path").(string)
	clientDevice := r.Get("client_device").(bool)
	switch {
	case dsID != "" && path != "":
		// If the datastore ID and path are both set, the CDROM will be mapped to a file on a datastore.
		ds, err := datastore.FromID(r.client, dsID)
		if err != nil {
			return fmt.Errorf("cannot find datastore: %s", err)
		}
		dsProps, err := datastore.Properties(ds)
		if err != nil {
			return fmt.Errorf("could not get properties for datastore: %s", err)
		}
		dsName := dsProps.Name
		dsPath := &object.DatastorePath{
			Datastore: dsName,
			Path:      path,
		}
		device = l.InsertIso(device, dsPath.String())
		l.Connect(device)
		return nil
	case clientDevice == true:
		// If set to use the client device, then the CDROM will be mapped to a remote device.
		device.Backing = &types.VirtualCdromRemoteAtapiBackingInfo{
			VirtualDeviceRemoteDeviceBackingInfo: types.VirtualDeviceRemoteDeviceBackingInfo{},
		}
		return nil
	}
	panic(fmt.Sprintf("%s: no CDROM types specified", r))
}

// mapCdrom takes a CdromSubresource and attaches either a client device or a datastore ISO.

mapCdrom takes a CdromSubresource and attaches either a client device or a datastore ISO .


func VerifyVAppTransport(d *schema.ResourceDiff, c *govmomi.Client) error {
	log.Printf("[DEBUG] VAppDiffOperation: Verifying configuration meets requirements for vApp transport")
	// Check if there is a client CDROM device configured.
	cl := d.Get("cdrom")
	for _, c := range cl.([]interface{}) {
		if c.(map[string]interface{})["client_device"].(bool) == true {
			// There is a device configured that can support vApp ISO transport if needed
			log.Printf("[DEBUG] VAppDiffOperation: Client CDROM device exists which can support ISO transport")
			return nil
		}
	}
	// Iterate over each transport and see if ISO transport is supported.
	tm := d.Get("vapp_transport").([]interface{})
	for _, m := range tm {
		if m.(string) == vAppTransportIso && len(tm) == 1 {
			return fmt.Errorf("this virtual machine requires a client CDROM device to deliver vApp properties")
		}
	}
	log.Printf("[DEBUG] VAppDiffOperation: ISO transport is not supported on this virtual machine or multiple transport options exist")
	return nil
}

// VerifyVAppTransport validates that all the required components are included in
// the virtual machine configuration if vApp properties are set.

VerifyVAppTransport validates that all the required components are included in the virtual machine configuration if vApp properties are set .


func verifyVAppCdromIso(d *schema.ResourceData, device *types.VirtualCdrom, l object.VirtualDeviceList, c *govmomi.Client) (bool, error) {
	log.Printf("[DEBUG] IsVAppCdrom: Checking if CDROM is using a vApp ISO")
	// If the CDROM is using VirtualCdromIsoBackingInfo and matches the ISO
	// naming pattern, it has been used as a vApp CDROM, and we can move on to
	// checking if the parent VM supports ISO transport.
	if backing, ok := device.Backing.(*types.VirtualCdromIsoBackingInfo); ok {
		dp := &object.DatastorePath{}
		if ok := dp.FromString(backing.FileName); !ok {
			// If the ISO path can not be read, we can't tell if a vApp ISO is
			// connected.
			log.Printf("[DEBUG] IsVAppCdrom: Cannot read ISO path, cannot determine if CDROM is used for vApp")
			return false, nil
		}
		// The pattern used for vApp ISO naming is
		// "<vmname>/_ovfenv-<vmname>.iso"
		re := regexp.MustCompile(".*/_ovfenv-.*.iso")
		if !re.MatchString(dp.Path) {
			log.Printf("[DEBUG] IsVAppCdrom: ISO is name does not match vApp ISO naming pattern (<vmname>/_ovfenv-<vmname>.iso): %s", dp.Path)
			return false, nil
		}
	} else {
		// vApp CDROMs must be backed by an ISO.
		log.Printf("[DEBUG] IsVAppCdrom: CDROM is not backed by an ISO")
		return false, nil
	}
	log.Printf("[DEBUG] IsVAppCdrom: CDROM has a vApp ISO inserted")
	// Set the vApp transport methods
	tm := d.Get("vapp_transport").([]interface{})
	for _, t := range tm {
		if t.(string) == "iso" {
			log.Printf("[DEBUG] IsVAppCdrom: vApp ISO transport is supported")
			return true, nil
		}
	}
	log.Printf("[DEBUG] IsVAppCdrom: vApp ISO transport is not required")
	return false, nil
}

// verifyVAppCdromIso takes VirtualCdrom and determines if it is needed for
// vApp ISO transport. It does this by first checking if it has an ISO inserted
// that matches the vApp ISO naming pattern. If it does, then the next step is
// to see if vApp ISO transport is supported on the VM. If both of those
// conditions are met, then the CDROM is considered in use for vApp transport.

verifyVAppCdromIso takes VirtualCdrom and determines if it is needed for vApp ISO transport . It does this by first checking if it has an ISO inserted that matches the vApp ISO naming pattern . If it does then the next step is to see if vApp ISO transport is supported on the VM . If both of those conditions are met then the CDROM is considered in use for vApp transport .


func DatastorePathFromString(p string) (*object.DatastorePath, bool) {
	dp := new(object.DatastorePath)
	success := dp.FromString(p)
	log.Printf("[DEBUG] DatastorePathFromString: success: %t, path: %q", success, p)
	return dp, success
}

func DatastorePathFromString ( p string ) ( * object . DatastorePath , bool ) { dp := new ( object . DatastorePath ) success := dp . FromString ( p ) log . Printf ( " " , success , p ) return dp , success }

// DatastorePathFromString is a convenience method that returns a
// fully-populated DatastorePath from a string containing a datastore path. A
// flag indicating a successful parsing is also returned.

DatastorePathFromString is a convenience method that returns a fully - populated DatastorePath from a string containing a datastore path . A flag indicating a successful parsing is also returned .


func IsVmdkDatastorePath(p string) bool {
	dp, success := DatastorePathFromString(p)
	if !success {
		log.Printf("[DEBUG] IsVmdkDatastorePath: %q is not a datastore path", p)
		return false
	}
	isVMDK := dp.IsVMDK()
	log.Printf("[DEBUG] IsVmdkDatastorePath: %q %s a datastore path", p, structure.LogCond(isVMDK, "is", "is not"))
	return isVMDK
}

func IsVmdkDatastorePath ( p string ) bool { dp , success := DatastorePathFromString ( p ) if ! success { log . Printf ( " " , p ) return false } isVMDK := dp . IsVMDK ( ) log . Printf ( " " , p , structure . LogCond ( isVMDK , " " , " " ) ) return isVMDK }

// IsVmdkDatastorePath ensures that a string can be parsed as a datastore path
// pointing to a virtual disk. This only checks the validity of the path, not
// whether or not the file exists.

IsVmdkDatastorePath ensures that a string can be parsed as a datastore path pointing to a virtual disk . This only checks the validity of the path not whether or not the file exists .


func QueryDiskType(client *govmomi.Client, name string, dc *object.Datacenter) (types.VirtualDiskType, error) {
	vdm := object.NewVirtualDiskManager(client.Client)
	ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
	defer cancel()
	di, err := vdm.QueryVirtualDiskInfo(ctx, name, dc, false)
	if err != nil {
		return types.VirtualDiskType(""), err
	}
	t := di[0].DiskType
	log.Printf("[DEBUG] QueryDiskType: Disk %q is of type %q", name, t)
	return types.VirtualDiskType(t), nil
}

func QueryDiskType ( client * govmomi . Client , name string , dc * object . Datacenter ) ( types . VirtualDiskType , error ) { vdm := object . NewVirtualDiskManager ( client . Client ) ctx , cancel := context . WithTimeout ( context . Background ( ) , provider . DefaultAPITimeout ) defer cancel ( ) di , err := vdm . QueryVirtualDiskInfo ( ctx , name , dc , false ) if err != nil { return types . VirtualDiskType ( " " ) , err } t := di [ 0 ] . DiskType log . Printf ( " " , name , t ) return types . VirtualDiskType ( t ) , nil }

// QueryDiskType queries the disk type of the specified virtual disk.

QueryDiskType queries the disk type of the specified virtual disk .


func Delete(client *govmomi.Client, name string, dc *object.Datacenter) error {
	if dc == nil {
		return fmt.Errorf("datacenter cannot be nil")
	}
	log.Printf("[DEBUG] Deleting virtual disk %q in datacenter %s", name, dc)
	vdm := object.NewVirtualDiskManager(client.Client)
	ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
	defer cancel()
	task, err := vdm.DeleteVirtualDisk(ctx, name, dc)
	if err != nil {
		return err
	}
	tctx, tcancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
	defer tcancel()
	if err := task.Wait(tctx); err != nil {
		return err
	}
	log.Printf("[DEBUG] Virtual disk %q in datacenter %s deleted succesfully", name, dc)
	return nil
}

func Delete ( client * govmomi . Client , name string , dc * object . Datacenter ) error { if dc == nil { return fmt . Errorf ( " " ) } log . Printf ( " " , name , dc ) vdm := object . NewVirtualDiskManager ( client . Client ) ctx , cancel := context . WithTimeout ( context . Background ( ) , provider . DefaultAPITimeout ) defer cancel ( ) task , err := vdm . DeleteVirtualDisk ( ctx , name , dc ) if err != nil { return err } tctx , tcancel := context . WithTimeout ( context . Background ( ) , provider . DefaultAPITimeout ) defer tcancel ( ) if err := task . Wait ( tctx ) ; err != nil { return err } log . Printf ( " " , name , dc ) return nil }

// Delete deletes the virtual disk at the specified datastore path.

Delete deletes the virtual disk at the specified datastore path .


func soapFault(err error) (*soap.Fault, bool) {
	if soap.IsSoapFault(err) {
		return soap.ToSoapFault(err), true
	}
	return nil, false
}

func soapFault ( err error ) ( * soap . Fault , bool ) { if soap . IsSoapFault ( err ) { return soap . ToSoapFault ( err ) , true } return nil , false }

// soapFault extracts the SOAP fault from an error fault, if it exists. Check
// the returned boolean value to see if you have a SoapFault.

soapFault extracts the SOAP fault from an error fault if it exists . Check the returned boolean value to see if you have a SoapFault .


func vimSoapFault(err error) (types.AnyType, bool) {
	if sf, ok := soapFault(err); ok {
		return sf.VimFault(), true
	}
	return nil, false
}

func vimSoapFault ( err error ) ( types . AnyType , bool ) { if sf , ok := soapFault ( err ) ; ok { return sf . VimFault ( ) , true } return nil , false }

// vimSoapFault extracts the VIM fault. Check the returned boolean value to see
// if you have a fault, which will need to be further asserted into the error
// that you are looking for.

vimSoapFault extracts the VIM fault . Check the returned boolean value to see if you have a fault which will need to be further asserted into the error that you are looking for .


func taskFault(err error) (types.BaseMethodFault, bool) {
	if te, ok := err.(task.Error); ok {
		return te.Fault(), true
	}
	return nil, false
}

func taskFault ( err error ) ( types . BaseMethodFault , bool ) { if te , ok := err . ( task . Error ) ; ok { return te . Fault ( ) , true } return nil , false }

// taskFault extracts the task fault from a supplied task.Error. Check the
// returned boolean value to see if the fault was extracted correctly, after
// which you will need to do further checking.

taskFault extracts the task fault from a supplied task . Error . Check the returned boolean value to see if the fault was extracted correctly after which you will need to do further checking .


func IsManagedObjectNotFoundError(err error) bool {
	if f, ok := vimSoapFault(err); ok {
		if _, ok := f.(types.ManagedObjectNotFound); ok {
			return true
		}
	}
	return false
}

func IsManagedObjectNotFoundError ( err error ) bool { if f , ok := vimSoapFault ( err ) ; ok { if _ , ok := f . ( types . ManagedObjectNotFound ) ; ok { return true } } return false }

// IsManagedObjectNotFoundError checks an error to see if it's of the
// ManagedObjectNotFound type.

IsManagedObjectNotFoundError checks an error to see if it s of the ManagedObjectNotFound type .


func isNotFoundError(err error) bool {
	if f, ok := vimSoapFault(err); ok {
		if _, ok := f.(types.NotFound); ok {
			return true
		}
	}
	return false
}

func isNotFoundError ( err error ) bool { if f , ok := vimSoapFault ( err ) ; ok { if _ , ok := f . ( types . NotFound ) ; ok { return true } } return false }

// isNotFoundError checks an error to see if it's of the NotFoundError type.
//
// Note this is different from the other "not found" faults and is an error
// type in its own right. Use IsAnyNotFoundError to check for any "not found"
// type.

isNotFoundError checks an error to see if it s of the NotFoundError type . Note this is different from the other not found faults and is an error type in its own right . Use IsAnyNotFoundError to check for any not found type .


func IsAnyNotFoundError(err error) bool {
	switch {
	case IsManagedObjectNotFoundError(err):
		fallthrough
	case isNotFoundError(err):
		return true
	}
	return false
}

func IsAnyNotFoundError ( err error ) bool { switch { case IsManagedObjectNotFoundError ( err ) : fallthrough case isNotFoundError ( err ) : return true } return false }

// IsAnyNotFoundError checks to see if the fault is of any not found error type
// that we track.

IsAnyNotFoundError checks to see if the fault is of any not found error type that we track .


func IsResourceInUseError(err error) bool {
	if f, ok := vimSoapFault(err); ok {
		if _, ok := f.(types.ResourceInUse); ok {
			return true
		}
	}
	return false
}

func IsResourceInUseError ( err error ) bool { if f , ok := vimSoapFault ( err ) ; ok { if _ , ok := f . ( types . ResourceInUse ) ; ok { return true } } return false }

// IsResourceInUseError checks an error to see if it's of the
// ResourceInUse type.

IsResourceInUseError checks an error to see if it s of the ResourceInUse type .


func isConcurrentAccessError(err error) bool {
	// ConcurrentAccess comes from a task more than it usually does from a direct
	// SOAP call, so we need to handle both here.
	var f types.AnyType
	var ok bool
	f, ok = vimSoapFault(err)
	if !ok {
		f, ok = taskFault(err)
	}
	if ok {
		switch f.(type) {
		case types.ConcurrentAccess, *types.ConcurrentAccess:
			return true
		}
	}
	return false
}

// isConcurrentAccessError checks an error to see if it's of the
// ConcurrentAccess type.

isConcurrentAccessError checks an error to see if it s of the ConcurrentAccess type .


func RenameObject(client *govmomi.Client, ref types.ManagedObjectReference, new string) error {
	req := types.Rename_Task{
		This:    ref,
		NewName: new,
	}

	rctx, rcancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
	defer rcancel()
	res, err := methods.Rename_Task(rctx, client.Client, &req)
	if err != nil {
		return err
	}

	t := object.NewTask(client.Client, res.Returnval)
	tctx, tcancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
	defer tcancel()
	return t.Wait(tctx)
}

func RenameObject ( client * govmomi . Client , ref types . ManagedObjectReference , new string ) error { req := types . Rename_Task { This : ref , NewName : new , } rctx , rcancel := context . WithTimeout ( context . Background ( ) , provider . DefaultAPITimeout ) defer rcancel ( ) res , err := methods . Rename_Task ( rctx , client . Client , & req ) if err != nil { return err } t := object . NewTask ( client . Client , res . Returnval ) tctx , tcancel := context . WithTimeout ( context . Background ( ) , provider . DefaultAPITimeout ) defer tcancel ( ) return t . Wait ( tctx ) }

// RenameObject renames a MO and tracks the task to make sure it completes.

RenameObject renames a MO and tracks the task to make sure it completes .


func VimValidateVirtualCenter(c *vim25.Client) error {
	if c.ServiceContent.About.ApiType != "VirtualCenter" {
		return errors.New(ErrVirtualCenterOnly)
	}
	return nil
}

func VimValidateVirtualCenter ( c * vim25 . Client ) error { if c . ServiceContent . About . ApiType != " " { return errors . New ( ErrVirtualCenterOnly ) } return nil }

// VimValidateVirtualCenter ensures that the client is connected to vCenter.
//
// This is a lower-level method that does not take the wrapped client from the
// higher-level govmomi object, and can be used to facilitate validation when
// it's not available.

VimValidateVirtualCenter ensures that the client is connected to vCenter . This is a lower - level method that does not take the wrapped client from the higher - level govmomi object and can be used to facilitate validation when it s not available .


func parseVersion(name, version, build string) (VSphereVersion, error) {
	v := VSphereVersion{
		Product: name,
	}
	s := strings.Split(version, ".")
	if len(s) > 3 {
		return v, fmt.Errorf("version string %q has more than 3 components", version)
	}
	var err error
	v.Major, err = strconv.Atoi(s[0])
	if err != nil {
		return v, fmt.Errorf("could not parse major version %q from version string %q", s[0], version)
	}
	v.Minor, err = strconv.Atoi(s[1])
	if err != nil {
		return v, fmt.Errorf("could not parse minor version %q from version string %q", s[1], version)
	}
	v.Patch, err = strconv.Atoi(s[2])
	if err != nil {
		return v, fmt.Errorf("could not parse patch version %q from version string %q", s[2], version)
	}
	v.Build, err = strconv.Atoi(build)
	if err != nil {
		return v, fmt.Errorf("could not parse build version string %q", build)
	}

	return v, nil
}

func parseVersion ( name , version , build string ) ( VSphereVersion , error ) { v := VSphereVersion { Product : name , } s := strings . Split ( version , " " ) if len ( s ) > 3 { return v , fmt . Errorf ( " " , version ) } var err error v . Major , err = strconv . Atoi ( s [ 0 ] ) if err != nil { return v , fmt . Errorf ( " " , s [ 0 ] , version ) } v . Minor , err = strconv . Atoi ( s [ 1 ] ) if err != nil { return v , fmt . Errorf ( " " , s [ 1 ] , version ) } v . Patch , err = strconv . Atoi ( s [ 2 ] ) if err != nil { return v , fmt . Errorf ( " " , s [ 2 ] , version ) } v . Build , err = strconv . Atoi ( build ) if err != nil { return v , fmt . Errorf ( " " , build ) } return v , nil }

// parseVersion creates a new VSphereVersion from a parsed version string and
// build number.

parseVersion creates a new VSphereVersion from a parsed version string and build number .


func parseVersionFromAboutInfo(info types.AboutInfo) VSphereVersion {
	v, err := parseVersion(info.Name, info.Version, info.Build)
	if err != nil {
		panic(err)
	}
	return v
}

func parseVersionFromAboutInfo ( info types . AboutInfo ) VSphereVersion { v , err := parseVersion ( info . Name , info . Version , info . Build ) if err != nil { panic ( err ) } return v }

// parseVersionFromAboutInfo returns a populated VSphereVersion from an
// AboutInfo data object.
//
// This function panics if it cannot parse the version correctly, as given our
// source of truth is a valid AboutInfo object, such an error is indicative of
// a major issue with our version parsing logic.

parseVersionFromAboutInfo returns a populated VSphereVersion from an AboutInfo data object . This function panics if it cannot parse the version correctly as given our source of truth is a valid AboutInfo object such an error is indicative of a major issue with our version parsing logic .


func ParseVersionFromClient(client *govmomi.Client) VSphereVersion {
	return parseVersionFromAboutInfo(client.Client.ServiceContent.About)
}

func ParseVersionFromClient ( client * govmomi . Client ) VSphereVersion { return parseVersionFromAboutInfo ( client . Client . ServiceContent . About ) }

// ParseVersionFromClient returns a populated VSphereVersion from a client
// connection.

ParseVersionFromClient returns a populated VSphereVersion from a client connection .


func (v VSphereVersion) String() string {
	return fmt.Sprintf("%s %d.%d.%d build-%d", v.Product, v.Major, v.Minor, v.Patch, v.Build)
}

func ( v VSphereVersion ) String ( ) string { return fmt . Sprintf ( " " , v . Product , v . Major , v . Minor , v . Patch , v . Build ) }

// String implements stringer for VSphereVersion.

String implements stringer for VSphereVersion .


func (v VSphereVersion) ProductEqual(other VSphereVersion) bool {
	return v.Product == other.Product
}

func ( v VSphereVersion ) ProductEqual ( other VSphereVersion ) bool { return v . Product == other . Product }

// ProductEqual returns true if this version's product name is the same as the
// supplied version's name.

ProductEqual returns true if this version s product name is the same as the supplied version s name .


func (v VSphereVersion) Older(other VSphereVersion) bool {
	if !v.ProductEqual(other) {
		return false
	}
	if v.olderVersion(other) {
		return true
	}

	// Double check this version is not actually newer by version number before
	// moving on to the build number
	if v.newerVersion(other) {
		return false
	}

	if v.Build < other.Build {
		return true
	}
	return false
}

// Older returns true if this version's product is the same, and composite of
// the version and build numbers, are older than the supplied version's
// information.

Older returns true if this version s product is the same and composite of the version and build numbers are older than the supplied version s information .


func (v VSphereVersion) Equal(other VSphereVersion) bool {
	return v.ProductEqual(other) && !v.Older(other) && !v.Newer(other)
}

func ( v VSphereVersion ) Equal ( other VSphereVersion ) bool { return v . ProductEqual ( other ) && ! v . Older ( other ) && ! v . Newer ( other ) }

// Equal returns true if the version is equal to the supplied version.

Equal returns true if the version is equal to the supplied version .


func expandClusterVMGroup(d *schema.ResourceData, meta interface{}, name string) (*types.ClusterVmGroup, error) {
	client, err := resourceVSphereComputeClusterVMGroupClient(meta)
	if err != nil {
		return nil, err
	}

	results, err := virtualmachine.MOIDsForUUIDs(
		client,
		structure.SliceInterfacesToStrings(d.Get("virtual_machine_ids").(*schema.Set).List()),
	)
	if err != nil {
		return nil, err
	}

	obj := &types.ClusterVmGroup{
		ClusterGroupInfo: types.ClusterGroupInfo{
			Name:        name,
			UserCreated: structure.BoolPtr(true),
		},
		Vm: results.ManagedObjectReferences(),
	}
	return obj, nil
}

// expandClusterVMGroup reads certain ResourceData keys and returns a
// ClusterVmGroup.

expandClusterVMGroup reads certain ResourceData keys and returns a ClusterVmGroup .


func flattenClusterVMGroup(d *schema.ResourceData, meta interface{}, obj *types.ClusterVmGroup) error {
	client, err := resourceVSphereComputeClusterVMGroupClient(meta)
	if err != nil {
		return err
	}

	results, err := virtualmachine.UUIDsForManagedObjectReferences(
		client,
		obj.Vm,
	)
	if err != nil {
		return err
	}

	return structure.SetBatch(d, map[string]interface{}{
		"virtual_machine_ids": results.UUIDs(),
	})
}

// flattenClusterVmGroup saves a ClusterVmGroup into the supplied ResourceData.

flattenClusterVmGroup saves a ClusterVmGroup into the supplied ResourceData .


func resourceVSphereComputeClusterVMGroupFindEntry(
	cluster *object.ClusterComputeResource,
	name string,
) (*types.ClusterVmGroup, error) {
	props, err := clustercomputeresource.Properties(cluster)
	if err != nil {
		return nil, fmt.Errorf("error fetching cluster properties: %s", err)
	}

	for _, info := range props.ConfigurationEx.(*types.ClusterConfigInfoEx).Group {
		if info.GetClusterGroupInfo().Name == name {
			if vmInfo, ok := info.(*types.ClusterVmGroup); ok {
				log.Printf("[DEBUG] Found VM group %q in cluster %q", name, cluster.Name())
				return vmInfo, nil
			}
			return nil, fmt.Errorf("unique group name %q in cluster %q is not a VM group", name, cluster.Name())
		}
	}

	log.Printf("[DEBUG] No VM group name %q found in cluster %q", name, cluster.Name())
	return nil, nil
}

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


func resourceVSphereComputeClusterVMGroupFetchObjects(
	meta interface{},
	clusterID string,
	name string,
) (*object.ClusterComputeResource, string, error) {
	client, err := resourceVSphereComputeClusterVMGroupClient(meta)
	if err != nil {
		return nil, "", err
	}

	cluster, err := clustercomputeresource.FromID(client, clusterID)
	if err != nil {
		return nil, "", fmt.Errorf("cannot locate cluster: %s", err)
	}

	return cluster, name, nil
}

// resourceVSphereComputeClusterVMGroupFetchObjects fetches the "objects" for a
// cluster VM group. This is currently just the cluster object as the name of
// the group is a static value and a pass-through - this is to keep its
// workflow consistent with other cluster-dependent resources that derive from
// ArrayUpdateSpec that have managed object as keys, such as VM and host
// overrides.


func resourceVSphereResourcePoolApplyTags(d *schema.ResourceData, meta interface{}, rp *object.ResourcePool) error {
	tagsClient, err := tagsClientIfDefined(d, meta)
	if err != nil {
		return err
	}

	// Apply any pending tags now.
	if tagsClient == nil {
		log.Printf("[DEBUG] %s: Tags unsupported on this connection, skipping", resourceVSphereComputeClusterIDString(d))
		return nil
	}

	log.Printf("[DEBUG] %s: Applying any pending tags", resourceVSphereResourcePoolIDString(d))
	return processTagDiff(tagsClient, d, rp)
}

func
resourceVSphereResourcePoolApplyTags
(
d
*
schema
.
ResourceData
,
meta
interface
{
}
,
rp
*
object
.
ResourcePool
)
error
{
tagsClient
,
err
:=
tagsClientIfDefined
(
d
,
meta
)
if
err
!=
{
return
err
}
// Apply any pending tags now.
if
tagsClient
==
{
log
.
Printf
(
"
"
,
resourceVSphereComputeClusterIDString
(
d
)
)
return
}
log
.
Printf
(
"
"
,
resourceVSphereResourcePoolIDString
(
d
)
)
return
processTagDiff
(
tagsClient
,
d
,
rp
)
}

// resourceVSphereResourcePoolApplyTags processes the tags step for both create
// and update for vsphere_resource_pool.

resourceVSphereResourcePoolApplyTags processes the tags step for both create and update for vsphere_resource_pool .


func resourceVSphereResourcePoolReadTags(d *schema.ResourceData, meta interface{}, rp *object.ResourcePool) error {
	if tagsClient, _ := meta.(*VSphereClient).TagsClient(); tagsClient != nil {
		log.Printf("[DEBUG] %s: Reading tags", resourceVSphereResourcePoolIDString(d))
		if err := readTagsForResource(tagsClient, rp, d); err != nil {
			return err
		}
	} else {
		log.Printf("[DEBUG] %s: Tags unsupported on this connection, skipping tag read", resourceVSphereResourcePoolIDString(d))
	}
	return nil
}

func resourceVSphereResourcePoolReadTags ( d * schema . ResourceData , meta interface { } , rp * object . ResourcePool ) error { if tagsClient , _ := meta . ( * VSphereClient ) . TagsClient ( ) ; tagsClient != nil { log . Printf ( " " , resourceVSphereResourcePoolIDString ( d ) ) if err := readTagsForResource ( tagsClient , rp , d ) ; err != nil { return err } } else { log . Printf ( " " , resourceVSphereResourcePoolIDString ( d ) ) } return nil }

// resourceVSphereResourcePoolReadTags reads the tags for
// vsphere_resource_pool.

resourceVSphereResourcePoolReadTags reads the tags for vsphere_resource_pool .


func expandClusterAffinityRuleSpec(d *schema.ResourceData, meta interface{}) (*types.ClusterAffinityRuleSpec, error) {
	client, err := resourceVSphereComputeClusterVMGroupClient(meta)
	if err != nil {
		return nil, err
	}

	results, err := virtualmachine.MOIDsForUUIDs(
		client,
		structure.SliceInterfacesToStrings(d.Get("virtual_machine_ids").(*schema.Set).List()),
	)
	if err != nil {
		return nil, err
	}

	obj := &types.ClusterAffinityRuleSpec{
		ClusterRuleInfo: types.ClusterRuleInfo{
			Enabled:     structure.GetBool(d, "enabled"),
			Mandatory:   structure.GetBool(d, "mandatory"),
			Name:        d.Get("name").(string),
			UserCreated: structure.BoolPtr(true),
		},
		Vm: results.ManagedObjectReferences(),
	}
	return obj, nil
}

// expandClusterAffinityRuleSpec reads certain ResourceData keys and returns a
// ClusterAffinityRuleSpec.

expandClusterAffinityRuleSpec reads certain ResourceData keys and returns a ClusterAffinityRuleSpec .


func flattenClusterAffinityRuleSpec(d *schema.ResourceData, meta interface{}, obj *types.ClusterAffinityRuleSpec) error {
	client, err := resourceVSphereComputeClusterVMGroupClient(meta)
	if err != nil {
		return err
	}

	results, err := virtualmachine.UUIDsForManagedObjectReferences(
		client,
		obj.Vm,
	)
	if err != nil {
		return err
	}

	return structure.SetBatch(d, map[string]interface{}{
		"enabled":             obj.Enabled,
		"mandatory":           obj.Mandatory,
		"name":                obj.Name,
		"virtual_machine_ids": results.UUIDs(),
	})
}

// flattenClusterAffinityRuleSpec saves a ClusterAffinityRuleSpec into the supplied ResourceData.

flattenClusterAffinityRuleSpec saves a ClusterAffinityRuleSpec into the supplied ResourceData .


func resourceVSphereComputeClusterVMAffinityRuleFindEntry(
	cluster *object.ClusterComputeResource,
	key int32,
) (*types.ClusterAffinityRuleSpec, error) {
	props, err := clustercomputeresource.Properties(cluster)
	if err != nil {
		return nil, fmt.Errorf("error fetching cluster properties: %s", err)
	}

	for _, info := range props.ConfigurationEx.(*types.ClusterConfigInfoEx).Rule {
		if info.GetClusterRuleInfo().Key == key {
			if vmAffinityRuleInfo, ok := info.(*types.ClusterAffinityRuleSpec); ok {
				log.Printf("[DEBUG] Found VM affinity rule key %d in cluster %q", key, cluster.Name())
				return vmAffinityRuleInfo, nil
			}
			return nil, fmt.Errorf("rule key %d in cluster %q is not a VM affinity rule", key, cluster.Name())
		}
	}

	log.Printf("[DEBUG] No VM affinity rule key %d found in cluster %q", key, cluster.Name())
	return nil, nil
}

// resourceVSphereComputeClusterVMAffinityRuleFindEntry attempts to locate an
// existing VM affinity rule in a cluster's configuration by key. It's used by the
// resource's read functionality and tests. nil is returned if the entry cannot
// be found.


func ConfigSchema() *schema.Schema {
	return &schema.Schema{
		Type:        schema.TypeMap,
		Description: "A list of custom attributes to set on this resource.",
		Optional:    true,
	}
}

func ConfigSchema ( ) * schema . Schema { return & schema . Schema { Type : schema . TypeMap , Description : " " , Optional : true , } }

// ConfigSchema returns the schema for custom attribute configuration
// for each resource that needs it.
//
// The key should be set to the ConfigKey constant and should be a
// map of custom attribute ids to values.

ConfigSchema returns the schema for custom attribute configuration for each resource that needs it . The key should be set to the ConfigKey constant and should be a map of custom attribute ids to values .


func VirtualMachineCloneSchema() map[string]*schema.Schema {
	return map[string]*schema.Schema{
		"template_uuid": {
			Type:        schema.TypeString,
			Required:    true,
			Description: "The UUID of the source virtual machine or template.",
		},
		"linked_clone": {
			Type:        schema.TypeBool,
			Optional:    true,
			Description: "Whether or not to create a linked clone when cloning. When this option is used, the source VM must have a single snapshot associated with it.",
		},
		"timeout": {
			Type:         schema.TypeInt,
			Optional:     true,
			Default:      30,
			Description:  "The timeout, in minutes, to wait for the virtual machine clone to complete.",
			ValidateFunc: validation.IntAtLeast(10),
		},
		"customize": {
			Type:        schema.TypeList,
			Optional:    true,
			MaxItems:    1,
			Description: "The customization spec for this clone. This allows the user to configure the virtual machine post-clone.",
			Elem:        &schema.Resource{Schema: VirtualMachineCustomizeSchema()},
		},
	}
}

func VirtualMachineCloneSchema ( ) map [ string ] * schema . Schema { return map [ string ] * schema . Schema { " " : { Type : schema . TypeString , Required : true , Description : " " , } , " " : { Type : schema . TypeBool , Optional : true , Description : " " , } , " " : { Type : schema . TypeInt , Optional : true , Default : 30 , Description : " " , ValidateFunc : validation . IntAtLeast ( 10 ) , } , " " : { Type : schema . TypeList , Optional : true , MaxItems : 1 , Description : " " , Elem : & schema . Resource { Schema : VirtualMachineCustomizeSchema ( ) } , } , } }

// VirtualMachineCloneSchema represents the schema for the VM clone sub-resource.
//
// This is a workflow for vsphere_virtual_machine that facilitates the creation
// of a virtual machine through cloning from an existing template.
// Customization is nested here, even though it exists in its own workflow.

VirtualMachineCloneSchema represents the schema for the VM clone sub - resource . This is a workflow for vsphere_virtual_machine that facilitates the creation of a virtual machine through cloning from an existing template . Customization is nested here even though it exists in its own workflow .


func ValidateVirtualMachineClone(d *schema.ResourceDiff, c *govmomi.Client) error {
	tUUID := d.Get("clone.0.template_uuid").(string)
	log.Printf("[DEBUG] ValidateVirtualMachineClone: Validating fitness of source VM/template %s", tUUID)
	vm, err := virtualmachine.FromUUID(c, tUUID)
	if err != nil {
		return fmt.Errorf("cannot locate virtual machine or template with UUID %q: %s", tUUID, err)
	}
	vprops, err := virtualmachine.Properties(vm)
	if err != nil {
		return fmt.Errorf("error fetching virtual machine or template properties: %s", err)
	}
	// The virtual machine needs to be powered off to be suitable for cloning.
	if vprops.Runtime.PowerState != types.VirtualMachinePowerStatePoweredOff {
		return fmt.Errorf("virtual machine %s must be powered off to be used as a source for cloning", tUUID)
	}
	// Check to see if our guest IDs match.
	eGuestID := vprops.Config.GuestId
	aGuestID := d.Get("guest_id").(string)
	if eGuestID != aGuestID {
		return fmt.Errorf("invalid guest ID %q for clone. Please set it to %q", aGuestID, eGuestID)
	}
	// If linked clone is enabled, check to see if we have a snapshot. There need
	// to be a single snapshot on the template for it to be eligible.
	linked := d.Get("clone.0.linked_clone").(bool)
	if linked {
		log.Printf("[DEBUG] ValidateVirtualMachineClone: Checking snapshots on %s for linked clone eligibility", tUUID)
		if err := validateCloneSnapshots(vprops); err != nil {
			return err
		}
	}
	// Check to make sure the disks for this VM/template line up with the disks
	// in the configuration. This is in the virtual device package, so pass off
	// to that now.
	l := object.VirtualDeviceList(vprops.Config.Hardware.Device)
	if err := virtualdevice.DiskCloneValidateOperation(d, c, l, linked); err != nil {
		return err
	}

	// If a customization spec was defined, we need to check some items in it as well.
	if len(d.Get("clone.0.customize").([]interface{})) > 0 {
		if poolID, ok := d.GetOk("resource_pool_id"); ok {
			pool, err := resourcepool.FromID(c, poolID.(string))
			if err != nil {
				return fmt.Errorf("could not find resource pool ID %q: %s", poolID, err)
			}
			family, err := resourcepool.OSFamily(c, pool, d.Get("guest_id").(string))
			if err != nil {
				return fmt.Errorf("cannot find OS family for guest ID %q: %s", d.Get("guest_id").(string), err)
			}
			if err := ValidateCustomizationSpec(d, family); err != nil {
				return err
			}
		} else {
			log.Printf("[DEBUG] ValidateVirtualMachineClone: resource_pool_id is not available. Skipping OS family check.")
		}
	}
	vconfig := vprops.Config.VAppConfig
	if vconfig != nil {
		// We need to set the vApp transport types here so that it is available
		// later in CustomizeDiff where transport requirements are validated in
		// ValidateVAppTransport
		d.SetNew("vapp_transport", vconfig.GetVmConfigInfo().OvfEnvironmentTransport)
	}

	log.Printf("[DEBUG] ValidateVirtualMachineClone: Source VM/template %s is a suitable source for cloning", tUUID)
	return nil
}

// ValidateVirtualMachineClone does pre-creation validation of a virtual
// machine's configuration to make sure it's suitable for use in cloning.
// This includes, but is not limited to checking to make sure that the disks in
// the new VM configuration line up with the configuration in the existing
// template, and checking to make sure that the VM has a single snapshot we can
// use in the even that linked clones are enabled.

ValidateVirtualMachineClone does pre - creation validation of a virtual machine s configuration to make sure it s suitable for use in cloning . This includes but is not limited to checking to make sure that the disks in the new VM configuration line up with the configuration in the existing template and checking to make sure that the VM has a single snapshot we can use in the even that linked clones are enabled .


func validateCloneSnapshots(props *mo.VirtualMachine) error {
	if props.Snapshot == nil {
		return fmt.Errorf("virtual machine or template %s must have a snapshot to be used as a linked clone", props.Config.Uuid)
	}
	// Root snapshot list can only have a singular element
	if len(props.Snapshot.RootSnapshotList) != 1 {
		return fmt.Errorf("virtual machine or template %s must have exactly one root snapshot (has: %d)", props.Config.Uuid, len(props.Snapshot.RootSnapshotList))
	}
	// Check to make sure the root snapshot has no children
	if len(props.Snapshot.RootSnapshotList[0].ChildSnapshotList) > 0 {
		return fmt.Errorf("virtual machine or template %s's root snapshot must not have children", props.Config.Uuid)
	}
	// Current snapshot must match root snapshot (this should be the case anyway)
	if props.Snapshot.CurrentSnapshot.Value != props.Snapshot.RootSnapshotList[0].Snapshot.Value {
		return fmt.Errorf("virtual machine or template %s's current snapshot must match root snapshot", props.Config.Uuid)
	}
	return nil
}

// validateCloneSnapshots checks a VM to make sure it has a single snapshot
// with no children, to make sure there is no ambiguity when selecting a
// snapshot for linked clones.

validateCloneSnapshots checks a VM to make sure it has a single snapshot with no children to make sure there is no ambiguity when selecting a snapshot for linked clones .


func ReferenceProperties(client *govmomi.Client, net object.NetworkReference) (*mo.Network, error) {
	ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
	defer cancel()
	var props mo.Network
	nc := object.NewCommon(client.Client, net.Reference())
	if err := nc.Properties(ctx, nc.Reference(), nil, &props); err != nil {
		return nil, err
	}
	return &props, nil
}

func ReferenceProperties ( client * govmomi . Client , net object . NetworkReference ) ( * mo . Network , error ) { ctx , cancel := context . WithTimeout ( context . Background ( ) , provider . DefaultAPITimeout ) defer cancel ( ) var props mo . Network nc := object . NewCommon ( client . Client , net . Reference ( ) ) if err := nc . Properties ( ctx , nc . Reference ( ) , nil , & props ) ; err != nil { return nil , err } return & props , nil }

// ReferenceProperties is a convenience method that wraps fetching the Network
// MO from a NetworkReference.
//
// Note that regardless of the network type, this only fetches the Network MO
// and not any of the extended properties of that network.

ReferenceProperties is a convenience method that wraps fetching the Network MO from a NetworkReference . Note that regardless of the network type this only fetches the Network MO and not any of the extended properties of that network .


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

	ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
	defer cancel()
	t := client.ServiceContent.About.ApiType
	switch t {
	case "HostAgent":
		return finder.DefaultHostSystem(ctx)
	case "VirtualCenter":
		if name != "" {
			return finder.HostSystem(ctx, name)
		}
		return finder.DefaultHostSystem(ctx)
	}
	return nil, fmt.Errorf("unsupported ApiType: %s", t)
}

func SystemOrDefault ( client * govmomi . Client , name string , dc * object . Datacenter ) ( * object . HostSystem , error ) { finder := find . NewFinder ( client . Client , false ) finder . SetDatacenter ( dc ) ctx , cancel := context . WithTimeout ( context . Background ( ) , provider . DefaultAPITimeout ) defer cancel ( ) t := client . ServiceContent . About . ApiType switch t { case " " : return finder . DefaultHostSystem ( ctx ) case " " : if name != " " { return finder . HostSystem ( ctx , name ) } return finder . DefaultHostSystem ( ctx ) } return nil , fmt . Errorf ( " " , t ) }

// SystemOrDefault returns a HostSystem from a specific host name and
// datacenter. If the user is connecting over ESXi, the default host system is
// used.

SystemOrDefault returns a HostSystem from a specific host name and datacenter . If the user is connecting over ESXi the default host system is used .


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

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

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

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


func ResourcePool(host *object.HostSystem) (*object.ResourcePool, error) {
	ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
	defer cancel()
	return host.ResourcePool(ctx)
}

func ResourcePool ( host * object . HostSystem ) ( * object . ResourcePool , error ) { ctx , cancel := context . WithTimeout ( context . Background ( ) , provider . DefaultAPITimeout ) defer cancel ( ) return host . ResourcePool ( ctx ) }

// ResourcePool is a convenience method that wraps fetching the host system's
// root resource pool

ResourcePool is a convenience method that wraps fetching the host system s root resource pool


func hostSystemNameFromID(client *govmomi.Client, id string) (string, error) {
	hs, err := FromID(client, id)
	if err != nil {
		return "", err
	}
	return hs.Name(), nil
}

func hostSystemNameFromID ( client * govmomi . Client , id string ) ( string , error ) { hs , err := FromID ( client , id ) if err != nil { return " " , err } return hs . Name ( ) , nil }

// hostSystemNameFromID returns the name of a host via its its managed object
// reference ID.

hostSystemNameFromID returns the name of a host via its its managed object reference ID .


func NameOrID(client *govmomi.Client, id string) string {
	name, err := hostSystemNameFromID(client, id)
	if err != nil {
		return id
	}
	return name
}

func NameOrID ( client * govmomi . Client , id string ) string { name , err := hostSystemNameFromID ( client , id ) if err != nil { return id } return name }

// NameOrID is a convenience method mainly for helping displaying friendly
// errors where space is important - it displays either the host name or the ID
// if there was an error fetching it.

NameOrID is a convenience method mainly for helping displaying friendly errors where space is important - it displays either the host name or the ID if there was an error fetching it .


func EnterMaintenanceMode(host *object.HostSystem, timeout int, evacuate bool) error {
	if err := viapi.VimValidateVirtualCenter(host.Client()); err != nil {
		evacuate = false
	}

	log.Printf("[DEBUG] Host %q is entering maintenance mode (evacuate: %t)", host.Name(), evacuate)

	ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(timeout))
	defer cancel()
	task, err := host.EnterMaintenanceMode(ctx, int32(timeout), evacuate, nil)
	if err != nil {
		return err
	}

	return task.Wait(ctx)
}

func EnterMaintenanceMode ( host * object . HostSystem , timeout int , evacuate bool ) error { if err := viapi . VimValidateVirtualCenter ( host . Client ( ) ) ; err != nil { evacuate = false } log . Printf ( " " , host . Name ( ) , evacuate ) ctx , cancel := context . WithTimeout ( context . Background ( ) , time . Second * time . Duration ( timeout ) ) defer cancel ( ) task , err := host . EnterMaintenanceMode ( ctx , int32 ( timeout ) , evacuate , nil ) if err != nil { return err } return task . Wait ( ctx ) }

// EnterMaintenanceMode puts a host into maintenance mode. If evacuate is set
// to true, all powered off VMs will be removed from the host, or the task will
// block until this is the case, depending on whether or not DRS is on or off
// for the host's cluster. This parameter is ignored on direct ESXi.

EnterMaintenanceMode puts a host into maintenance mode . If evacuate is set to true all powered off VMs will be removed from the host or the task will block until this is the case depending on whether or not DRS is on or off for the host s cluster . This parameter is ignored on direct ESXi .


func ExitMaintenanceMode(host *object.HostSystem, timeout int) error {
	log.Printf("[DEBUG] Host %q is exiting maintenance mode", host.Name())

	// Add 5 minutes to timeout for the context timeout to allow for any issues
	// with the request after.
	// TODO: Fix this so that it ultimately uses the provider context.
	ctxTimeout := timeout + 300
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(ctxTimeout))
	defer cancel()
	task, err := host.ExitMaintenanceMode(ctx, int32(timeout))
	if err != nil {
		return err
	}

	return task.Wait(ctx)
}

// ExitMaintenanceMode takes a host out of maintenance mode.

ExitMaintenanceMode takes a host out of maintenance mode .


func dvsFromUUID(client *govmomi.Client, uuid string) (*object.VmwareDistributedVirtualSwitch, error) {
	dvsm := types.ManagedObjectReference{Type: "DistributedVirtualSwitchManager", Value: "DVSManager"}
	req := &types.QueryDvsByUuid{
		This: dvsm,
		Uuid: uuid,
	}
	resp, err := methods.QueryDvsByUuid(context.TODO(), client, req)
	if err != nil {
		return nil, err
	}

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

func dvsFromUUID ( client * govmomi . Client , uuid string ) ( * object . VmwareDistributedVirtualSwitch , error ) { dvsm := types . ManagedObjectReference { Type : " " , Value : " " } req := & types . QueryDvsByUuid { This : dvsm , Uuid : uuid , } resp , err := methods . QueryDvsByUuid ( context . TODO ( ) , client , req ) if err != nil { return nil , err } return dvsFromMOID ( client , resp . Returnval . Reference ( ) . Value ) }

// dvsFromUUID gets a DVS object from its UUID.

dvsFromUUID gets a DVS object from its UUID .


func dvsFromPath(client *govmomi.Client, name string, dc *object.Datacenter) (*object.VmwareDistributedVirtualSwitch, error) {
	net, err := network.FromPath(client, name, dc)
	if err != nil {
		return nil, err
	}
	if net.Reference().Type != "VmwareDistributedVirtualSwitch" {
		return nil, fmt.Errorf("network at path %q is not a VMware distributed virtual switch (type %s)", name, net.Reference().Type)
	}
	return dvsFromMOID(client, net.Reference().Value)
}

func dvsFromPath ( client * govmomi . Client , name string , dc * object . Datacenter ) ( * object . VmwareDistributedVirtualSwitch , error ) { net , err := network . FromPath ( client , name , dc ) if err != nil { return nil , err } if net . Reference ( ) . Type != " " { return nil , fmt . Errorf ( " " , name , net . Reference ( ) . Type ) } return dvsFromMOID ( client , net . Reference ( ) . Value ) }

// dvsFromPath gets a DVS object from its path.

dvsFromPath gets a DVS object from its path .


func dvsProperties(dvs *object.VmwareDistributedVirtualSwitch) (*mo.VmwareDistributedVirtualSwitch, error) {
	ctx, cancel := context.WithTimeout(context.Background(), defaultAPITimeout)
	defer cancel()
	var props mo.VmwareDistributedVirtualSwitch
	if err := dvs.Properties(ctx, dvs.Reference(), nil, &props); err != nil {
		return nil, err
	}
	return &props, nil
}

func dvsProperties ( dvs * object . VmwareDistributedVirtualSwitch ) ( * mo . VmwareDistributedVirtualSwitch , error ) { ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultAPITimeout ) defer cancel ( ) var props mo . VmwareDistributedVirtualSwitch if err := dvs . Properties ( ctx , dvs . Reference ( ) , nil , & props ) ; err != nil { return nil , err } return & props , nil }

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

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


func upgradeDVS(client *govmomi.Client, dvs *object.VmwareDistributedVirtualSwitch, version string) error {
	req := &types.PerformDvsProductSpecOperation_Task{
		This:      dvs.Reference(),
		Operation: "upgrade",
		ProductSpec: &types.DistributedVirtualSwitchProductSpec{
			Version: version,
		},
	}

	ctx, cancel := context.WithTimeout(context.Background(), defaultAPITimeout)
	defer cancel()
	resp, err := methods.PerformDvsProductSpecOperation_Task(ctx, client, req)
	if err != nil {
		return err
	}
	task := object.NewTask(client.Client, resp.Returnval)
	tctx, tcancel := context.WithTimeout(context.Background(), defaultAPITimeout)
	defer tcancel()
	if err := task.Wait(tctx); err != nil {
		return err
	}

	return nil
}

func upgradeDVS ( client * govmomi . Client , dvs * object . VmwareDistributedVirtualSwitch , version string ) error { req := & types . PerformDvsProductSpecOperation_Task { This : dvs . Reference ( ) , Operation : " " , ProductSpec : & types . DistributedVirtualSwitchProductSpec { Version : version , } , } ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultAPITimeout ) defer cancel ( ) resp , err := methods . PerformDvsProductSpecOperation_Task ( ctx , client , req ) if err != nil { return err } task := object . NewTask ( client . Client , resp . Returnval ) tctx , tcancel := context . WithTimeout ( context . Background ( ) , defaultAPITimeout ) defer tcancel ( ) if err := task . Wait ( tctx ) ; err != nil { return err } return nil }

// upgradeDVS upgrades a DVS to a specific version. Downgrades are not
// supported and will result in an error. This should be checked before running
// this function.

upgradeDVS upgrades a DVS to a specific version . Downgrades are not supported and will result in an error . This should be checked before running this function .


func enableDVSNetworkResourceManagement(client *govmomi.Client, dvs *object.VmwareDistributedVirtualSwitch, enabled bool) error {
	req := &types.EnableNetworkResourceManagement{
		This:   dvs.Reference(),
		Enable: enabled,
	}

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

	return nil
}

func enableDVSNetworkResourceManagement ( client * govmomi . Client , dvs * object . VmwareDistributedVirtualSwitch , enabled bool ) error { req := & types . EnableNetworkResourceManagement { This : dvs . Reference ( ) , Enable : enabled , } ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultAPITimeout ) defer cancel ( ) _ , err := methods . EnableNetworkResourceManagement ( ctx , client , req ) if err != nil { return err } return nil }

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

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


func resourceVSphereDatastoreClusterVMAntiAffinityRuleFlattenID(pod *object.StoragePod, key int32) (string, error) {
	podID := pod.Reference().Value
	return strings.Join([]string{podID, strconv.Itoa(int(key))}, ":"), nil
}

// resourceVSphereDatastoreClusterVMAntiAffinityRuleFlattenID makes an ID for the
// vsphere_datastore_cluster_vm_anti_affinity_rule resource.


func resourceVSphereDatastoreClusterVMAntiAffinityRuleFindEntry(
	pod *object.StoragePod,
	key int32,
) (*types.ClusterAntiAffinityRuleSpec, 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.PodConfig.Rule {
		if info.GetClusterRuleInfo().Key == key {
			if vmAntiAffinityRuleInfo, ok := info.(*types.ClusterAntiAffinityRuleSpec); ok {
				log.Printf("[DEBUG] Found VM anti-affinity rule key %d in datastore cluster %q", key, pod.Name())
				return vmAntiAffinityRuleInfo, nil
			}
			return nil, fmt.Errorf("rule key %d in datastore cluster %q is not a VM anti-affinity rule", key, pod.Name())
		}
	}

	log.Printf("[DEBUG] No VM anti-affinity rule key %d found in datastore cluster %q", key, pod.Name())
	return nil, nil
}

// resourceVSphereDatastoreClusterVMAntiAffinityRuleFindEntry attempts to
// locate an existing VM anti-affinity rule in a datastore cluster's
// configuration by key. It's used by the resource's read functionality and
// tests. nil is returned if the entry cannot be found.


func resourceVSphereDatastoreClusterVMAntiAffinityRuleFindEntryByName(
	pod *object.StoragePod,
	name string,
) (*types.ClusterAntiAffinityRuleSpec, 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.PodConfig.Rule {
		if info.GetClusterRuleInfo().Name == name {
			if vmAntiAffinityRuleInfo, ok := info.(*types.ClusterAntiAffinityRuleSpec); ok {
				log.Printf("[DEBUG] Found VM anti-affinity rule %q in datastore cluster %q", name, pod.Name())
				return vmAntiAffinityRuleInfo, nil
			}
			return nil, fmt.Errorf("rule %q in datastore cluster %q is not a VM anti-affinity rule", name, pod.Name())
		}
	}

	return nil, fmt.Errorf("no VM anti-affinity rule %q found in datastore cluster %q", name, pod.Name())
}

// resourceVSphereDatastoreClusterVMAntiAffinityRuleFindEntryByName attempts to
// locate an existing VM anti-affinity rule in a datastore cluster's
// configuration by name. It differs from the standard
// resourceVSphereDatastoreClusterVMAntiAffinityRuleFindEntry in that we don't
// allow missing entries, as it's designed to be used in places where we don't
// want to allow for missing entries, such as during creation and import.


func resourceVSphereDatastoreClusterVMAntiAffinityRuleFetchObjects(
	meta interface{},
	podID string,
	key int32,
) (*object.StoragePod, int32, error) {
	client, err := resourceVSphereDatastoreClusterVMAntiAffinityRuleClient(meta)
	if err != nil {
		return nil, 0, err
	}

	pod, err := storagepod.FromID(client, podID)
	if err != nil {
		return nil, 0, fmt.Errorf("cannot locate datastore cluster: %s", err)
	}

	return pod, key, nil
}

// resourceVSphereDatastoreClusterVMAntiAffinityRuleFetchObjects fetches the
// "objects" for a cluster rule. This is currently just the cluster object as
// the rule key a static value and a pass-through - this is to keep its
// workflow consistent with other cluster-dependent resources that derive from
// ArrayUpdateSpec that have managed object as keys, such as VM and host
// overrides.


func controllerTypeToClass(c types.BaseVirtualController) (string, error) {
	var t string
	switch c.(type) {
	case *types.VirtualIDEController:
		t = SubresourceControllerTypeIDE
	case *types.VirtualAHCIController:
		t = SubresourceControllerTypeSATA
	case *types.VirtualPCIController:
		t = SubresourceControllerTypePCI
	case *types.ParaVirtualSCSIController, *types.VirtualBusLogicController,
		*types.VirtualLsiLogicController, *types.VirtualLsiLogicSASController:
		t = SubresourceControllerTypeSCSI
	default:
		return subresourceControllerTypeUnknown, fmt.Errorf("unsupported controller type %T", c)
	}
	return t, nil
}

func controllerTypeToClass ( c types . BaseVirtualController ) ( string , error ) { var t string switch c . ( type ) { case * types . VirtualIDEController : t = SubresourceControllerTypeIDE case * types . VirtualAHCIController : t = SubresourceControllerTypeSATA case * types . VirtualPCIController : t = SubresourceControllerTypePCI case * types . ParaVirtualSCSIController , * types . VirtualBusLogicController , * types . VirtualLsiLogicController , * types . VirtualLsiLogicSASController : t = SubresourceControllerTypeSCSI default : return subresourceControllerTypeUnknown , fmt . Errorf ( " " , c ) } return t , nil }

// controllerTypeToClass converts a controller type to a specific short-form
// controller class, namely for use with working with IDs.

controllerTypeToClass converts a controller type to a specific short - form controller class namely for use with working with IDs .


func (r *Subresource) Addr() string {
	return fmt.Sprintf("%s.%d", r.srtype, r.Index)
}

func ( r * Subresource ) Addr ( ) string { return fmt . Sprintf ( " " , r . srtype , r . Index ) }

// Addr returns the resource address for this subresource.

Addr returns the resource address for this subresource .


func (r *Subresource) HasChange(key string) bool {
	o, n := r.GetChange(key)
	return !reflect.DeepEqual(o, n)
}

func ( r * Subresource ) HasChange ( key string ) bool { o , n := r . GetChange ( key ) return ! reflect . DeepEqual ( o , n ) }

// HasChange checks to see if there has been a change in the resource data
// since the last update.
//
// Note that this operation may only be useful during update operations,
// depending on subresource-specific workflow.

HasChange checks to see if there has been a change in the resource data since the last update . Note that this operation may only be useful during update operations depending on subresource - specific workflow .


func (r *Subresource) GetChange(key string) (interface{}, interface{}) {
	new := r.data[key]
	// No old data means no change,  so we use the new value as a placeholder.
	old := r.data[key]
	if r.olddata != nil {
		old = r.olddata[key]
	}
	return old, new
}

// GetChange gets the old and new values for the value specified by key.

GetChange gets the old and new values for the value specified by key .


func (r *Subresource) GetWithRestart(key string) interface{} {
	if r.HasChange(key) {
		r.SetRestart(key)
	}
	return r.Get(key)
}

func ( r * Subresource ) GetWithRestart ( key string ) interface { } { if r . HasChange ( key ) { r . SetRestart ( key ) } return r . Get ( key ) }

// GetWithRestart checks to see if a field has been modified, returns the new
// value, and sets restart if it has changed.

GetWithRestart checks to see if a field has been modified returns the new value and sets restart if it has changed .


func (r *Subresource) GetWithVeto(key string) (interface{}, error) {
	if r.HasChange(key) {
		old, new := r.GetChange(key)
		return r.Get(key), fmt.Errorf("cannot change the value of %q - (old: %v new: %v)", key, old, new)
	}
	return r.Get(key), nil
}

func ( r * Subresource ) GetWithVeto ( key string ) ( interface { } , error ) { if r . HasChange ( key ) { old , new := r . GetChange ( key ) return r . Get ( key ) , fmt . Errorf ( " " , key , old , new ) } return r . Get ( key ) , nil }

// GetWithVeto returns the value specified by key, but returns an error if it
// has changed. The intention here is to block changes to the resource in a
// fashion that would otherwise result in forcing a new resource.

GetWithVeto returns the value specified by key but returns an error if it has changed . The intention here is to block changes to the resource in a fashion that would otherwise result in forcing a new resource .


func (r *Subresource) SetRestart(key string) {
	log.Printf("[DEBUG] %s: Resource argument %q requires a VM restart", r, key)
	switch d := r.rdd.(type) {
	case *schema.ResourceData:
		d.Set("reboot_required", true)
	case *schema.ResourceDiff:
		d.SetNew("reboot_required", true)
	default:
		// This should never happen, but log if it does.
		log.Printf("[WARN] %s: Could not flag reboot_required: invalid type %T", r, r.rdd)
	}
}

// SetRestart sets reboot_required in the global ResourceData. The key is only
// required for logging.

SetRestart sets reboot_required in the global ResourceData . The key is only required for logging .


func (r *Subresource) Hash() int {
	hf := schema.HashResource(&schema.Resource{Schema: r.schema})
	return hf(r.data)
}

func ( r * Subresource ) Hash ( ) int { hf := schema . HashResource ( & schema . Resource { Schema : r . schema } ) return hf ( r . data ) }

// Hash calculates a set hash for the current data. If you want a hash for
// error reporting a device address, it's probably a good idea to run this at
// the beginning of a run as any set calls will change the value this
// ultimately calculates.

Hash calculates a set hash for the current data . If you want a hash for error reporting a device address it s probably a good idea to run this at the beginning of a run as any set calls will change the value this ultimately calculates .


func computeDevAddr(device types.BaseVirtualDevice, ctlr types.BaseVirtualController) (string, error) {
	vd := device.GetVirtualDevice()
	vc := ctlr.GetVirtualController()
	ctype, err := controllerTypeToClass(ctlr)
	if err != nil {
		return "", err
	}
	parts := []string{
		ctype,
		strconv.Itoa(int(vc.BusNumber)),
		strconv.Itoa(int(structure.DeRef(vd.UnitNumber).(int32))),
	}
	return strings.Join(parts, ":"), nil
}

func computeDevAddr ( device types . BaseVirtualDevice , ctlr types . BaseVirtualController ) ( string , error ) { vd := device . GetVirtualDevice ( ) vc := ctlr . GetVirtualController ( ) ctype , err := controllerTypeToClass ( ctlr ) if err != nil { return " " , err } parts := [ ] string { ctype , strconv . Itoa ( int ( vc . BusNumber ) ) , strconv . Itoa ( int ( structure . DeRef ( vd . UnitNumber ) . ( int32 ) ) ) , } return strings . Join ( parts , " " ) , nil }

// computeDevAddr handles the logic for SaveDevIDs and allows it to be used
// outside of a subresource.

computeDevAddr handles the logic for SaveDevIDs and allows it to be used outside of a subresource .