func TestCreateVm(t *testing.T) { ctx := context.Background() for _, model := range []*Model{ESX(), VPX()} { defer model.Remove() err := model.Create() if err != nil { t.Fatal(err) } s := model.Service.NewServer() defer s.Close() c, err := govmomi.NewClient(ctx, s.URL, true) if err != nil { t.Fatal(err) } spec := types.VirtualMachineConfigSpec{ // Note: real ESX allows the VM to be created without a GuestId, // but will power on will fail. GuestId: string(types.VirtualMachineGuestOsIdentifierOtherGuest), } steps := []func(){ func() { spec.Name = "test" }, func() { spec.Files = &types.VirtualMachineFileInfo{ VmPathName: fmt.Sprintf("[LocalDS_0] %s/%s.vmx", spec.Name, spec.Name), } }, } finder := find.NewFinder(c.Client, false) dc, err := finder.DefaultDatacenter(ctx) if err != nil { t.Fatal(err) } finder.SetDatacenter(dc) folders, err := dc.Folders(ctx) if err != nil { t.Fatal(err) } hosts, err := finder.HostSystemList(ctx, "*/*") if err != nil { t.Fatal(err) } nhosts := len(hosts) host := hosts[rand.Intn(nhosts)] pool, err := host.ResourcePool(ctx) if err != nil { t.Fatal(err) } if nhosts == 1 { // test the default path against the ESX model host = nil } vmFolder := folders.VmFolder // expecting CreateVM to fail until all steps are taken for _, step := range steps { task, cerr := vmFolder.CreateVM(ctx, spec, pool, host) if cerr != nil { t.Fatal(err) } _, cerr = task.WaitForResult(ctx, nil) if cerr == nil { t.Error("expected error") } step() } task, err := vmFolder.CreateVM(ctx, spec, pool, host) if err != nil { t.Fatal(err) } info, err := task.WaitForResult(ctx, nil) if err != nil { t.Fatal(err) } vm := object.NewVirtualMachine(c.Client, info.Result.(types.ManagedObjectReference)) name, err := vm.ObjectName(ctx) if err != nil { t.Fatal(err) } if name != spec.Name { t.Errorf("name=%s", name) } _, err = vm.Device(ctx) if err != nil { t.Fatal(err) } recreate := func(context.Context) (*object.Task, error) { return vmFolder.CreateVM(ctx, spec, pool, nil) } ops := []struct { method func(context.Context) (*object.Task, error) state types.VirtualMachinePowerState fail bool }{ // Powered off by default {nil, types.VirtualMachinePowerStatePoweredOff, false}, // Create with same .vmx path should fail {recreate, "", true}, // Off -> On == ok {vm.PowerOn, types.VirtualMachinePowerStatePoweredOn, false}, // On -> On == fail {vm.PowerOn, types.VirtualMachinePowerStatePoweredOn, true}, // On -> Off == ok {vm.PowerOff, types.VirtualMachinePowerStatePoweredOff, false}, // Off -> Off == fail {vm.PowerOff, types.VirtualMachinePowerStatePoweredOff, true}, // Off -> On == ok {vm.PowerOn, types.VirtualMachinePowerStatePoweredOn, false}, // Destroy == fail (power is On) {vm.Destroy, types.VirtualMachinePowerStatePoweredOn, true}, // On -> Off == ok {vm.PowerOff, types.VirtualMachinePowerStatePoweredOff, false}, // Destroy == ok (power is Off) {vm.Destroy, "", false}, } for i, op := range ops { if op.method != nil { task, err = op.method(ctx) if err != nil { t.Fatal(err) } err = task.Wait(ctx) if op.fail { if err == nil { t.Errorf("%d: expected error", i) } } else { if err != nil { t.Errorf("%d: %s", i, err) } } } if len(op.state) != 0 { state, err := vm.PowerState(ctx) if err != nil { t.Fatal(err) } if state != op.state { t.Errorf("state=%s", state) } } } } }