Exemple #1
0
func (d *Driver) MountVolume(id string, opts map[string]string) (string, error) {
	volume := d.blankVolume(id)
	if err := util.ObjectLoad(volume); err != nil {
		return "", err
	}
	dev, err := d.GetVolumeDevice(id)
	if err != nil {
		return "", err
	}
	specifiedPoint := opts[convoydriver.OPT_MOUNT_POINT]
	mountPoint, err := d.getVolumeMountPoint(id, specifiedPoint)
	if err != nil {
		return "", err
	}
	if volume.MountPoint != "" && volume.MountPoint != mountPoint {
		return "", fmt.Errorf("volume %v already mounted at %v, but asked to mount at %v", id, volume.MountPoint, mountPoint)
	}
	if !mounted(dev, mountPoint) {
		log.Debugf("Volume %v is not mounted, mount it now to %v", id, mountPoint)
		_, err = util.Execute(MOUNT_BINARY, []string{dev, mountPoint})
		if err != nil {
			return "", err
		}
	}
	volume.MountPoint = mountPoint
	if err := util.ObjectSave(volume); err != nil {
		return "", err
	}

	return mountPoint, nil
}
Exemple #2
0
func (d *Driver) doCreateVolume(volume *Volume, stack *Stack, id string, opts map[string]string) error {
	// Doing find just to see if we are creating versus using an existing stack
	env, err := stack.Find()
	if err != nil {
		return err
	}

	// Always run create because it also ensures that things are active
	if _, err := stack.Create(); err != nil {
		return err
	}

	// If env was nil then we created stack so we need to format
	if env == nil {
		dev, _ := volume.GetDevice()
		err := Backoff(5*time.Minute, fmt.Sprintf("Failed to find %s", dev), func() (bool, error) {
			if _, err := os.Stat(dev); err == nil {
				return true, nil
			}
			return false, nil
		})
		if err != nil {
			return err
		}

		log.Infof("Formatting %s", dev)
		if _, err := util.Execute("mkfs.ext4", []string{dev}); err != nil {
			return err
		}
	}

	return util.ObjectSave(volume)
}
Exemple #3
0
func (d *Driver) CompareSnapshot(id, compareID, volumeID string) (*metadata.Mappings, error) {
	includeSame := false
	if compareID == "" || compareID == id {
		compareID = id
		includeSame = true
	}
	snap1, _, err := d.getSnapshotAndVolume(id, volumeID)
	if err != nil {
		return nil, err
	}
	snap2, _, err := d.getSnapshotAndVolume(compareID, volumeID)
	if err != nil {
		return nil, err
	}

	dev := d.MetadataDevice
	out, err := util.Execute(THIN_PROVISION_TOOLS_BINARY, []string{"thin_delta",
		"--snap1", strconv.Itoa(snap1.DevID),
		"--snap2", strconv.Itoa(snap2.DevID),
		dev})
	if err != nil {
		return nil, err
	}
	mapping, err := metadata.DeviceMapperThinDeltaParser([]byte(out), d.ThinpoolBlockSize*SECTOR_SIZE, includeSame)
	if err != nil {
		return nil, err
	}

	return mapping, err
}
func (v *VfsObjectStoreDriver) Download(src, dst string) error {
	_, err := util.Execute("cp", []string{v.updatePath(src), dst})
	if err != nil {
		return err
	}
	return nil
}
func (v *VfsObjectStoreDriver) Upload(src, dst string) error {
	tmpDst := dst + ".tmp"
	if v.FileExists(tmpDst) {
		v.Remove(tmpDst)
	}
	if err := v.preparePath(dst); err != nil {
		return err
	}
	_, err := util.Execute("cp", []string{src, v.updatePath(tmpDst)})
	if err != nil {
		return err
	}
	_, err = util.Execute("mv", []string{v.updatePath(tmpDst), v.updatePath(dst)})
	if err != nil {
		return err
	}
	return nil
}
func (v *VfsObjectStoreDriver) List(path string) ([]string, error) {
	out, err := util.Execute("ls", []string{"-1", v.updatePath(path)})
	if err != nil {
		return nil, err
	}
	var result []string
	if len(out) == 0 {
		return result, nil
	}
	result = strings.Split(strings.TrimSpace(string(out)), "\n")
	return result, nil
}
Exemple #7
0
func mounted(dev, mountPoint string) bool {
	output, err := util.Execute(MOUNT_BINARY, []string{})
	if err != nil {
		return false
	}
	lines := strings.Split(output, "\n")
	for _, line := range lines {
		if strings.Contains(line, dev) && strings.Contains(line, mountPoint) {
			return true
		}
	}
	return false
}
Exemple #8
0
func (d *Driver) UmountVolume(id string) error {
	volume := d.blankVolume(id)
	if err := util.ObjectLoad(volume); err != nil {
		return err
	}
	if volume.MountPoint == "" {
		log.Debugf("Umount a umounted volume %v", id)
		return nil
	}
	if _, err := util.Execute(UMOUNT_BINARY, []string{volume.MountPoint}); err != nil {
		return err
	}
	d.putVolumeMountPoint(volume.MountPoint)

	volume.MountPoint = ""
	if err := util.ObjectSave(volume); err != nil {
		return err
	}

	return nil
}
Exemple #9
0
func (d *Driver) DeleteVolume(id string, opts map[string]string) error {
	d.mutex.Lock()
	defer d.mutex.Unlock()

	volume := d.blankVolume(id)
	if err := util.ObjectLoad(volume); err != nil {
		return err
	}

	if volume.MountPoint != "" {
		return fmt.Errorf("Cannot delete volume %v. It is still mounted", id)
	}
	referenceOnly, _ := strconv.ParseBool(opts[convoydriver.OPT_REFERENCE_ONLY])
	if !referenceOnly {
		log.Debugf("Cleaning up %v for volume %v", volume.Path, id)
		if out, err := util.Execute("rm", []string{"-rf", volume.Path}); err != nil {
			return fmt.Errorf("Fail to cleanup the volume, output: %v, error: %v", out, err.Error())
		}
	}
	return util.ObjectDelete(volume)
}
Exemple #10
0
func (d *Driver) CreateVolume(id string, opts map[string]string) error {
	var (
		size int64
		err  error
	)
	backupURL := opts[convoydriver.OPT_BACKUP_URL]
	if backupURL != "" {
		objVolume, err := objectstore.LoadVolume(backupURL)
		if err != nil {
			return err
		}
		if objVolume.Driver != d.Name() {
			return fmt.Errorf("Cannot restore backup of %v to %v", objVolume.Driver, d.Name())
		}
		size, err = d.getSize(opts, objVolume.Size)
		if err != nil {
			return err
		}
		if size != objVolume.Size {
			return fmt.Errorf("Volume size must match with backup's size")
		}
	} else {
		size, err = d.getSize(opts, d.DefaultVolumeSize)
		if err != nil {
			return err
		}
	}

	if size%(d.ThinpoolBlockSize*SECTOR_SIZE) != 0 {
		return fmt.Errorf("Size must be multiple of block size")

	}
	volume := d.blankVolume(id)
	exists, err := util.ObjectExists(volume)
	if err != nil {
		return err
	}
	if exists {
		return generateError(logrus.Fields{
			LOG_FIELD_VOLUME: id,
		}, "Already has volume with specific uuid")
	}

	devID, err := d.allocateDevID()
	if err != nil {
		return err
	}
	log.WithFields(logrus.Fields{
		LOG_FIELD_REASON:          LOG_REASON_START,
		LOG_FIELD_EVENT:           LOG_EVENT_CREATE,
		LOG_FIELD_OBJECT:          LOG_OBJECT_VOLUME,
		LOG_FIELD_VOLUME:          id,
		DM_LOG_FIELD_VOLUME_DEVID: devID,
	}).Debugf("Creating volume")
	err = devicemapper.CreateDevice(d.ThinpoolDevice, devID)
	if err != nil {
		return err
	}

	log.WithFields(logrus.Fields{
		LOG_FIELD_REASON:          LOG_REASON_START,
		LOG_FIELD_EVENT:           LOG_EVENT_ACTIVATE,
		LOG_FIELD_OBJECT:          LOG_OBJECT_VOLUME,
		LOG_FIELD_VOLUME:          id,
		DM_LOG_FIELD_VOLUME_DEVID: devID,
	}).Debugf("Activating device for volume")
	err = devicemapper.ActivateDevice(d.ThinpoolDevice, id, devID, uint64(size))
	if err != nil {
		log.WithFields(logrus.Fields{
			LOG_FIELD_REASON:          LOG_REASON_ROLLBACK,
			LOG_FIELD_EVENT:           LOG_EVENT_REMOVE,
			LOG_FIELD_OBJECT:          LOG_OBJECT_VOLUME,
			LOG_FIELD_VOLUME:          id,
			DM_LOG_FIELD_VOLUME_DEVID: devID,
		}).Debugf("Removing device for volume due to fail to activate")
		if err := devicemapper.DeleteDevice(d.ThinpoolDevice, devID); err != nil {
			log.WithFields(logrus.Fields{
				LOG_FIELD_REASON:          LOG_REASON_FAILURE,
				LOG_FIELD_EVENT:           LOG_EVENT_REMOVE,
				LOG_FIELD_OBJECT:          LOG_OBJECT_VOLUME,
				LOG_FIELD_VOLUME:          id,
				DM_LOG_FIELD_VOLUME_DEVID: devID,
			}).Debugf("Failed to remove device")
		}
		return err
	}

	volume.DevID = devID
	volume.Size = size
	volume.Snapshots = make(map[string]Snapshot)
	if err := util.ObjectSave(volume); err != nil {
		return err
	}

	dev, err := d.GetVolumeDevice(id)
	if err != nil {
		return err
	}
	if backupURL == "" {
		// format the device
		if _, err := util.Execute("mkfs", []string{"-t", "ext4", dev}); err != nil {
			return err
		}
	} else {
		if err := objectstore.RestoreDeltaBlockBackup(backupURL, dev); err != nil {
			return err
		}
	}

	return nil
}
Exemple #11
0
func (d *Driver) CreateVolume(id string, opts map[string]string) error {
	var (
		err        error
		volumeSize int64
		format     bool
		snapshot   *Snapshot
	)

	d.mutex.Lock()
	defer d.mutex.Unlock()

	volume := d.blankVolume(id)
	exists, err := util.ObjectExists(volume)
	if err != nil {
		return err
	}
	if exists {
		return fmt.Errorf("Volume %v already exists", id)
	}

	//EBS volume ID
	volumeID := opts[convoydriver.OPT_VOLUME_ID]
	backupURL := opts[convoydriver.OPT_BACKUP_URL]
	if backupURL != "" && volumeID != "" {
		return fmt.Errorf("Cannot specify both backup and EBS volume ID")
	}

	newTags := map[string]string{
		"Name":             opts[convoydriver.OPT_VOLUME_NAME],
		"ConvoyVolumeUUID": id,
	}
	if volumeID != "" {
		ebsVolume, err := d.ebsService.GetVolume(volumeID)
		if err != nil {
			return err
		}
		volumeSize = *ebsVolume.Size * GB
		log.Debugf("Found EBS volume %v for volume %v, update tags", volumeID, id)
		if err := d.ebsService.AddTags(volumeID, newTags); err != nil {
			log.Debugf("Failed to update tags for volume %v, but continue", volumeID)
		}
	} else if backupURL != "" {
		region, ebsSnapshotID, err := decodeURL(backupURL)
		if err != nil {
			return err
		}
		if region != d.ebsService.Region {
			// We don't want to automatically copy snapshot here
			// because it's way too time consuming.
			return fmt.Errorf("Snapshot %v is at %v rather than current region %v. Copy snapshot is needed",
				ebsSnapshotID, region, d.ebsService.Region)
		}
		if err := d.ebsService.WaitForSnapshotComplete(ebsSnapshotID); err != nil {
			return err
		}
		log.Debugf("Snapshot %v is ready", ebsSnapshotID)
		ebsSnapshot, err := d.ebsService.GetSnapshot(ebsSnapshotID)
		if err != nil {
			return err
		}
		snapshot = &Snapshot{
			UUID:       uuid.New(),
			VolumeUUID: id,
			EBSID:      ebsSnapshotID,
		}

		snapshotVolumeSize := *ebsSnapshot.VolumeSize * GB
		volumeSize, err = d.getSize(opts, snapshotVolumeSize)
		if err != nil {
			return err
		}
		if volumeSize < snapshotVolumeSize {
			return fmt.Errorf("Volume size cannot be less than snapshot size %v", snapshotVolumeSize)
		}
		volumeType, iops, err := d.getTypeAndIOPS(opts)
		if err != nil {
			return err
		}
		r := &CreateEBSVolumeRequest{
			Size:       volumeSize,
			SnapshotID: ebsSnapshotID,
			VolumeType: volumeType,
			IOPS:       iops,
			Tags:       newTags,
		}
		volumeID, err = d.ebsService.CreateVolume(r)
		if err != nil {
			return err
		}
		log.Debugf("Created volume %v from EBS snapshot %v", id, ebsSnapshotID)
	} else {

		// Create a new EBS volume
		volumeSize, err = d.getSize(opts, d.DefaultVolumeSize)
		if err != nil {
			return err
		}
		volumeType, iops, err := d.getTypeAndIOPS(opts)
		if err != nil {
			return err
		}
		r := &CreateEBSVolumeRequest{
			Size:       volumeSize,
			VolumeType: volumeType,
			IOPS:       iops,
			Tags:       newTags,
		}
		volumeID, err = d.ebsService.CreateVolume(r)
		if err != nil {
			return err
		}
		log.Debugf("Created volume %v from EBS volume %v", id, volumeID)
		format = true
	}

	dev, err := d.ebsService.AttachVolume(volumeID, volumeSize)
	if err != nil {
		return err
	}
	log.Debugf("Attached EBS volume %v to %v", volumeID, dev)

	volume.EBSID = volumeID
	volume.Device = dev
	volume.Snapshots = make(map[string]Snapshot)
	if snapshot != nil {
		volume.Snapshots[snapshot.UUID] = *snapshot
	}

	// We don't format existing or snapshot restored volume
	if format {
		if _, err := util.Execute("mkfs", []string{"-t", "ext4", dev}); err != nil {
			return err
		}
	}

	return util.ObjectSave(volume)
}