// NewVMHost connects to a ESXi or vCenter instance and returns a *VMHost func NewVMHost(insecure bool, hostURL_param, user, pass string) (*VMHost, error) { ctx, _ := context.WithCancel(context.Background()) hostURL, err := url.Parse("https://" + hostURL_param + "/sdk") hostURL.User = url.UserPassword(user, pass) cli, err := govmomi.NewClient(ctx, hostURL, insecure) if err != nil { return nil, err } mac, err := getLocalMAC() if err != nil { return nil, err } vmh := &VMHost{ client: cli, Ctx: ctx, mac: mac, } vm, err := vmh.findVM(vmh.mac) if err != nil { return nil, err } vmh.Vm = vm return vmh, nil }
func TestClusterESX(t *testing.T) { content := esx.ServiceContent s := New(NewServiceInstance(content, esx.RootFolder)) ts := s.NewServer() defer ts.Close() ctx := context.Background() c, err := govmomi.NewClient(ctx, ts.URL, true) if err != nil { t.Fatal(err) } dc := object.NewDatacenter(c.Client, esx.Datacenter.Reference()) folders, err := dc.Folders(ctx) if err != nil { t.Fatal(err) } _, err = folders.HostFolder.CreateCluster(ctx, "cluster1", types.ClusterConfigSpecEx{}) if err == nil { t.Fatal("expected error") } }
func TestClusterVC(t *testing.T) { content := vc.ServiceContent s := New(NewServiceInstance(content, vc.RootFolder)) ts := s.NewServer() defer ts.Close() ctx := context.Background() c, err := govmomi.NewClient(ctx, ts.URL, true) if err != nil { t.Fatal(err) } f := object.NewRootFolder(c.Client) dc, err := f.CreateDatacenter(ctx, "foo") if err != nil { t.Error(err) } folders, err := dc.Folders(ctx) if err != nil { t.Fatal(err) } cluster, err := folders.HostFolder.CreateCluster(ctx, "cluster1", types.ClusterConfigSpecEx{}) if err != nil { t.Fatal(err) } _, err = folders.HostFolder.CreateCluster(ctx, "cluster1", types.ClusterConfigSpecEx{}) if err == nil { t.Error("expected DuplicateName error") } spec := types.HostConnectSpec{} for _, fail := range []bool{true, false} { task, err := cluster.AddHost(ctx, spec, true, nil, nil) if err != nil { t.Fatal(err) } _, err = task.WaitForResult(ctx, nil) if fail { if err == nil { t.Error("expected error") } spec.HostName = "localhost" } else { if err != nil { t.Error(err) } } } }
func TestWaitForUpdates(t *testing.T) { folder := esx.RootFolder s := New(NewServiceInstance(esx.ServiceContent, folder)) ts := s.NewServer() defer ts.Close() ctx := context.Background() c, err := govmomi.NewClient(ctx, ts.URL, true) if err != nil { t.Fatal(err) } cb := func(once bool) func([]types.PropertyChange) bool { return func(pc []types.PropertyChange) bool { if len(pc) != 1 { t.Fail() } c := pc[0] if c.Op != types.PropertyChangeOpAssign { t.Fail() } if c.Name != "name" { t.Fail() } if c.Val.(string) != folder.Name { t.Fail() } return once } } pc := property.DefaultCollector(c.Client) props := []string{"name"} err = property.Wait(ctx, pc, folder.Reference(), props, cb(true)) if err != nil { t.Error(err) } // incremental updates not yet suppported err = property.Wait(ctx, pc, folder.Reference(), props, cb(false)) if err == nil { t.Error("expected error") } // test object not found Map.Remove(folder.Reference()) err = property.Wait(ctx, pc, folder.Reference(), props, cb(true)) if err == nil { t.Error("expected error") } }
// Connect establishes the connection for the session but nothing more func (s *Session) Connect(ctx context.Context) (*Session, error) { soapURL, err := soap.ParseURL(s.Service) if soapURL == nil || err != nil { return nil, errors.Errorf("SDK URL (%s) could not be parsed: %s", s.Service, err) } // update the service URL with the resolved soapURL s.Service = soapURL.String() // we can't set a keep alive if we log in directly with client creation user := soapURL.User soapURL.User = nil // 1st connect without any userinfo to get the API type s.Client, err = govmomi.NewClient(ctx, soapURL, s.Insecure) if err != nil { return nil, errors.Errorf("Failed to connect to %s: %s", soapURL.String(), err) } if s.HasCertificate() && s.Client.IsVC() { // load the certificates cert, err2 := tls.X509KeyPair([]byte(s.ExtensionCert), []byte(s.ExtensionKey)) if err2 != nil { return nil, errors.Errorf("Unable to load X509 key pair(%s,%s): %s", s.ExtensionCert, s.ExtensionKey, err2) } // create the new client s.Client, err = govmomi.NewClientWithCertificate(ctx, soapURL, s.Insecure, cert) if err != nil { return nil, errors.Errorf("Failed to connect to %s: %s", soapURL.String(), err) } } if s.Keepalive != 0 { // now that we've verified everything, enable keepalive s.RoundTripper = session.KeepAlive(s.Client.RoundTripper, s.Keepalive) } // and now that the keepalive is registered we can log in to trigger it if !s.IsVC() || !s.HasCertificate() { log.Debugf("Trying to log in with username/password in lieu of cert") err = s.Client.Login(ctx, user) } else { log.Debugf("Logging into extension %s", s.ExtensionName) err = s.LoginExtensionByCertificate(ctx, s.ExtensionName, "") } if err != nil { return nil, errors.Errorf("Failed to log in to %s: %s", soapURL.String(), err) } s.Finder = find.NewFinder(s.Vim25(), true) // log high-level environement information s.logEnvironmentInfo() return s, nil }
func (i *vSphereInstanceManager) createClient(ctx context.Context) (*govmomi.Client, error) { client, err := govmomi.NewClient(ctx, i.vSphereURL, true) if err != nil { return nil, err } client.Client.RoundTripper = vim25.Retry(client.Client.RoundTripper, vim25.TemporaryNetworkError(3)) return client, nil }
func TestServeHTTP(t *testing.T) { configs := []struct { content types.ServiceContent folder mo.Folder }{ {esx.ServiceContent, esx.RootFolder}, {vc.ServiceContent, vc.RootFolder}, } for _, config := range configs { s := New(NewServiceInstance(config.content, config.folder)) ts := s.NewServer() defer ts.Close() ctx := context.Background() client, err := govmomi.NewClient(ctx, ts.URL, true) if err != nil { t.Fatal(err) } err = client.Login(ctx, nil) if err == nil { t.Fatal("expected invalid login error") } err = client.Login(ctx, url.UserPassword("user", "pass")) if err != nil { t.Fatal(err) } // Testing http client + reflect client clients := []soap.RoundTripper{client, s.client} for _, c := range clients { now, err := methods.GetCurrentTime(ctx, c) if err != nil { t.Fatal(err) } if now.After(time.Now()) { t.Fail() } // test the fail/Fault path _, err = methods.QueryVMotionCompatibility(ctx, c, &types.QueryVMotionCompatibility{}) if err == nil { t.Errorf("expected error") } } err = client.Logout(ctx) if err != nil { t.Error(err) } } }
func (c *Config) Client() (*vim25.Client, error) { u, err := url.Parse(fmt.Sprintf("https://%s:%s@%s/sdk", c.User, c.Password, c.vCenter)) if err != nil { return nil, fmt.Errorf("Incorrect vCenter server address: %s", err) } client, err := govmomi.NewClient(context.TODO(), u, c.Insecure) if err != nil { return nil, fmt.Errorf("Error setting up client: %s", err) } log.Printf("[INFO] vSphere Client configured") return client.Client, nil }
func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() flag.Parse() // Parse URL from string u, err := url.Parse(*urlFlag) if err != nil { exit(err) } fmt.Println("u:", u) // Override username and/or password as required processOverride(u) // Connect and log in to ESX or vCenter client, err := govmomi.NewClient(ctx, u, *insecureFlag) if err != nil { exit(err) } if client.IsVC() { fmt.Println("connected to vCenter") } else { fmt.Println("connected to ESXi host") } var perfManager mo.PerformanceManager err = client.RetrieveOne(ctx, *client.ServiceContent.PerfManager, nil, &perfManager) perfCounters := perfManager.PerfCounter counterDetails := make([][]string, 0) for _, perfCounter := range perfCounters { groupInfo := perfCounter.GroupInfo.GetElementDescription() nameInfo := perfCounter.NameInfo.GetElementDescription() fullName := groupInfo.Key + "." + nameInfo.Key + "." + fmt.Sprint(perfCounter.RollupType) counterDetails = append(counterDetails, []string{fullName, fmt.Sprint(perfCounter.Level), nameInfo.Summary}) } outputFile, err := os.Create("performanceCounters.csv") csvWriter := csv.NewWriter(outputFile) csvWriter.WriteAll(counterDetails) if err := csvWriter.Error(); err != nil { log.Fatalln("error writing csv:", err) } }
// Initialize establishes a connection to the remote vSphere API endpoint. func (bv *BaseVSphere) Initialize() error { bv.ctx, bv.cancel = context.WithCancel(context.Background()) // Connect and login to the VMWare vSphere API endpoint c, err := govmomi.NewClient(bv.ctx, bv.url, bv.Insecure) if err != nil { return err } bv.client = c bv.finder = find.NewFinder(bv.client.Client, true) return nil }
// Client() returns a new client for accessing VMWare vSphere. func (c *Config) Client() (*govmomi.Client, error) { u, err := url.Parse("https://" + c.VSphereServer + "/sdk") if err != nil { return nil, fmt.Errorf("Error parse url: %s", err) } u.User = url.UserPassword(c.User, c.Password) client, err := govmomi.NewClient(context.TODO(), u, c.InsecureFlag) if err != nil { return nil, fmt.Errorf("Error setting up client: %s", err) } log.Printf("[INFO] VMWare vSphere Client configured for URL: %s", u) return client, nil }
// Returns a client which communicates with vCenter. // This client can used to perform further vCenter operations. func vsphereLogin(cfg *VSphereConfig, ctx context.Context) (*govmomi.Client, error) { // Parse URL from string u, err := url.Parse(fmt.Sprintf("https://%s:%s/sdk", cfg.Global.VCenterIP, cfg.Global.VCenterPort)) if err != nil { return nil, err } // set username and password for the URL u.User = url.UserPassword(cfg.Global.User, cfg.Global.Password) // Connect and log in to ESX or vCenter c, err := govmomi.NewClient(ctx, u, cfg.Global.InsecureFlag) if err != nil { return nil, err } return c, nil }
func (d *Driver) vsphereLogin(ctx context.Context) (*govmomi.Client, error) { // Parse URL from string u, err := url.Parse(fmt.Sprintf("https://%s:%d/sdk", d.IP, d.Port)) if err != nil { return nil, err } // set username and password for the URL u.User = url.UserPassword(d.Username, d.Password) // Connect and log in to ESX or vCenter c, err := govmomi.NewClient(ctx, u, true) if err != nil { return nil, err } return c, nil }
func TestFolderESX(t *testing.T) { content := esx.ServiceContent s := New(NewServiceInstance(content, esx.RootFolder)) ts := s.NewServer() defer ts.Close() ctx := context.Background() c, err := govmomi.NewClient(ctx, ts.URL, true) if err != nil { t.Fatal(err) } f := object.NewRootFolder(c.Client) _, err = f.CreateFolder(ctx, "foo") if err == nil { t.Error("expected error") } _, err = f.CreateDatacenter(ctx, "foo") if err == nil { t.Error("expected error") } finder := find.NewFinder(c.Client, false) dc, err := finder.DatacenterOrDefault(ctx, "") if err != nil { t.Fatal(err) } folders, err := dc.Folders(ctx) if err != nil { t.Fatal(err) } spec := types.HostConnectSpec{} _, err = addStandaloneHost(folders.HostFolder, spec) if err == nil { t.Fatal("expected error") } }
func newClient(cfg *VSphereConfig, ctx context.Context) (*govmomi.Client, error) { // Parse URL from string u, err := url.Parse(fmt.Sprintf("https://%s:%s/sdk", cfg.Global.VCenterIP, cfg.Global.VCenterPort)) if err != nil { return nil, err } // set username and password for the URL u.User = url.UserPassword(cfg.Global.User, cfg.Global.Password) // Connect and log in to ESX or vCenter c, err := govmomi.NewClient(ctx, u, cfg.Global.InsecureFlag) if err != nil { return nil, err } // Add retry functionality c.RoundTripper = vim25.Retry(c.RoundTripper, vim25.TemporaryNetworkError(int(cfg.Global.RoundTripperCount))) return c, nil }
func TestDefaultESX(t *testing.T) { s := New(NewServiceInstance(esx.ServiceContent, esx.RootFolder)) ts := s.NewServer() defer ts.Close() ctx := context.Background() client, err := govmomi.NewClient(ctx, ts.URL, true) if err != nil { t.Fatal(err) } finder := find.NewFinder(client.Client, false) dc, err := finder.DatacenterOrDefault(ctx, "") if err != nil { t.Fatal(err) } finder.SetDatacenter(dc) host, err := finder.HostSystemOrDefault(ctx, "*") if err != nil { t.Fatal(err) } if host.Name() != esx.HostSystem.Summary.Config.Name { t.Fail() } pool, err := finder.ResourcePoolOrDefault(ctx, "*") if err != nil { t.Fatal(err) } if pool.Name() != "Resources" { t.Fail() } }
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) } } } } }
func TestServeHTTPErrors(t *testing.T) { s := New(NewServiceInstance(esx.ServiceContent, esx.RootFolder)) ts := s.NewServer() defer ts.Close() ctx := context.Background() client, err := govmomi.NewClient(ctx, ts.URL, true) if err != nil { t.Fatal(err) } // unregister type, covering the ServeHTTP UnmarshalBody error path typeFunc = func(name string) (reflect.Type, bool) { return nil, false } _, err = methods.GetCurrentTime(ctx, client) if err == nil { t.Error("expected error") } typeFunc = types.TypeFunc() // reset // cover the does not implement method error path Map.objects[serviceInstance] = &errorNoSuchMethod{} _, err = methods.GetCurrentTime(ctx, client) if err == nil { t.Error("expected error") } // cover the xml encode error path Map.objects[serviceInstance] = &errorMarshal{} _, err = methods.GetCurrentTime(ctx, client) if err == nil { t.Error("expected error") } // cover the no such object path Map.Remove(serviceInstance) _, err = methods.GetCurrentTime(ctx, client) if err == nil { t.Error("expected error") } // verify we properly marshal the fault fault := soap.ToSoapFault(err).VimFault() f, ok := fault.(types.ManagedObjectNotFound) if !ok { t.Fatalf("fault=%#v", fault) } if f.Obj != serviceInstance.Reference() { t.Errorf("obj=%#v", f.Obj) } // cover the method not supported path res, err := http.Get(ts.URL.String()) if err != nil { log.Fatal(err) } if res.StatusCode != http.StatusMethodNotAllowed { t.Errorf("expected status %d, got %s", http.StatusMethodNotAllowed, res.Status) } // cover the ioutil.ReadAll error path s.readAll = func(io.Reader) ([]byte, error) { return nil, io.ErrShortBuffer } res, err = http.Post(ts.URL.String(), "none", nil) if err != nil { log.Fatal(err) } if res.StatusCode != http.StatusBadRequest { t.Errorf("expected status %d, got %s", http.StatusBadRequest, res.Status) } }
func doRegistration(ui packer.Ui, config Config, vmx string, clonerequired bool) error { sdkURL, err := url.Parse(fmt.Sprintf("https://%s:%s@%s/sdk", url.QueryEscape(config.Username), url.QueryEscape(config.Password), config.Host)) if err != nil { return err } client, err := govmomi.NewClient(context.TODO(), sdkURL, true) if err != nil { return err } finder := find.NewFinder(client.Client, false) datacenter, err := finder.DefaultDatacenter(context.TODO()) finder.SetDatacenter(datacenter) if err != nil { return err } folders, err := datacenter.Folders(context.TODO()) if err != nil { return err } resourcePool, err := finder.DefaultResourcePool(context.TODO()) if err != nil { return err } splitString := strings.Split(vmx, "/") last := splitString[len(splitString)-1] vmName := strings.TrimSuffix(last, ".vmx") datastoreString := fmt.Sprintf("[%s] %s/%s.vmx", config.Datastore, config.VMFolder, vmName) ui.Message(fmt.Sprintf("Registering %s from %s", vmName, datastoreString)) task, err := folders.VmFolder.RegisterVM(context.TODO(), datastoreString, vmName, false, resourcePool, nil) if err != nil { return err } _, err = task.WaitForResult(context.TODO(), nil) if err != nil { return err } ui.Message(fmt.Sprintf("Registererd VM %s", vmName)) vm, err := finder.VirtualMachine(context.TODO(), vmName) rpRef := resourcePool.Reference() if clonerequired { cloneSpec := types.VirtualMachineCloneSpec{ Location: types.VirtualMachineRelocateSpec{ Pool: &rpRef, }, } cloneVmName := fmt.Sprintf("%s-vm", vmName) ui.Message(fmt.Sprintf("Cloning VM %s", cloneVmName)) task, err = vm.Clone(context.TODO(), folders.VmFolder, cloneVmName, cloneSpec) if err != nil { return err } _, err = task.WaitForResult(context.TODO(), nil) if err != nil { return err } clonedVM, err := finder.VirtualMachine(context.TODO(), cloneVmName) if err != nil { return err } ui.Message(fmt.Sprintf("Powering on %s", cloneVmName)) task, err = clonedVM.PowerOn(context.TODO()) if err != nil { return err } _, err = task.WaitForResult(context.TODO(), nil) if err != nil { return err } ui.Message(fmt.Sprintf("Powered on %s", cloneVmName)) timeout := time.After(5 * time.Minute) tick := time.Tick(500 * time.Millisecond) LoopWaitForVMToolsRunning: for { select { case <-timeout: task, err = clonedVM.PowerOff(context.TODO()) if err != nil { return err } _, err = task.WaitForResult(context.TODO(), nil) if err != nil { return err } return fmt.Errorf("Timed out while waiting for VM Tools to be recogonized") case <-tick: running, err := clonedVM.IsToolsRunning(context.TODO()) if err != nil { return err } if running { break LoopWaitForVMToolsRunning } } } ui.Message(fmt.Sprintf("Powering off %s", cloneVmName)) task, err = clonedVM.PowerOff(context.TODO()) if err != nil { return err } _, err = task.WaitForResult(context.TODO(), nil) if err != nil { return err } ui.Message(fmt.Sprintf("Powered off %s", cloneVmName)) ui.Message(fmt.Sprintf("Marking as template %s", cloneVmName)) err = clonedVM.MarkAsTemplate(context.TODO()) if err != nil { return err } ui.Message(fmt.Sprintf("Destroying %s", cloneVmName)) task, err = vm.Destroy(context.TODO()) _, err = task.WaitForResult(context.TODO(), nil) if err != nil { return err } ui.Message(fmt.Sprintf("Destroyed %s", cloneVmName)) } else { ui.Message(fmt.Sprintf("Marking as template %s", vmName)) err = vm.MarkAsTemplate(context.TODO()) if err != nil { return err } ui.Message(fmt.Sprintf("%s is now a template", vmName)) } return nil }
func doRegistration(ui packer.Ui, config Config, vmx string, clonerequired bool) (err error) { sdkURL, err := url.Parse(fmt.Sprintf("https://%s:%s@%s/sdk", url.QueryEscape(config.Username), url.QueryEscape(config.Password), config.Host)) if err != nil { return err } client, err := govmomi.NewClient(context.TODO(), sdkURL, true) if err != nil { return err } finder := find.NewFinder(client.Client, false) datacenter, err := finder.DefaultDatacenter(context.TODO()) finder.SetDatacenter(datacenter) if err != nil { return err } folders, err := datacenter.Folders(context.TODO()) if err != nil { return err } resourcePool, err := finder.DefaultResourcePool(context.TODO()) if err != nil { return err } splitString := strings.Split(vmx, "/") last := splitString[len(splitString)-1] vmName := strings.TrimSuffix(last, ".vmx") datastoreString := fmt.Sprintf("[%s] %s/%s.vmx", config.Datastore, config.VMFolder, vmName) ui.Message(fmt.Sprintf("Registering %s from %s", vmName, datastoreString)) task, err := folders.VmFolder.RegisterVM(context.TODO(), datastoreString, vmName, false, resourcePool, nil) if err != nil { return err } _, err = task.WaitForResult(context.TODO(), nil) if err != nil { return err } ui.Message(fmt.Sprintf("Registererd VM %s", vmName)) vm, err := finder.VirtualMachine(context.TODO(), vmName) rpRef := resourcePool.Reference() if clonerequired { cloneSpec := types.VirtualMachineCloneSpec{ Location: types.VirtualMachineRelocateSpec{ Pool: &rpRef, }, } cloneVmName := fmt.Sprintf("%s-vm", vmName) ui.Message(fmt.Sprintf("Cloning VM %s", cloneVmName)) task, err = vm.Clone(context.TODO(), folders.VmFolder, cloneVmName, cloneSpec) if err != nil { return err } _, err = task.WaitForResult(context.TODO(), nil) if err != nil { return err } clonedVM, err := finder.VirtualMachine(context.TODO(), cloneVmName) if err != nil { return err } ui.Message(fmt.Sprintf("Powering on %s", cloneVmName)) task, err = clonedVM.PowerOn(context.TODO()) if err != nil { return err } _, err = task.WaitForResult(context.TODO(), nil) if err != nil { return err } ui.Message(fmt.Sprintf("Powered on %s", cloneVmName)) time.Sleep(150000 * time.Millisecond) // This is really dirty, but I need to make sure the VM gets fully powered on before I turn it off, otherwise vmware tools won't register on the cloning side. ui.Message(fmt.Sprintf("Powering off %s", cloneVmName)) task, err = clonedVM.PowerOff(context.TODO()) if err != nil { return err } _, err = task.WaitForResult(context.TODO(), nil) if err != nil { return err } ui.Message(fmt.Sprintf("Powered off %s", cloneVmName)) ui.Message(fmt.Sprintf("Marking as template %s", cloneVmName)) err = clonedVM.MarkAsTemplate(context.TODO()) if err != nil { return err } ui.Message(fmt.Sprintf("Destroying %s", cloneVmName)) task, err = vm.Destroy(context.TODO()) _, err = task.WaitForResult(context.TODO(), nil) if err != nil { return err } ui.Message(fmt.Sprintf("Destroyed %s", cloneVmName)) } else { ui.Message(fmt.Sprintf("Marking as template %s", vmName)) err = vm.MarkAsTemplate(context.TODO()) if err != nil { return err } ui.Message(fmt.Sprintf("%s is now a template", vmName)) } return nil }
func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() flag.Parse() // Parse URL from string u, err := url.Parse(*urlFlag) if err != nil { exit(err) } // Override username and/or password as required processOverride(u) // Connect and log in to ESX or vCenter c, err := govmomi.NewClient(ctx, u, *insecureFlag) if err != nil { exit(err) } f := find.NewFinder(c.Client, true) // Find one and only datacenter dc, err := f.DefaultDatacenter(ctx) if err != nil { exit(err) } // Make future calls local to this datacenter f.SetDatacenter(dc) // Find virtual machines in datacenter vms, err := f.VirtualMachineList(ctx, "*") if err != nil { exit(err) } pc := property.DefaultCollector(c.Client) // Convert datastores into list of references var refs []types.ManagedObjectReference for _, vm := range vms { refs = append(refs, vm.Reference()) } // Retrieve name property for all vms var vmt []mo.VirtualMachine err = pc.Retrieve(ctx, refs, []string{"name"}, &vmt) if err != nil { exit(err) } // Print name per virtual machine tw := tabwriter.NewWriter(os.Stdout, 2, 0, 2, ' ', 0) fmt.Println("Virtual machines found:", len(vmt)) sort.Sort(ByName(vmt)) for _, vm := range vmt { fmt.Fprintf(tw, "%s\n", vm.Name) } tw.Flush() }
func TestFolderVC(t *testing.T) { content := vc.ServiceContent s := New(NewServiceInstance(content, vc.RootFolder)) ts := s.NewServer() defer ts.Close() ctx := context.Background() c, err := govmomi.NewClient(ctx, ts.URL, true) if err != nil { t.Fatal(err) } f := object.NewRootFolder(c.Client) ff, err := f.CreateFolder(ctx, "foo") if err != nil { t.Error(err) } dc, err := f.CreateDatacenter(ctx, "bar") if err != nil { t.Error(err) } for _, ref := range []object.Reference{ff, dc} { o := Map.Get(ref.Reference()) if o == nil { t.Fatalf("failed to find %#v", ref) } e := o.(mo.Entity).Entity() if *e.Parent != f.Reference() { t.Fail() } } dc, err = ff.CreateDatacenter(ctx, "biz") if err != nil { t.Error(err) } folders, err := dc.Folders(ctx) if err != nil { t.Fatal(err) } tests := []struct { name string state types.TaskInfoState }{ {"", types.TaskInfoStateError}, {"foo.local", types.TaskInfoStateSuccess}, } for _, test := range tests { spec := types.HostConnectSpec{ HostName: test.name, } task, err := addStandaloneHost(folders.HostFolder, spec) if err != nil { t.Fatal(err) } res, err := task.WaitForResult(ctx, nil) if test.state == types.TaskInfoStateError { if err == nil { t.Error("expected error") } if res.Result != nil { t.Error("expected nil") } } else { if err != nil { t.Fatal(err) } ref, ok := res.Result.(types.ManagedObjectReference) if !ok { t.Errorf("expected moref, got type=%T", res.Result) } host := Map.Get(ref).(*HostSystem) if host.Name != test.name { t.Fail() } if ref == esx.HostSystem.Self { t.Error("expected new host Self reference") } pool := Map.Get(*host.Parent).(*mo.ComputeResource).ResourcePool if *pool == esx.ResourcePool.Self { t.Error("expected new pool Self reference") } } if res.State != test.state { t.Fatalf("%s", res.State) } } }
func TestServeHTTPS(t *testing.T) { s := New(NewServiceInstance(esx.ServiceContent, esx.RootFolder)) s.TLS = new(tls.Config) ts := s.NewServer() defer ts.Close() ctx := context.Background() // insecure=true OK client, err := govmomi.NewClient(ctx, ts.URL, true) if err != nil { t.Fatal(err) } err = client.Login(ctx, ts.URL.User) if err != nil { t.Fatal(err) } // insecure=false should FAIL _, err = govmomi.NewClient(ctx, ts.URL, false) if err == nil { t.Fatal("expected error") } uerr, ok := err.(*url.Error) if !ok { t.Fatalf("err type=%T", err) } _, ok = uerr.Err.(x509.UnknownAuthorityError) if !ok { t.Fatalf("err type=%T", uerr.Err) } sinfo := ts.CertificateInfo() // Test thumbprint validation sc := soap.NewClient(ts.URL, false) // Add host with thumbprint mismatch should fail sc.SetThumbprint(ts.URL.Host, "nope") _, err = vim25.NewClient(ctx, sc) if err == nil { t.Error("expected error") } // Add host with thumbprint match should pass sc.SetThumbprint(ts.URL.Host, sinfo.ThumbprintSHA1) _, err = vim25.NewClient(ctx, sc) if err != nil { t.Fatal(err) } var pinfo object.HostCertificateInfo err = pinfo.FromURL(ts.URL, nil) if err != nil { t.Fatal(err) } if pinfo.ThumbprintSHA1 != sinfo.ThumbprintSHA1 { t.Error("thumbprint mismatch") } // Test custom RootCAs list sc = soap.NewClient(ts.URL, false) caFile, err := ts.CertificateFile() if err != nil { t.Fatal(err) } if err = sc.SetRootCAs(caFile); err != nil { t.Fatal(err) } _, err = vim25.NewClient(ctx, sc) if err != nil { t.Fatal(err) } }
func (s *StepFixNetwork) Run(state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packer.Ui) ui.Say("Waiting for vm") time.Sleep(20 * time.Second) ctx, cancel := context.WithCancel(context.Background()) defer cancel() // Parse URL from string // url. u, err := url.Parse(s.VCenterSDKURL) if err != nil { ui.Error(err.Error()) return multistep.ActionHalt } // Connect and log in to ESX or vCenter c, err := govmomi.NewClient(ctx, u, true) if err != nil { ui.Error(err.Error()) return multistep.ActionHalt } f := find.NewFinder(c.Client, true) ui.Say("Getting DataCenter ") // Find one and only datacenter dc, err := f.Datacenter(ctx, s.DataCenter) if err != nil { ui.Error(err.Error()) return multistep.ActionHalt } ui.Message(fmt.Sprintf("DataCenter Name : %s", dc.String())) // Make future calls local to this datacenter f.SetDatacenter(dc) var qualifiedVMName = "/" + s.DataCenter + "/vm/Discovered virtual machine/" + s.VMName fmt.Printf("qualifiedVMName VM %s", qualifiedVMName) // Find vm in datacenter vm, err := f.VirtualMachine(ctx, qualifiedVMName) if err != nil { ui.Message(fmt.Sprintf("Retrying to get VM using QualifiedVMName VM %s", s.QualifiedVMName)) vm, err = f.VirtualMachine(ctx, s.QualifiedVMName) if err != nil { ui.Error(err.Error()) return multistep.ActionHalt } } err = delVNIC(ui, f, ctx, vm) if err != nil { ui.Error(err.Error()) return multistep.ActionHalt } ui.Say("Waiting for delete nic") time.Sleep(20 * time.Second) err = addVNIC(ui, f, ctx, c, vm, s.Network, s.NetworkType) if err != nil { ui.Error(err.Error()) return multistep.ActionHalt } ui.Say("Waiting for add nic") time.Sleep(20 * time.Second) return multistep.ActionContinue }
func TestRetrieveProperties(t *testing.T) { configs := []struct { folder mo.Folder content types.ServiceContent dc *types.ManagedObjectReference }{ {esx.RootFolder, esx.ServiceContent, &esx.Datacenter.Self}, {vc.RootFolder, vc.ServiceContent, nil}, } for _, config := range configs { s := New(NewServiceInstance(config.content, config.folder)) ts := s.NewServer() defer ts.Close() ctx := context.Background() client, err := govmomi.NewClient(ctx, ts.URL, true) if err != nil { t.Fatal(err) } if config.dc == nil { dc, cerr := object.NewRootFolder(client.Client).CreateDatacenter(ctx, "dc1") if cerr != nil { t.Fatal(cerr) } ref := dc.Reference() config.dc = &ref } // Retrieve a specific property f := mo.Folder{} err = client.RetrieveOne(ctx, config.content.RootFolder, []string{"name"}, &f) if err != nil { t.Fatal(err) } if f.Name != config.folder.Name { t.Fail() } // Retrieve all properties f = mo.Folder{} err = client.RetrieveOne(ctx, config.content.RootFolder, nil, &f) if err != nil { t.Fatal(err) } if f.Name != config.folder.Name { t.Fatalf("'%s' vs '%s'", f.Name, config.folder.Name) } // Retrieve an ArrayOf property f = mo.Folder{} err = client.RetrieveOne(ctx, config.content.RootFolder, []string{"childEntity"}, &f) if err != nil { t.Fatal(err) } if len(f.ChildEntity) != 1 { t.Fail() } es, err := mo.Ancestors(ctx, client.Client, config.content.PropertyCollector, config.content.RootFolder) if err != nil { t.Fatal(err) } if len(es) != 1 { t.Fail() } finder := find.NewFinder(client.Client, false) dc, err := finder.DatacenterOrDefault(ctx, "") if err != nil { t.Fatal(err) } if dc.Reference() != *config.dc { t.Fail() } finder.SetDatacenter(dc) es, err = mo.Ancestors(ctx, client.Client, config.content.PropertyCollector, dc.Reference()) if err != nil { t.Fatal(err) } expect := map[string]types.ManagedObjectReference{ "Folder": config.folder.Reference(), "Datacenter": dc.Reference(), } if len(es) != len(expect) { t.Fail() } for _, e := range es { ref := e.Reference() if r, ok := expect[ref.Type]; ok { if r != ref { t.Errorf("%#v vs %#v", r, ref) } } else { t.Errorf("unexpected object %#v", e.Reference()) } } // finder tests ls, err := finder.ManagedObjectListChildren(ctx, ".") if err != nil { t.Error(err) } folders, err := dc.Folders(ctx) if err != nil { t.Fatal(err) } // Validated name properties are recursively retrieved for the datacenter and its folder children ipaths := []string{ folders.VmFolder.InventoryPath, folders.HostFolder.InventoryPath, folders.DatastoreFolder.InventoryPath, folders.NetworkFolder.InventoryPath, } var lpaths []string for _, p := range ls { lpaths = append(lpaths, p.Path) } if !reflect.DeepEqual(ipaths, lpaths) { t.Errorf("%#v != %#v\n", ipaths, lpaths) } // We have no VMs, expect NotFoundError _, err = finder.VirtualMachineList(ctx, "*") if err == nil { t.Error("expected error") } else { if _, ok := err.(*find.NotFoundError); !ok { t.Error(err) } } // Retrieve a missing property mdc := mo.Datacenter{} err = client.RetrieveOne(ctx, dc.Reference(), []string{"enoent"}, &mdc) if err == nil { t.Error("expected error") } else { switch fault := soap.ToVimFault(err).(type) { case *types.InvalidProperty: // ok default: t.Errorf("unexpected fault: %#v", fault) } } // Retrieve a nested property Map.Get(dc.Reference()).(*mo.Datacenter).Configuration.DefaultHardwareVersionKey = "foo" mdc = mo.Datacenter{} err = client.RetrieveOne(ctx, dc.Reference(), []string{"configuration.defaultHardwareVersionKey"}, &mdc) if err != nil { t.Fatal(err) } if mdc.Configuration.DefaultHardwareVersionKey != "foo" { t.Fail() } // Retrieve a missing nested property mdc = mo.Datacenter{} err = client.RetrieveOne(ctx, dc.Reference(), []string{"configuration.enoent"}, &mdc) if err == nil { t.Error("expected error") } else { switch fault := soap.ToVimFault(err).(type) { case *types.InvalidProperty: // ok default: t.Errorf("unexpected fault: %#v", fault) } } // Retrieve an empty property err = client.RetrieveOne(ctx, dc.Reference(), []string{""}, &mdc) if err != nil { t.Error(err) } // Expect ManagedObjectNotFoundError Map.Remove(dc.Reference()) err = client.RetrieveOne(ctx, dc.Reference(), []string{"name"}, &mdc) if err == nil { t.Fatal("expected error") } } }
func TestHostDatastoreSystem(t *testing.T) { s := New(NewServiceInstance(esx.ServiceContent, esx.RootFolder)) ts := s.NewServer() defer ts.Close() ctx := context.Background() c, err := govmomi.NewClient(ctx, ts.URL, true) if err != nil { t.Fatal(err) } host := object.NewHostSystem(c.Client, esx.HostSystem.Reference()) dss, err := host.ConfigManager().DatastoreSystem(ctx) if err != nil { t.Error(err) } pwd, err := os.Getwd() if err != nil { t.Fatal(err) } spec := types.HostNasVolumeSpec{ Type: string(types.HostFileSystemVolumeFileSystemTypeNFS), RemoteHost: "localhost", } tests := []func(string) (*object.Datastore, error){ func(dir string) (*object.Datastore, error) { spec.LocalPath = dir spec.RemotePath = dir return dss.CreateNasDatastore(ctx, spec) }, func(dir string) (*object.Datastore, error) { return dss.CreateLocalDatastore(ctx, filepath.Base(dir), dir) }, } for _, create := range tests { for _, fail := range []bool{false, true} { if fail { _, err = create(pwd) if err == nil { t.Error("expected error") } // TODO: hds.Remove(ds) pwd = filepath.Join(pwd, "esx") } else { _, err = create(pwd) if err != nil { t.Error(err) } } } } for _, create := range tests { for _, dir := range []string{"./enoent", "host_datastore_system.go"} { _, err = create(dir) if err == nil { t.Error("expected error") } } } }
func main() { vcUrl := flag.String("url", GetEnvString(envURL, ""), fmt.Sprintf("vCenter Connect URL [%s]", envURL)) insecure := flag.Bool("insecure", GetEnvBool(envInsecure, false), fmt.Sprintf("Don't verify Certificate [%s]", envInsecure)) flag.Parse() ctx, cancel := context.WithCancel(context.Background()) defer cancel() url, err := url.Parse(*vcUrl) if err != nil { exit(err) } client, err := govmomi.NewClient(ctx, url, *insecure) if err != nil { exit(err) } finder := find.NewFinder(client.Client, false) dc, err := finder.DefaultDatacenter(ctx) if err != nil { exit(err) } filter := types.EventFilterSpec{ Entity: &types.EventFilterSpecByEntity{ Entity: dc.Reference(), Recursion: types.EventFilterSpecRecursionOptionAll, }, } eventManager := event.NewManager(client.Client) collector, err := eventManager.CreateCollectorForEvents(ctx, filter) defer collector.Destroy(ctx) collector.SetPageSize(ctx, 0) collector.Reset(ctx) for true { items, err := collector.ReadNextEvents(ctx, 10) if err != nil { exit(err) } for _, e := range items { category, _ := eventManager.EventCategory(ctx, e) event := e.GetEvent() msg := strings.TrimSpace(event.FullFormattedMessage) m := make(map[string]string) t := event.CreatedTime m["time"] = strconv.FormatInt(t.Unix(), 10) m["type"] = "Event" if t, ok := e.(*types.TaskEvent); ok { m["type"] = "Task" m["targetType"] = t.Info.Entity.Type m["targetName"] = t.Info.EntityName } m["message"] = msg m["category"] = category if event.Host != nil && event.Host.Name != "" { m["host"] = event.Host.Name } if event.Vm != nil && event.Vm.Name != "" { m["vm"] = event.Vm.Name } if event.UserName != "" { m["username"] = event.UserName } s, _ := json.Marshal(m) fmt.Printf("%s\n", string(s)) } time.Sleep(10 * 1000 * 1000 * 1000) } }
func TestDatastoreHTTP(t *testing.T) { ctx := context.Background() src := "datastore_test.go" dst := "tmp.go" 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) } finder := find.NewFinder(c.Client, false) dc, err := finder.DefaultDatacenter(ctx) if err != nil { t.Fatal(err) } finder.SetDatacenter(dc) ds, err := finder.DefaultDatastore(ctx) if err != nil { t.Fatal(err) } dsPath := ds.Path if !c.IsVC() { dc = nil // test using the default } fm := object.NewFileManager(c.Client) browser, err := ds.Browser(ctx) if err != nil { t.Fatal(err) } download := func(name string, fail bool) { st, serr := ds.Stat(ctx, name) _, _, err = ds.Download(ctx, name, nil) if fail { if err == nil { t.Fatal("expected Download error") } if serr == nil { t.Fatal("expected Stat error") } } else { if err != nil { t.Errorf("Download error: %s", err) } if serr != nil { t.Errorf("Stat error: %s", serr) } p := st.GetFileInfo().Path if p != name { t.Errorf("path=%s", p) } } } upload := func(name string, fail bool, method string) { f, err := os.Open(src) if err != nil { t.Fatal(err) } defer f.Close() p := soap.DefaultUpload p.Method = method err = ds.Upload(ctx, f, name, &p) if fail { if err == nil { t.Fatalf("%s %s: expected error", method, name) } } else { if err != nil { t.Fatal(err) } } } rm := func(name string, fail bool) { task, err := fm.DeleteDatastoreFile(ctx, dsPath(name), dc) if err != nil { t.Fatal(err) } err = task.Wait(ctx) if fail { if err == nil { t.Fatalf("rm %s: expected error", name) } } else { if err != nil { t.Fatal(err) } } } mv := func(src string, dst string, fail bool, force bool) { task, err := fm.MoveDatastoreFile(ctx, dsPath(src), dc, dsPath(dst), dc, force) if err != nil { t.Fatal(err) } err = task.Wait(ctx) if fail { if err == nil { t.Fatalf("mv %s %s: expected error", src, dst) } } else { if err != nil { t.Fatal(err) } } } mkdir := func(name string, fail bool, p bool) { err := fm.MakeDirectory(ctx, dsPath(name), dc, p) if fail { if err == nil { t.Fatalf("mkdir %s: expected error", name) } } else { if err != nil { t.Fatal(err) } } } stat := func(name string, fail bool) { _, err := ds.Stat(ctx, name) if fail { if err == nil { t.Fatalf("stat %s: expected error", name) } } else { if err != nil { t.Fatal(err) } } } ls := func(name string, fail bool) []types.BaseFileInfo { spec := types.HostDatastoreBrowserSearchSpec{ MatchPattern: []string{"*"}, } task, err := browser.SearchDatastore(ctx, dsPath(name), &spec) if err != nil { t.Fatal(err) } info, err := task.WaitForResult(ctx, nil) if err != nil { if fail { if err == nil { t.Fatalf("ls %s: expected error", name) } } else { if err != nil { t.Fatal(err) } } return nil } return info.Result.(types.HostDatastoreBrowserSearchResults).File } // GET file does not exist = fail download(dst, true) stat(dst, true) ls(dst, true) // delete file does not exist = fail rm(dst, true) // PUT file = ok upload(dst, false, "PUT") stat(dst, false) // GET file exists = ok download(dst, false) // POST file exists = fail upload(dst, true, "POST") // delete existing file = ok rm(dst, false) stat(dst, true) // GET file does not exist = fail download(dst, true) // POST file does not exist = ok upload(dst, false, "POST") // PATCH method not supported = fail upload(dst+".patch", true, "PATCH") // PUT path is directory = fail upload("", true, "PUT") // mkdir parent does not exist = fail mkdir("foo/bar", true, false) // mkdir -p parent does not exist = ok mkdir("foo/bar", false, true) // mkdir = ok mkdir("foo/bar/baz", false, false) target := path.Join("foo", dst) // mv dst not exist = ok mv(dst, target, false, false) // POST file does not exist = ok upload(dst, false, "POST") // mv dst exists = fail mv(dst, target, true, false) // mv dst exists, force=true = ok mv(dst, target, false, true) // mv src does not exist = fail mv(dst, target, true, true) invalid := []string{ "", //InvalidDatastorePath "[nope]", // InvalidDatastore } // test FileType details mkdir("exts", false, false) stat("exts", false) exts := []string{"img", "iso", "log", "nvram", "vmdk", "vmx"} for _, ext := range exts { name := dst + "." + ext upload(name, false, "POST") stat(name, false) } for _, p := range invalid { dsPath = func(name string) string { return p } mv(target, dst, true, false) mkdir("sorry", true, false) rm(target, true) ls(target, true) } // cover the dst failure path for _, p := range invalid { dsPath = func(name string) string { if name == dst { return p } return ds.Path(name) } mv(target, dst, true, false) } dsPath = func(name string) string { return ds.Path("enoent") } ls(target, true) // cover the case where datacenter or datastore lookup fails for _, q := range []string{"dcName=nope", "dsName=nope"} { u := *s.URL u.RawQuery = q u.Path = path.Join(folderPrefix, dst) r, err := http.Get(u.String()) if err != nil { t.Fatal(err) } if r.StatusCode == http.StatusOK { t.Error("expected failure") } } } }
func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() flag.Parse() // Parse URL from string u, err := url.Parse(*urlFlag) if err != nil { exit(err) } // Connect and log in to ESX or vCenter c, err := govmomi.NewClient(ctx, u, *insecureFlag) if err != nil { exit(err) } f := find.NewFinder(c.Client, true) // Find one and only datacenter dc, err := f.DefaultDatacenter(ctx) if err != nil { exit(err) } // Make future calls local to this datacenter f.SetDatacenter(dc) // Find datastores in datacenter dss, err := f.DatastoreList(ctx, "*") if err != nil { exit(err) } pc := property.DefaultCollector(c.Client) // Convert datastores into list of references var refs []types.ManagedObjectReference for _, ds := range dss { refs = append(refs, ds.Reference()) } // Retrieve summary property for all datastores var dst []mo.Datastore err = pc.Retrieve(ctx, refs, []string{"summary"}, &dst) if err != nil { exit(err) } // Print summary per datastore tw := tabwriter.NewWriter(os.Stdout, 2, 0, 2, ' ', 0) fmt.Fprintf(tw, "Name:\tType:\tCapacity:\tFree:\n") for _, ds := range dst { fmt.Fprintf(tw, "%s\t", ds.Summary.Name) fmt.Fprintf(tw, "%s\t", ds.Summary.Type) fmt.Fprintf(tw, "%s\t", Humanize(ds.Summary.Capacity)) fmt.Fprintf(tw, "%s\t", Humanize(ds.Summary.FreeSpace)) fmt.Fprintf(tw, "\n") } tw.Flush() }
// TestSoapFaults covers the various soap fault checking paths func TestSoapFaults(t *testing.T) { ctx := context.Background() // Nothing VC specific in this test, so we use the simpler ESX model model := simulator.ESX() defer model.Remove() err := model.Create() if err != nil { t.Fatal(err) } server := model.Service.NewServer() defer server.Close() client, err := govmomi.NewClient(ctx, server.URL, true) if err != nil { t.Fatal(err) } // Any VM will do finder := find.NewFinder(client.Client, false) vm, err := finder.VirtualMachine(ctx, "/ha-datacenter/vm/*_VM0") if err != nil { t.Fatal(err) } // Test the success path err = Wait(ctx, func(ctx context.Context) (Task, error) { return vm.PowerOn(ctx) }) if err != nil { t.Fatal(err) } // Wrap existing vm MO with faultyVirtualMachine ref := simulator.Map.Get(vm.Reference()) fvm := &faultyVirtualMachine{*ref.(*simulator.VirtualMachine), nil} simulator.Map.Put(fvm) // Inject TaskInProgress fault fvm.fault = new(types.TaskInProgress) task, err := vm.PowerOff(ctx) if err != nil { t.Fatal(err) } // Test the task.Error path res, err := task.WaitForResult(ctx, nil) if !isTaskInProgress(err) { t.Error(err) } // Test the soap.IsVimFault() path if !isTaskInProgress(soap.WrapVimFault(res.Error.Fault)) { t.Errorf("fault=%#v", res.Error.Fault) } // Test the soap.IsSoapFault() path err = vm.MarkAsTemplate(ctx) if !isTaskInProgress(err) { t.Error(err) } // Test a fault other than TaskInProgress fvm.fault = &types.QuestionPending{ Text: "now why would you want to do such a thing?", } err = Wait(ctx, func(ctx context.Context) (Task, error) { return vm.PowerOff(ctx) }) if err == nil { t.Error("expected error") } if isTaskInProgress(err) { t.Error(err) } // Test with retry fvm.fault = new(types.TaskInProgress) called := 0 err = Wait(ctx, func(ctx context.Context) (Task, error) { called++ if called > 1 { simulator.Map.Put(ref) // remove fault injection } return vm.PowerOff(ctx) }) if err != nil { t.Error(err) } if called != 2 { t.Errorf("called=%d", called) } }