// The user wants to create a volume. // No need to actually manifest the volume on the filesystem yet // (until Mount is called). // Name and driver specific options passed through to the ESX host func (d *vmdkDriver) Create(r volume.Request) volume.Response { // Use default fstype if not specified if _, result := r.Options["fstype"]; result == false { r.Options["fstype"] = fs.FstypeDefault } // Get existent filesystem tools supportedFs := fs.MkfsLookup() // Verify the existence of fstype mkfs mkfscmd, result := supportedFs[r.Options["fstype"]] if result == false { msg := "Not found mkfs for " + r.Options["fstype"] msg += "\nSupported filesystems found: " validfs := "" for fs := range supportedFs { if validfs != "" { validfs += ", " + fs } else { validfs += fs } } log.WithFields(log.Fields{"name": r.Name, "fstype": r.Options["fstype"]}).Error("Not found ") return volume.Response{Err: msg + validfs} } errCreate := d.ops.Create(r.Name, r.Options) if errCreate != nil { log.WithFields(log.Fields{"name": r.Name, "error": errCreate}).Error("Create volume failed ") return volume.Response{Err: errCreate.Error()} } // Handle filesystem creation log.WithFields(log.Fields{"name": r.Name, "fstype": r.Options["fstype"]}).Info("Attaching volume and creating filesystem ") dev, errAttach := d.ops.Attach(r.Name, nil) if errAttach != nil { log.WithFields(log.Fields{"name": r.Name, "error": errAttach}).Error("Attach volume failed, removing the volume ") errRemove := d.ops.Remove(r.Name, nil) if errRemove != nil { log.WithFields(log.Fields{"name": r.Name, "error": errRemove}).Warning("Remove volume failed ") } return volume.Response{Err: errAttach.Error()} } device, errGetDevicePath := fs.GetDevicePath(dev) if errGetDevicePath != nil { log.WithFields(log.Fields{"name": r.Name, "error": errGetDevicePath}).Error("Could not find attached device, removing the volume ") errDetach := d.ops.Detach(r.Name, nil) if errDetach != nil { log.WithFields(log.Fields{"name": r.Name, "error": errDetach}).Warning("Detach volume failed ") } errRemove := d.ops.Remove(r.Name, nil) if errRemove != nil { log.WithFields(log.Fields{"name": r.Name, "error": errRemove}).Warning("Remove volume failed ") } return volume.Response{Err: errGetDevicePath.Error()} } errMkfs := fs.Mkfs(mkfscmd, r.Name, device) if errMkfs != nil { log.WithFields(log.Fields{"name": r.Name, "error": errMkfs}).Error("Create filesystem failed, removing the volume ") errDetach := d.ops.Detach(r.Name, nil) if errDetach != nil { log.WithFields(log.Fields{"name": r.Name, "error": errDetach}).Warning("Detach volume failed ") } errRemove := d.ops.Remove(r.Name, nil) if errRemove != nil { log.WithFields(log.Fields{"name": r.Name, "error": errRemove}).Warning("Remove volume failed ") } return volume.Response{Err: errMkfs.Error()} } errDetach := d.ops.Detach(r.Name, nil) if errDetach != nil { log.WithFields(log.Fields{"name": r.Name, "error": errDetach}).Error("Detach volume failed ") return volume.Response{Err: errDetach.Error()} } log.WithFields(log.Fields{"name": r.Name, "fstype": r.Options["fstype"]}).Info("Volume and filesystem created ") return volume.Response{Err: ""} }
// Request attach and them mounts the volume. // Actual mount - send attach to ESX and do the in-guest magic // Returns mount point and error (or nil) func (d *vmdkDriver) mountVolume(name string, fstype string, isReadOnly bool) (string, error) { mountpoint := getMountPoint(name) // First, make sure that mountpoint exists. err := fs.Mkdir(mountpoint) if err != nil { log.WithFields( log.Fields{"name": name, "dir": mountpoint}, ).Error("Failed to make directory for volume mount ") return mountpoint, err } skipInotify := false watcher, err := inotify.NewWatcher() if err != nil { log.WithFields( log.Fields{"name": name, "dir": mountpoint}, ).Error("Failed to create watcher, skip inotify ") skipInotify = true } else { err = watcher.Watch(watchPath) if err != nil { log.WithFields( log.Fields{"name": name, "dir": mountpoint}, ).Error("Failed to watch /dev, skip inotify ") skipInotify = true } } // Have ESX attach the disk dev, err := d.ops.Attach(name, nil) if err != nil { return mountpoint, err } if d.useMockEsx { return mountpoint, fs.Mount(mountpoint, fstype, string(dev[:]), false) } device, err := fs.GetDevicePath(dev) if err != nil { return mountpoint, err } if skipInotify { time.Sleep(sleepBeforeMount) return mountpoint, fs.Mount(mountpoint, fstype, device, false) } loop: for { select { case ev := <-watcher.Event: log.Debug("event: ", ev) if ev.Name == device { // Log when the device is discovered log.WithFields( log.Fields{"name": name, "event": ev}, ).Info("Attach complete ") break loop } case err := <-watcher.Error: log.WithFields( log.Fields{"name": name, "device": device, "error": err}, ).Error("Hit error during watch ") break loop case <-time.After(devWaitTimeout): log.WithFields( log.Fields{"name": name, "timeout": devWaitTimeout, "device": device}, ).Warning("Reached timeout while waiting for device, trying to mount anyways ") break loop } } return mountpoint, fs.Mount(mountpoint, fstype, device, isReadOnly) }