func deleteFile(client *govmomi.Client, f *file) error { dc, err := getDatacenter(client, f.datacenter) if err != nil { return err } finder := find.NewFinder(client.Client, true) finder = finder.SetDatacenter(dc) ds, err := getDatastore(finder, f.datastore) if err != nil { return fmt.Errorf("error %s", err) } fm := object.NewFileManager(client.Client) task, err := fm.DeleteDatastoreFile(context.TODO(), ds.Path(f.destinationFile), dc) if err != nil { return err } _, err = task.WaitForResult(context.TODO(), nil) if err != nil { return err } return nil }
// NewDatastore returns a Datastore. // ctx is a context, // s is an authenticated session // ds is the vsphere datastore // rootdir is the top level directory to root all data. If root does not exist, // it will be created. If it already exists, NOOP. This cannot be empty. func NewDatastore(ctx context.Context, s *session.Session, ds *object.Datastore, rootdir string) (*Datastore, error) { d := &Datastore{ ds: ds, s: s, fm: object.NewFileManager(s.Vim25()), } if strings.HasPrefix(rootdir, "/") { rootdir = strings.TrimPrefix(rootdir, "/") } // Get the root directory element split from the rest of the path (if there is one) root := strings.SplitN(rootdir, "/", 2) // Create the first element. This handles vsan vmfs top level dirs. if err := d.mkRootDir(ctx, root[0]); err != nil { log.Infof("error creating root directory %s: %s", rootdir, err) return nil, err } // Create the rest conventionally if len(root) > 1 { r, err := d.Mkdir(ctx, true, root[1]) if err != nil { return nil, err } d.RootURL = r } log.Infof("Datastore path is %s", d.RootURL) return d, nil }
func (d *Dispatcher) deleteDatastoreFiles(ds *object.Datastore, path string, force bool) (bool, error) { defer trace.End(trace.Begin(fmt.Sprintf("path %q, force %t", path, force))) // refuse to delete everything on the datstore, ignore force if path == "" { dsn, _ := ds.ObjectName(d.ctx) msg := fmt.Sprintf("refusing to remove datastore files for path \"\" on datastore %q", dsn) return false, errors.New(msg) } var empty bool dsPath := ds.Path(path) res, err := d.lsFolder(ds, dsPath) if err != nil { if !types.IsFileNotFound(err) { err = errors.Errorf("Failed to browse folder %q: %s", dsPath, err) return empty, err } log.Debugf("Folder %q is not found", dsPath) empty = true return empty, nil } if len(res.File) > 0 && !force { log.Debugf("Folder %q is not empty, leave it there", dsPath) return empty, nil } m := object.NewFileManager(ds.Client()) if err = d.deleteFilesIteratively(m, ds, dsPath); err != nil { return empty, err } return true, nil }
func resourceVSphereFileUpdate(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] updating file: %#v", d) if d.HasChange("destination_file") { oldDestinationFile, newDestinationFile := d.GetChange("destination_file") f := file{} if v, ok := d.GetOk("datacenter"); ok { f.datacenter = v.(string) } if v, ok := d.GetOk("datastore"); ok { f.datastore = v.(string) } else { return fmt.Errorf("datastore argument is required") } if v, ok := d.GetOk("source_file"); ok { f.sourceFile = v.(string) } else { return fmt.Errorf("source_file argument is required") } if v, ok := d.GetOk("destination_file"); ok { f.destinationFile = v.(string) } else { return fmt.Errorf("destination_file argument is required") } client := meta.(*govmomi.Client) dc, err := getDatacenter(client, f.datacenter) if err != nil { return err } finder := find.NewFinder(client.Client, true) finder = finder.SetDatacenter(dc) ds, err := getDatastore(finder, f.datastore) if err != nil { return fmt.Errorf("error %s", err) } fm := object.NewFileManager(client.Client) task, err := fm.MoveDatastoreFile(context.TODO(), ds.Path(oldDestinationFile.(string)), dc, ds.Path(newDestinationFile.(string)), dc, true) if err != nil { return err } _, err = task.WaitForResult(context.TODO(), nil) if err != nil { return err } } return nil }
func (cmd *mkdir) Run(ctx context.Context, f *flag.FlagSet) error { args := f.Args() if len(args) == 0 { return errors.New("missing operand") } c, err := cmd.Client() if err != nil { return err } if cmd.isNamespace { var uuid string var ds *object.Datastore if ds, err = cmd.Datastore(); err != nil { return err } path := args[0] nm := object.NewDatastoreNamespaceManager(c) if uuid, err = nm.CreateDirectory(ctx, ds, path, ""); err != nil { return err } fmt.Println(uuid) } else { var dc *object.Datacenter var path string dc, err = cmd.Datacenter() if err != nil { return err } path, err = cmd.DatastorePath(args[0]) if err != nil { return err } m := object.NewFileManager(c) err = m.MakeDirectory(ctx, path, dc, cmd.createParents) // ignore EEXIST if -p flag is given if err != nil && cmd.createParents { if soap.IsSoapFault(err) { soapFault := soap.ToSoapFault(err) if _, ok := soapFault.VimFault().(types.FileAlreadyExists); ok { return nil } } } } return err }
func rm(t *testing.T, client *session.Session, name string) { t.Logf("deleting %s", name) fm := object.NewFileManager(client.Vim25()) task, err := fm.DeleteDatastoreFile(context.TODO(), name, client.Datacenter) if !assert.NoError(t, err) { return } _, _ = task.WaitForResult(context.TODO(), nil) }
func testDeleteDatastoreFiles(v *validate.Validator, t *testing.T) { d := &Dispatcher{ session: v.Session, ctx: v.Context, isVC: v.Session.IsVC(), force: false, } ds := v.Session.Datastore m := object.NewFileManager(ds.Client()) err := m.MakeDirectory(v.Context, ds.Path("Test/folder/data"), v.Session.Datacenter, true) if err != nil { t.Errorf("Failed to create datastore dir: %s", err) return } err = m.MakeDirectory(v.Context, ds.Path("Test/folder/metadata"), v.Session.Datacenter, true) if err != nil { t.Errorf("Failed to create datastore dir: %s", err) return } err = m.MakeDirectory(v.Context, ds.Path("Test/folder/file"), v.Session.Datacenter, true) if err != nil { t.Errorf("Failed to create datastore dir: %s", err) return } isVSAN := d.isVSAN(ds) t.Logf("datastore is vsan: %t", isVSAN) if err = createDatastoreFiles(d, ds, t); err != nil { t.Errorf("Failed to upload file: %s", err) return } if err = d.deleteFilesIteratively(m, ds, ds.Path("Test")); err != nil { t.Errorf("Failed to delete recursively: %s", err) } err = m.MakeDirectory(v.Context, ds.Path("Test/folder/data"), v.Session.Datacenter, true) if err != nil { t.Errorf("Failed to create datastore dir: %s", err) return } if err = createDatastoreFiles(d, ds, t); err != nil { t.Errorf("Failed to upload file: %s", err) return } if _, err = d.deleteDatastoreFiles(ds, "Test", true); err != nil { t.Errorf("Failed to delete recursively: %s", err) } }
func (cmd *rm) Run(ctx context.Context, f *flag.FlagSet) error { args := f.Args() if len(args) == 0 { return errors.New("missing operand") } c, err := cmd.Client() if err != nil { return err } var dc *object.Datacenter dc, err = cmd.Datacenter() if err != nil { return err } if cmd.isNamespace { path := args[0] nm := object.NewDatastoreNamespaceManager(c) err = nm.DeleteDirectory(ctx, dc, path) } else { var path string var task *object.Task // TODO(PN): Accept multiple args path, err = cmd.DatastorePath(args[0]) if err != nil { return err } m := object.NewFileManager(c) task, err = m.DeleteDatastoreFile(ctx, path, dc) if err != nil { return err } err = task.Wait(ctx) } if err != nil { if types.IsFileNotFound(err) && cmd.force { // Ignore error return nil } } return err }
func vmCleanup(dc *object.Datacenter, ds *object.Datastore, vmName string) error { client := testAccProvider.Meta().(*govmomi.Client) fileManager := object.NewFileManager(client.Client) task, err := fileManager.DeleteDatastoreFile(context.TODO(), ds.Path(vmName), dc) if err != nil { log.Printf("[ERROR] checkForDisk - Couldn't delete vm folder '%v': %v", vmName, err) return err } _, err = task.WaitForResult(context.TODO(), nil) if err != nil { log.Printf("[ERROR] checForDisk - Failed while deleting vm folder '%v': %v", vmName, err) return err } return nil }
// Creates a folder using the specified name. // If the intermediate level folders do not exist, // and the parameter createParents is true, // all the non-existent folders are created. func makeDirectoryInDatastore(c *govmomi.Client, dc *object.Datacenter, path string, createParents bool) error { ctx, cancel := context.WithCancel(context.Background()) defer cancel() fileManager := object.NewFileManager(c.Client) err := fileManager.MakeDirectory(ctx, path, dc, createParents) if err != nil { if soap.IsSoapFault(err) { soapFault := soap.ToSoapFault(err) if _, ok := soapFault.VimFault().(types.FileAlreadyExists); ok { return ErrFileAlreadyExist } } } return err }
// PrepareDestination makes sure that the destination VMDK does not yet exist. // If the force flag is passed, it removes the existing VMDK. This functions // exists to give a meaningful error if the remote VMDK already exists. // // CopyVirtualDisk can return a "<src> file does not exist" error while in fact // the source file *does* exist and the *destination* file also exist. // func (cmd *vmdk) PrepareDestination(i importable) error { ctx := context.TODO() vmdkPath := i.RemoteDstVMDK() res, err := cmd.Datastore.Stat(ctx, vmdkPath) if err != nil { switch err.(type) { case object.DatastoreNoSuchDirectoryError: // The base path doesn't exist. Create it. dsPath := cmd.Datastore.Path(path.Dir(vmdkPath)) m := object.NewFileManager(cmd.Client) return m.MakeDirectory(ctx, dsPath, cmd.Datacenter, true) case object.DatastoreNoSuchFileError: // Destination path doesn't exist; all good to continue with import. return nil } return err } // Check that the returned entry has the right type. switch res.(type) { case *types.VmDiskFileInfo: default: expected := "VmDiskFileInfo" actual := reflect.TypeOf(res) panic(fmt.Sprintf("Expected: %s, actual: %s", expected, actual)) } if !cmd.force { dsPath := cmd.Datastore.Path(vmdkPath) err = fmt.Errorf("File %s already exists", dsPath) return err } // Delete existing disk. err = cmd.DeleteDisk(vmdkPath) if err != nil { return err } return nil }
func checkForDisk(datacenter string, datastore string, vmName string, path string) resource.TestCheckFunc { return func(s *terraform.State) error { client := testAccProvider.Meta().(*govmomi.Client) finder := find.NewFinder(client.Client, true) dc, err := getDatacenter(client, datacenter) if err != nil { return err } finder.SetDatacenter(dc) ds, err := finder.Datastore(context.TODO(), datastore) if err != nil { log.Printf("[ERROR] checkForDisk - Couldn't find Datastore '%v': %v", datastore, err) return err } diskPath := vmName + "/" + path _, err = ds.Stat(context.TODO(), diskPath) if err != nil { log.Printf("[ERROR] checkForDisk - Couldn't stat file '%v': %v", diskPath, err) return err } // Cleanup fileManager := object.NewFileManager(client.Client) task, err := fileManager.DeleteDatastoreFile(context.TODO(), ds.Path(vmName), dc) if err != nil { log.Printf("[ERROR] checkForDisk - Couldn't delete vm folder '%v': %v", vmName, err) return err } _, err = task.WaitForResult(context.TODO(), nil) if err != nil { log.Printf("[ERROR] checForDisk - Failed while deleting vm folder '%v': %v", vmName, err) return err } return nil } }
func (d *Dispatcher) deleteUpgradeImages(ds *object.Datastore, settings *data.InstallerData) { defer trace.End(trace.Begin("")) log.Infof("Deleting upgrade images") // do clean up aggressively, even the previous operation failed with context deadline excceeded. d.ctx = context.Background() m := object.NewFileManager(ds.Client()) file := ds.Path(path.Join(d.vmPathName, settings.ApplianceISO)) if err := d.deleteVMFSFiles(m, ds, file); err != nil { log.Warnf("Image file %q is not removed for %s. Use the vSphere UI to delete content", file, err) } file = ds.Path(path.Join(d.vmPathName, settings.BootstrapISO)) if err := d.deleteVMFSFiles(m, ds, file); err != nil { log.Warnf("Image file %q is not removed for %s. Use the vSphere UI to delete content", file, err) } }
func (cmd *rm) Run(f *flag.FlagSet) error { args := f.Args() if len(args) == 0 { return errors.New("missing operand") } c, err := cmd.Client() if err != nil { return err } dc, err := cmd.Datacenter() if err != nil { return err } // TODO(PN): Accept multiple args path, err := cmd.DatastorePath(args[0]) if err != nil { return err } m := object.NewFileManager(c) task, err := m.DeleteDatastoreFile(context.TODO(), path, dc) if err != nil { return err } err = task.Wait(context.TODO()) if err != nil { if types.IsFileNotFound(err) && cmd.force { // Ignore error return nil } } return err }
// GetDatastores returns a map of datastores given a map of names and urls func GetDatastores(ctx context.Context, s *session.Session, dsURLs map[string]*url.URL) (map[string]*Helper, error) { stores := make(map[string]*Helper) fm := object.NewFileManager(s.Vim25()) for name, dsURL := range dsURLs { vsDs, err := s.Finder.DatastoreOrDefault(ctx, s.DatastorePath) if err != nil { return nil, err } d := &Helper{ ds: vsDs, s: s, fm: fm, RootURL: dsURL.Path, } stores[name] = d } return stores, nil }
func (cmd *mkdir) Run(f *flag.FlagSet) error { args := f.Args() if len(args) == 0 { return errors.New("missing operand") } c, err := cmd.Client() if err != nil { return err } dc, err := cmd.Datacenter() if err != nil { return err } // TODO(PN): Accept multiple args path, err := cmd.DatastorePath(args[0]) if err != nil { return err } m := object.NewFileManager(c) err = m.MakeDirectory(context.TODO(), path, dc, cmd.createParents) // ignore EEXIST if -p flag is given if err != nil && cmd.createParents { if soap.IsSoapFault(err) { soapFault := soap.ToSoapFault(err) if _, ok := soapFault.VimFault().(types.FileAlreadyExists); ok { return nil } } } return err }
// NewDatastore returns a Datastore. // ctx is a context, // s is an authenticated session // ds is the vsphere datastore // rootdir is the top level directory to root all data. If root does not exist, // it will be created. If it already exists, NOOP. This cannot be empty. func NewHelper(ctx context.Context, s *session.Session, ds *object.Datastore, rootdir string) (*Helper, error) { d := &Helper{ ds: ds, s: s, fm: object.NewFileManager(s.Vim25()), } if path.IsAbs(rootdir) { rootdir = rootdir[1:] } if err := d.mkRootDir(ctx, rootdir); err != nil { log.Infof("error creating root directory %s: %s", rootdir, err) return nil, err } if d.RootURL == "" { return nil, fmt.Errorf("failed to create root directory") } log.Infof("Datastore path is %s", d.RootURL) return d, nil }
func (cmd *mv) Run(f *flag.FlagSet) error { args := f.Args() if len(args) != 2 { return errors.New("SRC and DST arguments are required") } c, err := cmd.Client() if err != nil { return err } dc, err := cmd.Datacenter() if err != nil { return err } // TODO: support cross-datacenter move src, err := cmd.DatastorePath(args[0]) if err != nil { return err } dst, err := cmd.DatastorePath(args[1]) if err != nil { return err } m := object.NewFileManager(c) task, err := m.MoveDatastoreFile(context.TODO(), src, dc, dst, dc, cmd.force) if err != nil { return err } return task.Wait(context.TODO()) }
func (d *Driver) Remove() error { machineState, err := d.GetState() if err != nil { return err } if machineState == state.Running { if err = d.Kill(); err != nil { return fmt.Errorf("can't stop VM: %s", err) } } ctx, cancel := context.WithCancel(context.Background()) defer cancel() c, err := d.vsphereLogin(ctx) if err != nil { return err } defer c.Logout(ctx) // Create a new finder f := find.NewFinder(c.Client, true) dc, err := f.DatacenterOrDefault(ctx, d.Datacenter) if err != nil { return err } f.SetDatacenter(dc) dss, err := f.DatastoreOrDefault(ctx, d.Datastore) if err != nil { return err } // Remove B2D Iso from VM folder m := object.NewFileManager(c.Client) task, err := m.DeleteDatastoreFile(ctx, dss.Path(fmt.Sprintf("%s/%s", d.MachineName, isoFilename)), dc) if err != nil { return err } err = task.Wait(ctx) if err != nil { if types.IsFileNotFound(err) { // Ignore error return nil } } vm, err := d.fetchVM(c, ctx, d.MachineName) if err != nil { return err } task, err = vm.Destroy(ctx) if err != nil { return err } _, err = task.WaitForResult(ctx, nil) if err != nil { return err } return nil }
func (c *Container) Remove(ctx context.Context, sess *session.Session) error { defer trace.End(trace.Begin("Container.Remove")) c.Lock() defer c.Unlock() if c.vm == nil { return NotFoundError{} } // check state first if c.State == StateRunning { return RemovePowerError{fmt.Errorf("Container is powered on")} } // get existing state and set to removing // if there's a failure we'll revert to existing existingState := c.State c.State = StateRemoving // get the folder the VM is in url, err := c.vm.DSPath(ctx) if err != nil { // handle the out-of-band removal case if soap.IsSoapFault(err) { fault := soap.ToSoapFault(err).VimFault() if _, ok := fault.(types.ManagedObjectNotFound); ok { containers.Remove(c.ExecConfig.ID) return NotFoundError{} } } log.Errorf("Failed to get datastore path for %s: %s", c.ExecConfig.ID, err) c.State = existingState return err } // FIXME: was expecting to find a utility function to convert to/from datastore/url given // how widely it's used but couldn't - will ask around. dsPath := fmt.Sprintf("[%s] %s", url.Host, url.Path) //removes the vm from vsphere, but detaches the disks first _, err = tasks.WaitForResult(ctx, func(ctx context.Context) (tasks.ResultWaiter, error) { return c.vm.DeleteExceptDisks(ctx) }) if err != nil { c.State = existingState return err } // remove from datastore fm := object.NewFileManager(c.vm.Client.Client) if _, err = tasks.WaitForResult(ctx, func(ctx context.Context) (tasks.ResultWaiter, error) { return fm.DeleteDatastoreFile(ctx, dsPath, sess.Datacenter) }); err != nil { c.State = existingState log.Debugf("Failed to delete %s, %s", dsPath, err) } //remove container from cache containers.Remove(c.ExecConfig.ID) return nil }
// Create a disk, make an ext filesystem on it, set the label, mount it, // unmount it, then clean up. func TestCreateFS(t *testing.T) { log.SetLevel(log.DebugLevel) client := Session(context.Background(), t) if client == nil { return } imagestore := client.Datastore.Path(datastore.TestName("diskTest")) fm := object.NewFileManager(client.Vim25()) // create a directory in the datastore // eat the error because we dont care if it exists fm.MakeDirectory(context.TODO(), imagestore, nil, true) // Nuke the image store defer func() { task, err := fm.DeleteDatastoreFile(context.TODO(), imagestore, nil) if err != nil && err.Error() == "can't find the hosting vm" { t.Skip("Skipping: test must be run in a VM") } if !assert.NoError(t, err) { return } _, err = task.WaitForResult(context.TODO(), nil) if !assert.NoError(t, err) { return } }() op := trace.NewOperation(context.TODO(), "test") vdm, err := NewDiskManager(op, client) if err != nil && err.Error() == "can't find the hosting vm" { t.Skip("Skipping: test must be run in a VM") } if !assert.NoError(t, err) || !assert.NotNil(t, vdm) { return } diskSize := int64(1 << 10) d, err := vdm.CreateAndAttach(op, path.Join(imagestore, "scratch.vmdk"), "", diskSize, os.O_RDWR) if !assert.NoError(t, err) { return } // make the filesysetem if err = d.Mkfs("foo"); !assert.NoError(t, err) { return } // set the label if err = d.SetLabel("foo"); !assert.NoError(t, err) { return } // make a tempdir to mount the fs to dir, err := ioutil.TempDir("", "mnt") if !assert.NoError(t, err) { return } defer os.RemoveAll(dir) // do the mount err = d.Mount(dir, nil) if !assert.NoError(t, err) { return } // boom if mounted, err := mount.Mounted(dir); !assert.NoError(t, err) || !assert.True(t, mounted) { return } // clean up err = d.Unmount() if !assert.NoError(t, err) { return } err = vdm.Detach(op, d) if !assert.NoError(t, err) { return } }
// Remove removes a containerVM after detaching the disks func (c *Container) Remove(ctx context.Context, sess *session.Session) error { defer trace.End(trace.Begin(c.ExecConfig.ID)) c.m.Lock() defer c.m.Unlock() if c.vm == nil { return NotFoundError{} } // check state first if c.state == StateRunning { return RemovePowerError{fmt.Errorf("Container is powered on")} } // get existing state and set to removing // if there's a failure we'll revert to existing existingState := c.updateState(StateRemoving) // get the folder the VM is in url, err := c.vm.DSPath(ctx) if err != nil { // handle the out-of-band removal case if soap.IsSoapFault(err) { fault := soap.ToSoapFault(err).VimFault() if _, ok := fault.(types.ManagedObjectNotFound); ok { Containers.Remove(c.ExecConfig.ID) return NotFoundError{} } } log.Errorf("Failed to get datastore path for %s: %s", c.ExecConfig.ID, err) c.updateState(existingState) return err } // FIXME: was expecting to find a utility function to convert to/from datastore/url given // how widely it's used but couldn't - will ask around. dsPath := fmt.Sprintf("[%s] %s", url.Host, url.Path) //removes the vm from vsphere, but detaches the disks first _, err = c.vm.WaitForResult(ctx, func(ctx context.Context) (tasks.Task, error) { return c.vm.DeleteExceptDisks(ctx) }) if err != nil { f, ok := err.(types.HasFault) if !ok { c.updateState(existingState) return err } switch f.Fault().(type) { case *types.InvalidState: log.Warnf("container VM is in invalid state, unregistering") if err := c.vm.Unregister(ctx); err != nil { log.Errorf("Error while attempting to unregister container VM: %s", err) return err } default: log.Debugf("Fault while attempting to destroy vm: %#v", f.Fault()) c.updateState(existingState) return err } } // remove from datastore fm := object.NewFileManager(c.vm.Client.Client) if _, err = tasks.WaitForResult(ctx, func(ctx context.Context) (tasks.Task, error) { return fm.DeleteDatastoreFile(ctx, dsPath, sess.Datacenter) }); err != nil { // at this phase error doesn't matter. Just log it. log.Debugf("Failed to delete %s, %s", dsPath, err) } //remove container from cache Containers.Remove(c.ExecConfig.ID) return nil }
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") } } } }
// Create a lineage of disks inheriting from eachother, write portion of a // string to each, the confirm the result is the whole string func TestCreateAndDetach(t *testing.T) { log.SetLevel(log.DebugLevel) client := Session(context.Background(), t) if client == nil { return } imagestore := client.Datastore.Path(datastore.TestName("diskManagerTest")) fm := object.NewFileManager(client.Vim25()) // create a directory in the datastore // eat the error because we dont care if it exists fm.MakeDirectory(context.TODO(), imagestore, nil, true) vdm, err := NewDiskManager(context.TODO(), client) if err != nil && err.Error() == "can't find the hosting vm" { t.Skip("Skipping: test must be run in a VM") } if !assert.NoError(t, err) || !assert.NotNil(t, vdm) { return } diskSize := int64(1 << 10) parent, err := vdm.Create(context.TODO(), path.Join(imagestore, "scratch.vmdk"), diskSize) if !assert.NoError(t, err) { return } numChildren := 3 children := make([]*VirtualDisk, numChildren) testString := "Ground control to Major Tom" writeSize := len(testString) / numChildren // Create children which inherit from eachother for i := 0; i < numChildren; i++ { p := path.Join(imagestore, fmt.Sprintf("child%d.vmdk", i)) child, cerr := vdm.CreateAndAttach(context.TODO(), p, parent.DatastoreURI, 0, os.O_RDWR) if !assert.NoError(t, cerr) { return } children[i] = child // Write directly to the disk f, cerr := os.OpenFile(child.DevicePath, os.O_RDWR, os.FileMode(0777)) if !assert.NoError(t, cerr) { return } start := i * writeSize end := start + writeSize if i == numChildren-1 { // last chunk, write to the end. _, cerr = f.WriteAt([]byte(testString[start:]), int64(start)) if !assert.NoError(t, cerr) || !assert.NoError(t, f.Sync()) { return } // Try to read the whole string b := make([]byte, len(testString)) f.Seek(0, 0) _, cerr = f.Read(b) if !assert.NoError(t, cerr) { return } //check against the test string if !assert.Equal(t, testString, string(b)) { return } } else { _, cerr = f.WriteAt([]byte(testString[start:end]), int64(start)) if !assert.NoError(t, cerr) || !assert.NoError(t, f.Sync()) { return } } f.Close() cerr = vdm.Detach(context.TODO(), child) if !assert.NoError(t, cerr) { return } // use this image as the next parent parent = child } // // Nuke the images // for i := len(children) - 1; i >= 0; i-- { // err = vdm.Delete(context.TODO(), children[i]) // if !assert.NoError(t, err) { // return // } // } // Nuke the image store _, err = tasks.WaitForResult(context.TODO(), func(ctx context.Context) (tasks.ResultWaiter, error) { return fm.DeleteDatastoreFile(ctx, imagestore, nil) }) if !assert.NoError(t, err) { return } }
func resourceVSphereFileUpdate(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] updating file: %#v", d) if d.HasChange("destination_file") || d.HasChange("datacenter") || d.HasChange("datastore") { // File needs to be moved, get old and new destination changes var oldDataceneter, newDatacenter, oldDatastore, newDatastore, oldDestinationFile, newDestinationFile string if d.HasChange("datacenter") { tmpOldDataceneter, tmpNewDatacenter := d.GetChange("datacenter") oldDataceneter = tmpOldDataceneter.(string) newDatacenter = tmpNewDatacenter.(string) } else { if v, ok := d.GetOk("datacenter"); ok { oldDataceneter = v.(string) newDatacenter = oldDataceneter } } if d.HasChange("datastore") { tmpOldDatastore, tmpNewDatastore := d.GetChange("datastore") oldDatastore = tmpOldDatastore.(string) newDatastore = tmpNewDatastore.(string) } else { oldDatastore = d.Get("datastore").(string) newDatastore = oldDatastore } if d.HasChange("destination_file") { tmpOldDestinationFile, tmpNewDestinationFile := d.GetChange("destination_file") oldDestinationFile = tmpOldDestinationFile.(string) newDestinationFile = tmpNewDestinationFile.(string) } else { oldDestinationFile = d.Get("destination_file").(string) newDestinationFile = oldDestinationFile } // Get old and new dataceter and datastore client := meta.(*govmomi.Client) dcOld, err := getDatacenter(client, oldDataceneter) if err != nil { return err } dcNew, err := getDatacenter(client, newDatacenter) if err != nil { return err } finder := find.NewFinder(client.Client, true) finder = finder.SetDatacenter(dcOld) dsOld, err := getDatastore(finder, oldDatastore) if err != nil { return fmt.Errorf("error %s", err) } finder = finder.SetDatacenter(dcNew) dsNew, err := getDatastore(finder, newDatastore) if err != nil { return fmt.Errorf("error %s", err) } // Move file between old/new dataceter, datastore and path (destination_file) fm := object.NewFileManager(client.Client) task, err := fm.MoveDatastoreFile(context.TODO(), dsOld.Path(oldDestinationFile), dcOld, dsNew.Path(newDestinationFile), dcNew, true) if err != nil { return err } _, err = task.WaitForResult(context.TODO(), nil) if err != nil { return err } } return nil }
func TestVolumeCreateListAndRestart(t *testing.T) { client := datastore.Session(context.TODO(), t) if client == nil { return } ctx := context.TODO() // Create the backing store on vsphere vsVolumeStore, err := NewVolumeStore(ctx, client) if !assert.NoError(t, err) || !assert.NotNil(t, vsVolumeStore) { return } // Root our datastore testStorePath := datastore.TestName("voltest") ds, err := datastore.NewHelper(ctx, client, client.Datastore, testStorePath) if !assert.NoError(t, err) || !assert.NotNil(t, ds) { return } // Add a volume store and give it a name ("testStoreName") volumeStore, err := vsVolumeStore.AddStore(ctx, ds, "testStoreName") if !assert.NoError(t, err) || !assert.NotNil(t, volumeStore) { return } // test we can list it m, err := vsVolumeStore.VolumeStoresList(ctx) if !assert.NoError(t, err) || !assert.NotNil(t, m) { return } // test the returned url matches s, ok := m["testStoreName"] if !assert.True(t, ok) || !assert.Equal(t, testStorePath, filepath.Base(s.String())) { return } // Clean up the mess defer func() { fm := object.NewFileManager(client.Vim25()) tasks.WaitForResult(context.TODO(), func(ctx context.Context) (tasks.ResultWaiter, error) { return fm.DeleteDatastoreFile(ctx, client.Datastore.Path(testStorePath), client.Datacenter) }) }() // Create the cache cache, err := portlayer.NewVolumeLookupCache(ctx, vsVolumeStore) if !assert.NoError(t, err) || !assert.NotNil(t, cache) { return } // Create the volumes (in parallel) numVols := 5 wg := &sync.WaitGroup{} wg.Add(numVols) volumes := make(map[string]*portlayer.Volume) for i := 0; i < numVols; i++ { go func(idx int) { defer wg.Done() ID := fmt.Sprintf("testvolume-%d", idx) // add some metadata if i is even var info map[string][]byte if idx%2 == 0 { info = make(map[string][]byte) info[ID] = []byte(ID) } outVol, err := cache.VolumeCreate(ctx, ID, volumeStore, 10240, info) if !assert.NoError(t, err) || !assert.NotNil(t, outVol) { return } volumes[ID] = outVol }(i) } wg.Wait() // list using the datastore (skipping the cache) outVols, err := vsVolumeStore.VolumesList(ctx) if !assert.NoError(t, err) || !assert.NotNil(t, outVols) || !assert.Equal(t, numVols, len(outVols)) { return } for _, outVol := range outVols { if !assert.Equal(t, volumes[outVol.ID], outVol) { return } } // Test restart // Create a new vs and cache to the same datastore (simulating restart) and compare secondVStore, err := NewVolumeStore(ctx, client) if !assert.NoError(t, err) || !assert.NotNil(t, vsVolumeStore) { return } volumeStore, err = secondVStore.AddStore(ctx, ds, "testStoreName") if !assert.NoError(t, err) || !assert.NotNil(t, volumeStore) { return } secondCache, err := portlayer.NewVolumeLookupCache(ctx, secondVStore) if !assert.NoError(t, err) || !assert.NotNil(t, cache) { return } secondOutVols, err := secondCache.VolumesList(ctx) if !assert.NoError(t, err) || !assert.NotNil(t, secondOutVols) || !assert.Equal(t, numVols, len(secondOutVols)) { return } for _, outVol := range secondOutVols { // XXX we could compare the Volumes, but the paths are different the // second time around on vsan since the vsan UUID is not included. if !assert.NotEmpty(t, volumes[outVol.ID].Device.DiskPath()) { return } } }
func createFile(client *govmomi.Client, f *file) error { finder := find.NewFinder(client.Client, true) dc, err := finder.Datacenter(context.TODO(), f.datacenter) if err != nil { return fmt.Errorf("error %s", err) } finder = finder.SetDatacenter(dc) ds, err := getDatastore(finder, f.datastore) if err != nil { return fmt.Errorf("error %s", err) } if f.copyFile { // Copying file from withing vSphere source_dc, err := finder.Datacenter(context.TODO(), f.sourceDatacenter) if err != nil { return fmt.Errorf("error %s", err) } finder = finder.SetDatacenter(dc) source_ds, err := getDatastore(finder, f.sourceDatastore) if err != nil { return fmt.Errorf("error %s", err) } fm := object.NewFileManager(client.Client) if f.createDirectories { directoryPathIndex := strings.LastIndex(f.destinationFile, "/") path := f.destinationFile[0:directoryPathIndex] err = fm.MakeDirectory(context.TODO(), ds.Path(path), dc, true) if err != nil { return fmt.Errorf("error %s", err) } } task, err := fm.CopyDatastoreFile(context.TODO(), source_ds.Path(f.sourceFile), source_dc, ds.Path(f.destinationFile), dc, true) if err != nil { return fmt.Errorf("error %s", err) } _, err = task.WaitForResult(context.TODO(), nil) if err != nil { return fmt.Errorf("error %s", err) } } else { // Uploading file to vSphere dsurl, err := ds.URL(context.TODO(), dc, f.destinationFile) if err != nil { return fmt.Errorf("error %s", err) } p := soap.DefaultUpload err = client.Client.UploadFile(f.sourceFile, dsurl, &p) if err != nil { return fmt.Errorf("error %s", err) } } return nil }