Example #1
0
// 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: ""}
}
Example #2
0
// 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)
}