Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vcsim: add PlaceVm support #1589

Merged
merged 3 commits into from
Sep 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 24 additions & 7 deletions govc/test/vm.bats
Original file line number Diff line number Diff line change
Expand Up @@ -57,18 +57,28 @@ load test_helper
}

@test "vm.create" {
esx_env
unset GOVC_DATASTORE
vcsim_start

id=$(new_ttylinux_vm)
run govc cluster.create empty-cluster
assert_success

run govc vm.power -on $id
id=$(new_id)
run govc vm.create -on=false "$id"
assert_failure # -pool must be specified

run govc vm.create -pool DC0_C0/Resources "$id"
assert_success

result=$(govc device.ls -vm $vm | grep disk- | wc -l)
[ $result -eq 0 ]
id=$(new_id)
run govc vm.create -cluster enoent "$id"
assert_failure # cluster does not exist

result=$(govc device.ls -vm $vm | grep cdrom- | wc -l)
[ $result -eq 0 ]
run govc vm.create -cluster empty-cluster "$id"
assert_failure # cluster has no hosts

run govc vm.create -cluster DC0_C0 "$id"
assert_success
}

@test "vm.change" {
Expand Down Expand Up @@ -664,6 +674,13 @@ load test_helper

run govc vm.clone -vm "$vm" -snapshot X "$clone"
assert_success

clone=$(new_id)
run govc vm.clone -cluster enoent -vm "$vm" "$clone"
assert_failure

run govc vm.clone -cluster DC0_C0 -vm "$vm" "$clone"
assert_success
}

