Blame vendor/github.com/vmware/govmomi/govc/vm/create.go

Packit 63bb0d
/*
Packit 63bb0d
Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved.
Packit 63bb0d
Packit 63bb0d
Licensed under the Apache License, Version 2.0 (the "License");
Packit 63bb0d
you may not use this file except in compliance with the License.
Packit 63bb0d
You may obtain a copy of the License at
Packit 63bb0d
Packit 63bb0d
    http://www.apache.org/licenses/LICENSE-2.0
Packit 63bb0d
Packit 63bb0d
Unless required by applicable law or agreed to in writing, software
Packit 63bb0d
distributed under the License is distributed on an "AS IS" BASIS,
Packit 63bb0d
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 63bb0d
See the License for the specific language governing permissions and
Packit 63bb0d
limitations under the License.
Packit 63bb0d
*/
Packit 63bb0d
Packit 63bb0d
package vm
Packit 63bb0d
Packit 63bb0d
import (
Packit 63bb0d
	"context"
Packit 63bb0d
	"flag"
Packit 63bb0d
	"fmt"
Packit 63bb0d
	"strings"
Packit 63bb0d
Packit 63bb0d
	"github.com/vmware/govmomi/govc/cli"
Packit 63bb0d
	"github.com/vmware/govmomi/govc/flags"
Packit 63bb0d
	"github.com/vmware/govmomi/object"
Packit 63bb0d
	"github.com/vmware/govmomi/property"
Packit 63bb0d
	"github.com/vmware/govmomi/units"
Packit 63bb0d
	"github.com/vmware/govmomi/vim25"
Packit 63bb0d
	"github.com/vmware/govmomi/vim25/mo"
Packit 63bb0d
	"github.com/vmware/govmomi/vim25/types"
Packit 63bb0d
)
Packit 63bb0d
Packit 63bb0d
var hardwareVersions = []struct {
Packit 63bb0d
	esx, vmx string
Packit 63bb0d
}{
Packit 63bb0d
	{"5.0", "vmx-8"},
Packit 63bb0d
	{"5.5", "vmx-10"},
Packit 63bb0d
	{"6.0", "vmx-11"},
Packit 63bb0d
	{"6.5", "vmx-13"},
Packit 63bb0d
	{"6.7", "vmx-14"},
Packit 63bb0d
	{"7.0", "vmx-17"},
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
type create struct {
Packit 63bb0d
	*flags.ClientFlag
Packit 63bb0d
	*flags.ClusterFlag
Packit 63bb0d
	*flags.DatacenterFlag
Packit 63bb0d
	*flags.DatastoreFlag
Packit 63bb0d
	*flags.StoragePodFlag
Packit 63bb0d
	*flags.ResourcePoolFlag
Packit 63bb0d
	*flags.HostSystemFlag
Packit 63bb0d
	*flags.NetworkFlag
Packit 63bb0d
	*flags.FolderFlag
Packit 63bb0d
Packit 63bb0d
	name       string
Packit 63bb0d
	memory     int
Packit 63bb0d
	cpus       int
Packit 63bb0d
	guestID    string
Packit 63bb0d
	link       bool
Packit 63bb0d
	on         bool
Packit 63bb0d
	force      bool
Packit 63bb0d
	controller string
Packit 63bb0d
	annotation string
Packit 63bb0d
	firmware   string
Packit 63bb0d
	version    string
Packit 63bb0d
Packit 63bb0d
	iso              string
Packit 63bb0d
	isoDatastoreFlag *flags.DatastoreFlag
Packit 63bb0d
	isoDatastore     *object.Datastore
Packit 63bb0d
Packit 63bb0d
	disk              string
Packit 63bb0d
	diskDatastoreFlag *flags.DatastoreFlag
Packit 63bb0d
	diskDatastore     *object.Datastore
Packit 63bb0d
Packit 63bb0d
	// Only set if the disk argument is a byte size, which means the disk
Packit 63bb0d
	// doesn't exist yet and should be created
Packit 63bb0d
	diskByteSize int64
Packit 63bb0d
Packit 63bb0d
	Client       *vim25.Client
Packit 63bb0d
	Cluster      *object.ClusterComputeResource
Packit 63bb0d
	Datacenter   *object.Datacenter
Packit 63bb0d
	Datastore    *object.Datastore
Packit 63bb0d
	StoragePod   *object.StoragePod
Packit 63bb0d
	ResourcePool *object.ResourcePool
Packit 63bb0d
	HostSystem   *object.HostSystem
Packit 63bb0d
	Folder       *object.Folder
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func init() {
Packit 63bb0d
	cli.Register("vm.create", &create{})
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func (cmd *create) Register(ctx context.Context, f *flag.FlagSet) {
Packit 63bb0d
	cmd.ClientFlag, ctx = flags.NewClientFlag(ctx)
Packit 63bb0d
	cmd.ClientFlag.Register(ctx, f)
Packit 63bb0d
Packit 63bb0d
	cmd.ClusterFlag, ctx = flags.NewClusterFlag(ctx)
Packit 63bb0d
	cmd.ClusterFlag.RegisterPlacement(ctx, f)
Packit 63bb0d
Packit 63bb0d
	cmd.DatacenterFlag, ctx = flags.NewDatacenterFlag(ctx)
Packit 63bb0d
	cmd.DatacenterFlag.Register(ctx, f)
Packit 63bb0d
Packit 63bb0d
	cmd.DatastoreFlag, ctx = flags.NewDatastoreFlag(ctx)
Packit 63bb0d
	cmd.DatastoreFlag.Register(ctx, f)
Packit 63bb0d
Packit 63bb0d
	cmd.StoragePodFlag, ctx = flags.NewStoragePodFlag(ctx)
Packit 63bb0d
	cmd.StoragePodFlag.Register(ctx, f)
Packit 63bb0d
Packit 63bb0d
	cmd.ResourcePoolFlag, ctx = flags.NewResourcePoolFlag(ctx)
Packit 63bb0d
	cmd.ResourcePoolFlag.Register(ctx, f)
Packit 63bb0d
Packit 63bb0d
	cmd.HostSystemFlag, ctx = flags.NewHostSystemFlag(ctx)
Packit 63bb0d
	cmd.HostSystemFlag.Register(ctx, f)
Packit 63bb0d
Packit 63bb0d
	cmd.NetworkFlag, ctx = flags.NewNetworkFlag(ctx)
Packit 63bb0d
	cmd.NetworkFlag.Register(ctx, f)
Packit 63bb0d
Packit 63bb0d
	cmd.FolderFlag, ctx = flags.NewFolderFlag(ctx)
Packit 63bb0d
	cmd.FolderFlag.Register(ctx, f)
Packit 63bb0d
Packit 63bb0d
	f.IntVar(&cmd.memory, "m", 1024, "Size in MB of memory")
Packit 63bb0d
	f.IntVar(&cmd.cpus, "c", 1, "Number of CPUs")
Packit 63bb0d
	f.StringVar(&cmd.guestID, "g", "otherGuest", "Guest OS ID")
Packit 63bb0d
	f.BoolVar(&cmd.link, "link", true, "Link specified disk")
Packit 63bb0d
	f.BoolVar(&cmd.on, "on", true, "Power on VM")
Packit 63bb0d
	f.BoolVar(&cmd.force, "force", false, "Create VM if vmx already exists")
Packit 63bb0d
	f.StringVar(&cmd.controller, "disk.controller", "scsi", "Disk controller type")
Packit 63bb0d
	f.StringVar(&cmd.annotation, "annotation", "", "VM description")
Packit 63bb0d
Packit 63bb0d
	firmwareTypes := []string{
Packit 63bb0d
		string(types.GuestOsDescriptorFirmwareTypeBios),
Packit 63bb0d
		string(types.GuestOsDescriptorFirmwareTypeEfi),
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	f.StringVar(&cmd.firmware, "firmware", firmwareTypes[0],
Packit 63bb0d
		fmt.Sprintf("Firmware type [%s]", strings.Join(firmwareTypes, "|")))
Packit 63bb0d
	var versions []string
Packit 63bb0d
	for i := range hardwareVersions {
Packit 63bb0d
		versions = append(versions, hardwareVersions[i].esx)
Packit 63bb0d
	}
Packit 63bb0d
	f.StringVar(&cmd.version, "version", "",
Packit 63bb0d
		fmt.Sprintf("ESXi hardware version [%s]", strings.Join(versions, "|")))
Packit 63bb0d
Packit 63bb0d
	f.StringVar(&cmd.iso, "iso", "", "ISO path")
Packit 63bb0d
	cmd.isoDatastoreFlag, ctx = flags.NewCustomDatastoreFlag(ctx)
Packit 63bb0d
	f.StringVar(&cmd.isoDatastoreFlag.Name, "iso-datastore", "", "Datastore for ISO file")
Packit 63bb0d
Packit 63bb0d
	f.StringVar(&cmd.disk, "disk", "", "Disk path (to use existing) OR size (to create new, e.g. 20GB)")
Packit 63bb0d
	cmd.diskDatastoreFlag, _ = flags.NewCustomDatastoreFlag(ctx)
Packit 63bb0d
	f.StringVar(&cmd.diskDatastoreFlag.Name, "disk-datastore", "", "Datastore for disk file")
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func (cmd *create) Process(ctx context.Context) error {
Packit 63bb0d
	if err := cmd.ClientFlag.Process(ctx); err != nil {
Packit 63bb0d
		return err
Packit 63bb0d
	}
Packit 63bb0d
	if err := cmd.ClusterFlag.Process(ctx); err != nil {
Packit 63bb0d
		return err
Packit 63bb0d
	}
Packit 63bb0d
	if err := cmd.DatacenterFlag.Process(ctx); err != nil {
Packit 63bb0d
		return err
Packit 63bb0d
	}
Packit 63bb0d
	if err := cmd.DatastoreFlag.Process(ctx); err != nil {
Packit 63bb0d
		return err
Packit 63bb0d
	}
Packit 63bb0d
	if err := cmd.StoragePodFlag.Process(ctx); err != nil {
Packit 63bb0d
		return err
Packit 63bb0d
	}
Packit 63bb0d
	if err := cmd.ResourcePoolFlag.Process(ctx); err != nil {
Packit 63bb0d
		return err
Packit 63bb0d
	}
Packit 63bb0d
	if err := cmd.HostSystemFlag.Process(ctx); err != nil {
Packit 63bb0d
		return err
Packit 63bb0d
	}
Packit 63bb0d
	if err := cmd.NetworkFlag.Process(ctx); err != nil {
Packit 63bb0d
		return err
Packit 63bb0d
	}
Packit 63bb0d
	if err := cmd.FolderFlag.Process(ctx); err != nil {
Packit 63bb0d
		return err
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// Default iso/disk datastores to the VM's datastore
Packit 63bb0d
	if cmd.isoDatastoreFlag.Name == "" {
Packit 63bb0d
		cmd.isoDatastoreFlag = cmd.DatastoreFlag
Packit 63bb0d
	}
Packit 63bb0d
	if cmd.diskDatastoreFlag.Name == "" {
Packit 63bb0d
		cmd.diskDatastoreFlag = cmd.DatastoreFlag
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	return nil
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func (cmd *create) Usage() string {
Packit 63bb0d
	return "NAME"
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func (cmd *create) Description() string {
Packit 63bb0d
	return `Create VM.
Packit 63bb0d
Packit 63bb0d
For a list of possible '-g' IDs, use 'govc vm.option.info' or see:
Packit 63bb0d
https://code.vmware.com/apis/358/vsphere/doc/vim.vm.GuestOsDescriptor.GuestOsIdentifier.html
Packit 63bb0d
Packit 63bb0d
Examples:
Packit 63bb0d
  govc vm.create -on=false vm-name
Packit 63bb0d
  govc vm.create -cluster cluster1 vm-name # use compute cluster placement
Packit 63bb0d
  govc vm.create -datastore-cluster dscluster vm-name # use datastore cluster placement
Packit 63bb0d
  govc vm.create -m 2048 -c 2 -g freebsd64Guest -net.adapter vmxnet3 -disk.controller pvscsi vm-name`
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func (cmd *create) Run(ctx context.Context, f *flag.FlagSet) error {
Packit 63bb0d
	var err error
Packit 63bb0d
Packit 63bb0d
	if len(f.Args()) != 1 {
Packit 63bb0d
		return flag.ErrHelp
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	cmd.name = f.Arg(0)
Packit 63bb0d
	if cmd.name == "" {
Packit 63bb0d
		return flag.ErrHelp
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	cmd.Client, err = cmd.ClientFlag.Client()
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return err
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	cmd.Cluster, err = cmd.ClusterFlag.ClusterIfSpecified()
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return err
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	cmd.Datacenter, err = cmd.DatacenterFlag.Datacenter()
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return err
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	if cmd.StoragePodFlag.Isset() {
Packit 63bb0d
		cmd.StoragePod, err = cmd.StoragePodFlag.StoragePod()
Packit 63bb0d
		if err != nil {
Packit 63bb0d
			return err
Packit 63bb0d
		}
Packit 63bb0d
	} else if cmd.Cluster == nil {
Packit 63bb0d
		cmd.Datastore, err = cmd.DatastoreFlag.Datastore()
Packit 63bb0d
		if err != nil {
Packit 63bb0d
			return err
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	cmd.HostSystem, err = cmd.HostSystemFlag.HostSystemIfSpecified()
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return err
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	if cmd.HostSystem != nil {
Packit 63bb0d
		if cmd.ResourcePool, err = cmd.HostSystem.ResourcePool(ctx); err != nil {
Packit 63bb0d
			return err
Packit 63bb0d
		}
Packit 63bb0d
	} else {
Packit 63bb0d
		if cmd.Cluster == nil {
Packit 63bb0d
			// -host is optional
Packit 63bb0d
			if cmd.ResourcePool, err = cmd.ResourcePoolFlag.ResourcePool(); err != nil {
Packit 63bb0d
				return err
Packit 63bb0d
			}
Packit 63bb0d
		} else {
Packit 63bb0d
			if cmd.ResourcePool, err = cmd.Cluster.ResourcePool(ctx); err != nil {
Packit 63bb0d
				return err
Packit 63bb0d
			}
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	if cmd.Folder, err = cmd.FolderFlag.Folder(); err != nil {
Packit 63bb0d
		return err
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// Verify ISO exists
Packit 63bb0d
	if cmd.iso != "" {
Packit 63bb0d
		_, err = cmd.isoDatastoreFlag.Stat(ctx, cmd.iso)
Packit 63bb0d
		if err != nil {
Packit 63bb0d
			return err
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		cmd.isoDatastore, err = cmd.isoDatastoreFlag.Datastore()
Packit 63bb0d
		if err != nil {
Packit 63bb0d
			return err
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// Verify disk exists
Packit 63bb0d
	if cmd.disk != "" {
Packit 63bb0d
		var b units.ByteSize
Packit 63bb0d
Packit 63bb0d
		// If disk can be parsed as byte units, don't stat
Packit 63bb0d
		err = b.Set(cmd.disk)
Packit 63bb0d
		if err == nil {
Packit 63bb0d
			cmd.diskByteSize = int64(b)
Packit 63bb0d
		} else {
Packit 63bb0d
			_, err = cmd.diskDatastoreFlag.Stat(ctx, cmd.disk)
Packit 63bb0d
			if err != nil {
Packit 63bb0d
				return err
Packit 63bb0d
			}
Packit 63bb0d
Packit 63bb0d
			cmd.diskDatastore, err = cmd.diskDatastoreFlag.Datastore()
Packit 63bb0d
			if err != nil {
Packit 63bb0d
				return err
Packit 63bb0d
			}
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	task, err := cmd.createVM(ctx)
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return err
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	info, err := task.WaitForResult(ctx, nil)
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return err
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	vm := object.NewVirtualMachine(cmd.Client, info.Result.(types.ManagedObjectReference))
Packit 63bb0d
Packit 63bb0d
	if cmd.on {
Packit 63bb0d
		task, err := vm.PowerOn(ctx)
Packit 63bb0d
		if err != nil {
Packit 63bb0d
			return err
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		_, err = task.WaitForResult(ctx, nil)
Packit 63bb0d
		if err != nil {
Packit 63bb0d
			return err
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	return nil
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func (cmd *create) createVM(ctx context.Context) (*object.Task, error) {
Packit 63bb0d
	var devices object.VirtualDeviceList
Packit 63bb0d
	var err error
Packit 63bb0d
Packit 63bb0d
	if cmd.version != "" {
Packit 63bb0d
		for i := range hardwareVersions {
Packit 63bb0d
			if hardwareVersions[i].esx == cmd.version {
Packit 63bb0d
				cmd.version = hardwareVersions[i].vmx
Packit 63bb0d
				break
Packit 63bb0d
			}
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	spec := &types.VirtualMachineConfigSpec{
Packit 63bb0d
		Name:       cmd.name,
Packit 63bb0d
		GuestId:    cmd.guestID,
Packit 63bb0d
		NumCPUs:    int32(cmd.cpus),
Packit 63bb0d
		MemoryMB:   int64(cmd.memory),
Packit 63bb0d
		Annotation: cmd.annotation,
Packit 63bb0d
		Firmware:   cmd.firmware,
Packit 63bb0d
		Version:    cmd.version,
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	devices, err = cmd.addStorage(nil)
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return nil, err
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	devices, err = cmd.addNetwork(devices)
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return nil, err
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	deviceChange, err := devices.ConfigSpec(types.VirtualDeviceConfigSpecOperationAdd)
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return nil, err
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	spec.DeviceChange = deviceChange
Packit 63bb0d
Packit 63bb0d
	var datastore *object.Datastore
Packit 63bb0d
Packit 63bb0d
	// If storage pod is specified, collect placement recommendations
Packit 63bb0d
	if cmd.StoragePod != nil {
Packit 63bb0d
		datastore, err = cmd.recommendDatastore(ctx, spec)
Packit 63bb0d
		if err != nil {
Packit 63bb0d
			return nil, err
Packit 63bb0d
		}
Packit 63bb0d
	} else if cmd.Datastore != nil {
Packit 63bb0d
		datastore = cmd.Datastore
Packit 63bb0d
	} else if cmd.Cluster != nil {
Packit 63bb0d
		pspec := types.PlacementSpec{
Packit 63bb0d
			PlacementType: string(types.PlacementSpecPlacementTypeCreate),
Packit 63bb0d
			ConfigSpec:    spec,
Packit 63bb0d
		}
Packit 63bb0d
		result, err := cmd.Cluster.PlaceVm(ctx, pspec)
Packit 63bb0d
		if err != nil {
Packit 63bb0d
			return nil, err
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		recs := result.Recommendations
Packit 63bb0d
		if len(recs) == 0 {
Packit 63bb0d
			return nil, fmt.Errorf("no cluster recommendations")
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		rspec := *recs[0].Action[0].(*types.PlacementAction).RelocateSpec
Packit 63bb0d
		if rspec.Datastore != nil {
Packit 63bb0d
			datastore = object.NewDatastore(cmd.Client, *rspec.Datastore)
Packit 63bb0d
			datastore.InventoryPath, _ = datastore.ObjectName(ctx)
Packit 63bb0d
			cmd.Datastore = datastore
Packit 63bb0d
		}
Packit 63bb0d
		if rspec.Host != nil {
Packit 63bb0d
			cmd.HostSystem = object.NewHostSystem(cmd.Client, *rspec.Host)
Packit 63bb0d
		}
Packit 63bb0d
		if rspec.Pool != nil {
Packit 63bb0d
			cmd.ResourcePool = object.NewResourcePool(cmd.Client, *rspec.Pool)
Packit 63bb0d
		}
Packit 63bb0d
	} else {
Packit 63bb0d
		return nil, fmt.Errorf("please provide either a cluster, datastore or datastore-cluster")
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	if !cmd.force {
Packit 63bb0d
		vmxPath := fmt.Sprintf("%s/%s.vmx", cmd.name, cmd.name)
Packit 63bb0d
Packit 63bb0d
		_, err := datastore.Stat(ctx, vmxPath)
Packit 63bb0d
		if err == nil {
Packit 63bb0d
			dsPath := cmd.Datastore.Path(vmxPath)
Packit 63bb0d
			return nil, fmt.Errorf("file %s already exists", dsPath)
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	folder := cmd.Folder
Packit 63bb0d
Packit 63bb0d
	spec.Files = &types.VirtualMachineFileInfo{
Packit 63bb0d
		VmPathName: fmt.Sprintf("[%s]", datastore.Name()),
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	return folder.CreateVM(ctx, *spec, cmd.ResourcePool, cmd.HostSystem)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func (cmd *create) addStorage(devices object.VirtualDeviceList) (object.VirtualDeviceList, error) {
Packit 63bb0d
	if cmd.controller != "ide" {
Packit 63bb0d
		if cmd.controller == "nvme" {
Packit 63bb0d
			nvme, err := devices.CreateNVMEController()
Packit 63bb0d
			if err != nil {
Packit 63bb0d
				return nil, err
Packit 63bb0d
			}
Packit 63bb0d
Packit 63bb0d
			devices = append(devices, nvme)
Packit 63bb0d
			cmd.controller = devices.Name(nvme)
Packit 63bb0d
		} else {
Packit 63bb0d
			scsi, err := devices.CreateSCSIController(cmd.controller)
Packit 63bb0d
			if err != nil {
Packit 63bb0d
				return nil, err
Packit 63bb0d
			}
Packit 63bb0d
Packit 63bb0d
			devices = append(devices, scsi)
Packit 63bb0d
			cmd.controller = devices.Name(scsi)
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// If controller is specified to be IDE or if an ISO is specified, add IDE controller.
Packit 63bb0d
	if cmd.controller == "ide" || cmd.iso != "" {
Packit 63bb0d
		ide, err := devices.CreateIDEController()
Packit 63bb0d
		if err != nil {
Packit 63bb0d
			return nil, err
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		devices = append(devices, ide)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	if cmd.diskByteSize != 0 {
Packit 63bb0d
		controller, err := devices.FindDiskController(cmd.controller)
Packit 63bb0d
		if err != nil {
Packit 63bb0d
			return nil, err
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		disk := &types.VirtualDisk{
Packit 63bb0d
			VirtualDevice: types.VirtualDevice{
Packit 63bb0d
				Key: devices.NewKey(),
Packit 63bb0d
				Backing: &types.VirtualDiskFlatVer2BackingInfo{
Packit 63bb0d
					DiskMode:        string(types.VirtualDiskModePersistent),
Packit 63bb0d
					ThinProvisioned: types.NewBool(true),
Packit 63bb0d
				},
Packit 63bb0d
			},
Packit 63bb0d
			CapacityInKB: cmd.diskByteSize / 1024,
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		devices.AssignController(disk, controller)
Packit 63bb0d
		devices = append(devices, disk)
Packit 63bb0d
	} else if cmd.disk != "" {
Packit 63bb0d
		controller, err := devices.FindDiskController(cmd.controller)
Packit 63bb0d
		if err != nil {
Packit 63bb0d
			return nil, err
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		ds := cmd.diskDatastore.Reference()
Packit 63bb0d
		path := cmd.diskDatastore.Path(cmd.disk)
Packit 63bb0d
		disk := devices.CreateDisk(controller, ds, path)
Packit 63bb0d
Packit 63bb0d
		if cmd.link {
Packit 63bb0d
			disk = devices.ChildDisk(disk)
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		devices = append(devices, disk)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	if cmd.iso != "" {
Packit 63bb0d
		ide, err := devices.FindIDEController("")
Packit 63bb0d
		if err != nil {
Packit 63bb0d
			return nil, err
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		cdrom, err := devices.CreateCdrom(ide)
Packit 63bb0d
		if err != nil {
Packit 63bb0d
			return nil, err
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		cdrom = devices.InsertIso(cdrom, cmd.isoDatastore.Path(cmd.iso))
Packit 63bb0d
		devices = append(devices, cdrom)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	return devices, nil
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func (cmd *create) addNetwork(devices object.VirtualDeviceList) (object.VirtualDeviceList, error) {
Packit 63bb0d
	netdev, err := cmd.NetworkFlag.Device()
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return nil, err
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	devices = append(devices, netdev)
Packit 63bb0d
	return devices, nil
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func (cmd *create) recommendDatastore(ctx context.Context, spec *types.VirtualMachineConfigSpec) (*object.Datastore, error) {
Packit 63bb0d
	sp := cmd.StoragePod.Reference()
Packit 63bb0d
Packit 63bb0d
	// Build pod selection spec from config spec
Packit 63bb0d
	podSelectionSpec := types.StorageDrsPodSelectionSpec{
Packit 63bb0d
		StoragePod: &sp,
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// Keep list of disks that need to be placed
Packit 63bb0d
	var disks []*types.VirtualDisk
Packit 63bb0d
Packit 63bb0d
	// Collect disks eligible for placement
Packit 63bb0d
	for _, deviceConfigSpec := range spec.DeviceChange {
Packit 63bb0d
		s := deviceConfigSpec.GetVirtualDeviceConfigSpec()
Packit 63bb0d
		if s.Operation != types.VirtualDeviceConfigSpecOperationAdd {
Packit 63bb0d
			continue
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		if s.FileOperation != types.VirtualDeviceConfigSpecFileOperationCreate {
Packit 63bb0d
			continue
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		d, ok := s.Device.(*types.VirtualDisk)
Packit 63bb0d
		if !ok {
Packit 63bb0d
			continue
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		podConfigForPlacement := types.VmPodConfigForPlacement{
Packit 63bb0d
			StoragePod: sp,
Packit 63bb0d
			Disk: []types.PodDiskLocator{
Packit 63bb0d
				{
Packit 63bb0d
					DiskId:          d.Key,
Packit 63bb0d
					DiskBackingInfo: d.Backing,
Packit 63bb0d
				},
Packit 63bb0d
			},
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		podSelectionSpec.InitialVmConfig = append(podSelectionSpec.InitialVmConfig, podConfigForPlacement)
Packit 63bb0d
		disks = append(disks, d)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	sps := types.StoragePlacementSpec{
Packit 63bb0d
		Type:             string(types.StoragePlacementSpecPlacementTypeCreate),
Packit 63bb0d
		ResourcePool:     types.NewReference(cmd.ResourcePool.Reference()),
Packit 63bb0d
		PodSelectionSpec: podSelectionSpec,
Packit 63bb0d
		ConfigSpec:       spec,
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	srm := object.NewStorageResourceManager(cmd.Client)
Packit 63bb0d
	result, err := srm.RecommendDatastores(ctx, sps)
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return nil, err
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// Use result to pin disks to recommended datastores
Packit 63bb0d
	recs := result.Recommendations
Packit 63bb0d
	if len(recs) == 0 {
Packit 63bb0d
		return nil, fmt.Errorf("no datastore-cluster recommendations")
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	ds := recs[0].Action[0].(*types.StoragePlacementAction).Destination
Packit 63bb0d
Packit 63bb0d
	var mds mo.Datastore
Packit 63bb0d
	err = property.DefaultCollector(cmd.Client).RetrieveOne(ctx, ds, []string{"name"}, &mds)
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return nil, err
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	datastore := object.NewDatastore(cmd.Client, ds)
Packit 63bb0d
	datastore.InventoryPath = mds.Name
Packit 63bb0d
Packit 63bb0d
	// Apply recommendation to eligible disks
Packit 63bb0d
	for _, disk := range disks {
Packit 63bb0d
		backing := disk.Backing.(*types.VirtualDiskFlatVer2BackingInfo)
Packit 63bb0d
		backing.Datastore = &ds
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	return datastore, nil
Packit 63bb0d
}