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) } } }
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) }
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 }
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) } }
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) }