@test "vm.clone change resources" {
Expand Down
59 changes: 50 additions & 9 deletions govc/vm/clone.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (

type clone struct {
*flags.ClientFlag
*flags.ClusterFlag
*flags.DatacenterFlag
*flags.DatastoreFlag
*flags.StoragePodFlag
Expand All @@ -54,6 +55,7 @@ type clone struct {
link bool

Client *vim25.Client
Cluster *object.ClusterComputeResource
Datacenter *object.Datacenter
Datastore *object.Datastore
StoragePod *object.StoragePod
Expand All @@ -71,6 +73,9 @@ func (cmd *clone) Register(ctx context.Context, f *flag.FlagSet) {
cmd.ClientFlag, ctx = flags.NewClientFlag(ctx)
cmd.ClientFlag.Register(ctx, f)

cmd.ClusterFlag, ctx = flags.NewClusterFlag(ctx)
cmd.ClusterFlag.Register(ctx, f)

cmd.DatacenterFlag, ctx = flags.NewDatacenterFlag(ctx)
cmd.DatacenterFlag.Register(ctx, f)

Expand Down Expand Up @@ -119,13 +124,18 @@ Examples:
govc vm.clone -vm template-vm -link new-vm
govc vm.clone -vm template-vm -snapshot s-name new-vm
govc vm.clone -vm template-vm -link -snapshot s-name new-vm
govc vm.clone -vm template-vm -cluster cluster1 new-vm # use compute cluster placement
govc vm.clone -vm template-vm -datastore-cluster dscluster new-vm # use datastore cluster placement
govc vm.clone -vm template-vm -snapshot $(govc snapshot.tree -vm template-vm -C) new-vm`
}

func (cmd *clone) Process(ctx context.Context) error {
if err := cmd.ClientFlag.Process(ctx); err != nil {
return err
}
if err := cmd.ClusterFlag.Process(ctx); err != nil {
return err
}
if err := cmd.DatacenterFlag.Process(ctx); err != nil {
return err
}
Expand Down Expand Up @@ -171,6 +181,11 @@ func (cmd *clone) Run(ctx context.Context, f *flag.FlagSet) error {
return err
}

cmd.Cluster, err = cmd.ClusterFlag.ClusterIfSpecified()
if err != nil {
return err
}

cmd.Datacenter, err = cmd.DatacenterFlag.Datacenter()
if err != nil {
return err
Expand All @@ -181,7 +196,7 @@ func (cmd *clone) Run(ctx context.Context, f *flag.FlagSet) error {
if err != nil {
return err
}
} else {
} else if cmd.Cluster == nil {
cmd.Datastore, err = cmd.DatastoreFlag.Datastore()
if err != nil {
return err
Expand All @@ -198,9 +213,15 @@ func (cmd *clone) Run(ctx context.Context, f *flag.FlagSet) error {
return err
}
} else {
// -host is optional
if cmd.ResourcePool, err = cmd.ResourcePoolFlag.ResourcePool(); err != nil {
return err
if cmd.Cluster == nil {
// -host is optional
if cmd.ResourcePool, err = cmd.ResourcePoolFlag.ResourcePool(); err != nil {
return err
}
} else {
if cmd.ResourcePool, err = cmd.Cluster.ResourcePool(ctx); err != nil {
return err
}
}
}

Expand Down Expand Up @@ -331,6 +352,7 @@ func (cmd *clone) cloneVM(ctx context.Context) (*object.VirtualMachine, error) {
}

cloneSpec.Location = relocateSpec
vmref := cmd.VirtualMachine.Reference()

// clone to storage pod
datastoreref := types.ManagedObjectReference{}
Expand All @@ -342,9 +364,6 @@ func (cmd *clone) cloneVM(ctx context.Context) (*object.VirtualMachine, error) {
StoragePod: &storagePod,
}

// Get the virtual machine reference
vmref := cmd.VirtualMachine.Reference()

// Build the placement spec
storagePlacementSpec := types.StoragePlacementSpec{
Folder: &folderref,
Expand All @@ -365,15 +384,37 @@ func (cmd *clone) cloneVM(ctx context.Context) (*object.VirtualMachine, error) {
// Get the recommendations
recommendations := result.Recommendations
if len(recommendations) == 0 {
return nil, fmt.Errorf("no recommendations")
return nil, fmt.Errorf("no datastore-cluster recommendations")
}

// Get the first recommendation
datastoreref = recommendations[0].Action[0].(*types.StoragePlacementAction).Destination
} else if cmd.StoragePod == nil && cmd.Datastore != nil {
datastoreref = cmd.Datastore.Reference()
} else if cmd.Cluster != nil {
spec := types.PlacementSpec{
PlacementType: string(types.PlacementSpecPlacementTypeClone),
CloneName: cmd.name,
CloneSpec: cloneSpec,
RelocateSpec: &cloneSpec.Location,
Vm: &vmref,
}
result, err := cmd.Cluster.PlaceVm(ctx, spec)
if err != nil {
return nil, err
}

recs := result.Recommendations
if len(recs) == 0 {
return nil, fmt.Errorf("no cluster recommendations")
}

rspec := *recs[0].Action[0].(*types.PlacementAction).RelocateSpec
cloneSpec.Location.Host = rspec.Host
cloneSpec.Location.Datastore = rspec.Datastore
datastoreref = *rspec.Datastore
} else {
return nil, fmt.Errorf("please provide either a datastore or a storagepod")
return nil, fmt.Errorf("please provide either a cluster, datastore or datastore-cluster")
}

// Set the destination datastore
Expand Down
62 changes: 56 additions & 6 deletions govc/vm/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ var hardwareVersions = []struct {

type create struct {
*flags.ClientFlag
*flags.ClusterFlag
*flags.DatacenterFlag
*flags.DatastoreFlag
*flags.StoragePodFlag
Expand Down Expand Up @@ -76,6 +77,7 @@ type create struct {
diskByteSize int64

Client *vim25.Client
Cluster *object.ClusterComputeResource
Datacenter *object.Datacenter
Datastore *object.Datastore
StoragePod *object.StoragePod
Expand All @@ -92,6 +94,9 @@ func (cmd *create) Register(ctx context.Context, f *flag.FlagSet) {
cmd.ClientFlag, ctx = flags.NewClientFlag(ctx)
cmd.ClientFlag.Register(ctx, f)

cmd.ClusterFlag, ctx = flags.NewClusterFlag(ctx)
cmd.ClusterFlag.Register(ctx, f)

cmd.DatacenterFlag, ctx = flags.NewDatacenterFlag(ctx)
cmd.DatacenterFlag.Register(ctx, f)

Expand Down Expand Up @@ -149,6 +154,9 @@ func (cmd *create) Process(ctx context.Context) error {
if err := cmd.ClientFlag.Process(ctx); err != nil {
return err
}
if err := cmd.ClusterFlag.Process(ctx); err != nil {
return err
}
if err := cmd.DatacenterFlag.Process(ctx); err != nil {
return err
}
Expand Down Expand Up @@ -194,6 +202,8 @@ http://pubs.vmware.com/vsphere-6-5/topic/com.vmware.wssdk.apiref.doc/vim.vm.Gues

Examples:
govc vm.create vm-name
govc vm.create -cluster cluster1 vm-name # use compute cluster placement
govc vm.create -datastore-cluster dscluster vm-name # use datastore cluster placement
govc vm.create -m 2048 -c 2 -g freebsd64Guest -net.adapter vmxnet3 -disk.controller pvscsi vm-name`
}

Expand All @@ -214,6 +224,11 @@ func (cmd *create) Run(ctx context.Context, f *flag.FlagSet) error {
return err
}

cmd.Cluster, err = cmd.ClusterFlag.ClusterIfSpecified()
if err != nil {
return err
}

cmd.Datacenter, err = cmd.DatacenterFlag.Datacenter()
if err != nil {
return err
Expand All @@ -224,7 +239,7 @@ func (cmd *create) Run(ctx context.Context, f *flag.FlagSet) error {
if err != nil {
return err
}
} else {
} else if cmd.Cluster == nil {
cmd.Datastore, err = cmd.DatastoreFlag.Datastore()
if err != nil {
return err
Expand All @@ -241,9 +256,15 @@ func (cmd *create) Run(ctx context.Context, f *flag.FlagSet) error {
return err
}
} else {
// -host is optional
if cmd.ResourcePool, err = cmd.ResourcePoolFlag.ResourcePool(); err != nil {
return err
if cmd.Cluster == nil {
// -host is optional
if cmd.ResourcePool, err = cmd.ResourcePoolFlag.ResourcePool(); err != nil {
return err
}
} else {
if cmd.ResourcePool, err = cmd.Cluster.ResourcePool(ctx); err != nil {
return err
}
}
}

Expand Down Expand Up @@ -360,8 +381,37 @@ func (cmd *create) createVM(ctx context.Context) (*object.Task, error) {
if err != nil {
return nil, err
}
} else {
} else if cmd.Datastore != nil {
datastore = cmd.Datastore
} else if cmd.Cluster != nil {
pspec := types.PlacementSpec{
PlacementType: string(types.PlacementSpecPlacementTypeCreate),
ConfigSpec: spec,
}
result, err := cmd.Cluster.PlaceVm(ctx, pspec)
if err != nil {
return nil, err
}

recs := result.Recommendations
if len(recs) == 0 {
return nil, fmt.Errorf("no cluster recommendations")
}

rspec := *recs[0].Action[0].(*types.PlacementAction).RelocateSpec
if rspec.Datastore != nil {
datastore = object.NewDatastore(cmd.Client, *rspec.Datastore)
datastore.InventoryPath, _ = datastore.ObjectName(ctx)
cmd.Datastore = datastore
}
if rspec.Host != nil {
cmd.HostSystem = object.NewHostSystem(cmd.Client, *rspec.Host)
}
if rspec.Pool != nil {
cmd.ResourcePool = object.NewResourcePool(cmd.Client, *rspec.Pool)
}
} else {
return nil, fmt.Errorf("please provide either a cluster, datastore or datastore-cluster")
}

if !cmd.force {
Expand Down Expand Up @@ -535,7 +585,7 @@ func (cmd *create) recommendDatastore(ctx context.Context, spec *types.VirtualMa
// Use result to pin disks to recommended datastores
recs := result.Recommendations
if len(recs) == 0 {
return nil, fmt.Errorf("no recommendations")
return nil, fmt.Errorf("no datastore-cluster recommendations")
}

ds := recs[0].Action[0].(*types.StoragePlacementAction).Destination
Expand Down
14 changes: 14 additions & 0 deletions object/cluster_compute_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,17 @@ func (c ClusterComputeResource) MoveInto(ctx context.Context, hosts ...*HostSyst

return NewTask(c.c, res.Returnval), nil
}

func (c ClusterComputeResource) PlaceVm(ctx context.Context, spec types.PlacementSpec) (*types.PlacementResult, error) {
req := types.PlaceVm{
This: c.Reference(),
PlacementSpec: spec,
}

res, err := methods.PlaceVm(ctx, c.c, &req)
if err != nil {
return nil, err
}

return &res.Returnval, nil
}
Loading