Beispiel #1
0
func (dc *DaemonConfig) pruneSnapshots(val *config.Volume) {
	logrus.Infof("starting snapshot prune for %q", val.VolumeName)
	if val.Backends.Snapshot == "" {
		logrus.Debugf("Snapshot driver for volume %v was empty, not snapshotting.", val)
		return
	}

	uc := &config.UseSnapshot{
		Volume: val.String(),
		Reason: lock.ReasonSnapshotPrune,
	}

	stopChan, err := lock.NewDriver(dc.Config).AcquireWithTTLRefresh(uc, dc.Global.TTL, dc.Global.Timeout)
	if err != nil {
		logrus.Error(errors.LockFailed.Combine(err))
		return
	}

	defer func() { stopChan <- struct{}{} }()

	driver, err := backend.NewSnapshotDriver(val.Backends.Snapshot)
	if err != nil {
		logrus.Errorf("failed to get driver: %v", err)
		return
	}

	driverOpts := storage.DriverOptions{
		Volume: storage.Volume{
			Name: val.String(),
			Params: storage.Params{
				"pool": val.DriverOptions["pool"],
			},
		},
		Timeout: dc.Global.Timeout,
	}

	list, err := driver.ListSnapshots(driverOpts)
	if err != nil {
		logrus.Errorf("Could not list snapshots for volume %q: %v", val.VolumeName, err)
		return
	}

	logrus.Debugf("Volume %q: keeping %d snapshots", val, val.RuntimeOptions.Snapshot.Keep)

	toDeleteCount := len(list) - int(val.RuntimeOptions.Snapshot.Keep)
	if toDeleteCount < 0 {
		return
	}

	for i := 0; i < toDeleteCount; i++ {
		logrus.Infof("Removing snapshot %q for volume %q", list[i], val.VolumeName)
		if err := driver.RemoveSnapshot(list[i], driverOpts); err != nil {
			logrus.Errorf("Removing snapshot %q for volume %q failed: %v", list[i], val.VolumeName, err)
		}
	}
}
Beispiel #2
0
func (d *DaemonConfig) handleSnapshotList(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	policy := vars["policy"]
	volumeName := vars["volume"]

	volConfig, err := d.Config.GetVolume(policy, volumeName)
	if err != nil {
		api.RESTHTTPError(w, errors.GetVolume.Combine(err))
		return
	}

	if volConfig.Backends.Snapshot == "" {
		api.RESTHTTPError(w, errors.SnapshotsUnsupported.Combine(errored.Errorf("%q", volConfig)))
		return
	}

	driver, err := backend.NewSnapshotDriver(volConfig.Backends.Snapshot)
	if err != nil {
		api.RESTHTTPError(w, errors.GetDriver.Combine(err))
		return
	}

	do := storage.DriverOptions{
		Volume: storage.Volume{
			Name:   volConfig.String(),
			Params: volConfig.DriverOptions,
		},
		Timeout: d.Global.Timeout,
	}

	results, err := driver.ListSnapshots(do)
	if err != nil {
		api.RESTHTTPError(w, errors.ListSnapshots.Combine(err))
		return
	}

	content, err := json.Marshal(results)
	if err != nil {
		api.RESTHTTPError(w, errors.MarshalResponse.Combine(err))
		return
	}

	w.Write(content)
}
Beispiel #3
0
func (cfg *Volume) validateBackends() error {
	// We use a few dummy variables to ensure that global configuration is
	// not needed in the storage drivers, that the validation does not fail
	// because of it.
	do, err := cfg.ToDriverOptions(time.Second)
	if err != nil {
		return err
	}

	if cfg.Backends.CRUD != "" {
		crud, err := backend.NewCRUDDriver(cfg.Backends.CRUD)
		if err != nil {
			return err
		}

		if err := crud.Validate(&do); err != nil {
			return err
		}
	}

	mnt, err := backend.NewMountDriver(cfg.Backends.Mount, backend.MountPath)
	if err != nil {
		return err
	}

	if err := mnt.Validate(&do); err != nil {
		return err
	}
	if cfg.Backends.Snapshot != "" {
		snapshot, err := backend.NewSnapshotDriver(cfg.Backends.Snapshot)
		if err != nil {
			return err
		}
		if err := snapshot.Validate(&do); err != nil {

			return err
		}
	}
	return nil
}
Beispiel #4
0
func (dc *DaemonConfig) createSnapshot(val *config.Volume) {
	logrus.Infof("Snapshotting %q.", val)

	uc := &config.UseSnapshot{
		Volume: val.String(),
		Reason: lock.ReasonSnapshot,
	}

	stopChan, err := lock.NewDriver(dc.Config).AcquireWithTTLRefresh(uc, dc.Global.TTL, dc.Global.Timeout)
	if err != nil {
		logrus.Error(err)
		return
	}

	defer func() { stopChan <- struct{}{} }()

	driver, err := backend.NewSnapshotDriver(val.Backends.Snapshot)
	if err != nil {
		logrus.Errorf("Error establishing driver backend %q; cannot snapshot", val.Backends.Snapshot)
		return
	}

	driverOpts := storage.DriverOptions{
		Volume: storage.Volume{
			Name: val.String(),
			Params: storage.Params{
				"pool": val.DriverOptions["pool"],
			},
		},
		Timeout: dc.Global.Timeout,
	}

	if err := driver.CreateSnapshot(time.Now().String(), driverOpts); err != nil {
		logrus.Errorf("Error creating snapshot for volume %q: %v", val, err)
	}
}
Beispiel #5
0
func (d *DaemonConfig) handleCopy(w http.ResponseWriter, r *http.Request) {
	req, err := unmarshalRequest(r)
	if err != nil {
		api.RESTHTTPError(w, errors.UnmarshalRequest.Combine(err))
		return
	}

	if _, ok := req.Options["snapshot"]; !ok {
		api.RESTHTTPError(w, errors.MissingSnapshotOption)
		return
	}

	if _, ok := req.Options["target"]; !ok {
		api.RESTHTTPError(w, errors.MissingTargetOption)
		return
	}

	if strings.Contains(req.Options["target"], "/") {
		api.RESTHTTPError(w, errors.InvalidVolume.Combine(errored.New("/")))
		return
	}

	volConfig, err := d.Config.GetVolume(req.Policy, req.Name)
	if err != nil {
		api.RESTHTTPError(w, errors.GetVolume.Combine(err))
		return
	}

	if volConfig.Backends.Snapshot == "" {
		api.RESTHTTPError(w, errors.SnapshotsUnsupported.Combine(errored.New(volConfig.Backends.Snapshot)))
		return
	}

	driver, err := backend.NewSnapshotDriver(volConfig.Backends.Snapshot)
	if err != nil {
		api.RESTHTTPError(w, errors.GetDriver.Combine(err))
		return
	}

	newVolConfig, err := d.Config.GetVolume(req.Policy, req.Name)
	if err != nil {
		api.RESTHTTPError(w, errors.GetVolume.Combine(err))
		return
	}

	newVolConfig.VolumeName = req.Options["target"]

	do := storage.DriverOptions{
		Volume: storage.Volume{
			Name:   volConfig.String(),
			Params: volConfig.DriverOptions,
		},
		Timeout: d.Global.Timeout,
	}

	host, err := os.Hostname()
	if err != nil {
		api.RESTHTTPError(w, errors.GetHostname.Combine(err))
		return
	}

	if volConfig.VolumeName == newVolConfig.VolumeName {
		api.RESTHTTPError(w, errors.CannotCopyVolume.Combine(errored.Errorf("You cannot copy volume %q onto itself.", volConfig.VolumeName)))
		return
	}

	snapUC := &config.UseSnapshot{
		Volume: volConfig.String(),
		Reason: lock.ReasonCopy,
	}

	newUC := &config.UseMount{
		Volume:   newVolConfig.String(),
		Reason:   lock.ReasonCopy,
		Hostname: host,
	}

	newSnapUC := &config.UseSnapshot{
		Volume: newVolConfig.String(),
		Reason: lock.ReasonCopy,
	}

	err = lock.NewDriver(d.Config).ExecuteWithMultiUseLock([]config.UseLocker{newUC, newSnapUC, snapUC}, d.Global.Timeout, func(ld *lock.Driver, ucs []config.UseLocker) error {
		if err := d.Config.PublishVolume(newVolConfig); err != nil {
			return err
		}

		if err := driver.CopySnapshot(do, req.Options["snapshot"], newVolConfig.String()); err != nil {
			return err
		}
		return nil
	})

	if err != nil {
		api.RESTHTTPError(w, errors.PublishVolume.Combine(errored.Errorf(
			"Creating new volume %q from volume %q, snapshot %q",
			req.Options["target"],
			volConfig.String(),
			req.Options["snapshot"],
		)).Combine(err))
		return
	}

	content, err := json.Marshal(newVolConfig)
	if err != nil {
		api.RESTHTTPError(w, errors.PublishVolume.Combine(errored.Errorf(
			"Creating new volume %q from volume %q, snapshot %q",
			req.Options["target"],
			volConfig.String(),
			req.Options["snapshot"],
		)).Combine(err))
	}

	w.Write(content)
}