The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/6625
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) ===
From d296b744b605fb8e497d01e2c8b361a4948021bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com> Date: Sun, 15 Dec 2019 01:42:10 -0500 Subject: [PATCH 1/3] lxd/storage: Add createParentSnapshotDirIfMissing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber <stgra...@ubuntu.com> --- lxd/storage/drivers/driver_dir.go | 8 +++++++- lxd/storage/drivers/utils.go | 12 ++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lxd/storage/drivers/driver_dir.go b/lxd/storage/drivers/driver_dir.go index 5e3788dd9e..d54c19f071 100644 --- a/lxd/storage/drivers/driver_dir.go +++ b/lxd/storage/drivers/driver_dir.go @@ -818,8 +818,14 @@ func (d *dir) CreateVolumeSnapshot(snapVol Volume, op *operations.Operation) err srcPath := GetVolumeMountPath(d.name, snapVol.volType, parentName) snapPath := snapVol.MountPath() + // Create the parent directory. + err := createParentSnapshotDirIfMissing(d.name, snapVol.volType, parentName) + if err != nil { + return err + } + // Create snapshot directory. - err := snapVol.CreateMountPath() + err = snapVol.CreateMountPath() if err != nil { return err } diff --git a/lxd/storage/drivers/utils.go b/lxd/storage/drivers/utils.go index d3606a28a3..dc6b2fd87c 100644 --- a/lxd/storage/drivers/utils.go +++ b/lxd/storage/drivers/utils.go @@ -175,6 +175,18 @@ func GetSnapshotVolumeName(parentName, snapshotName string) string { return fmt.Sprintf("%s%s%s", parentName, shared.SnapshotDelimiter, snapshotName) } +// createParentSnapshotDirIfMissing creates the parent directory for volume snapshots +func createParentSnapshotDirIfMissing(poolName string, volType VolumeType, volName string) error { + snapshotsPath := GetVolumeSnapshotDir(poolName, volType, volName) + + // If it's missing, create it. + if !shared.PathExists(snapshotsPath) { + return os.Mkdir(snapshotsPath, 0700) + } + + return nil +} + // deleteParentSnapshotDirIfEmpty removes the parent snapshot directory if it is empty. // It accepts the pool name, volume type and parent volume name. func deleteParentSnapshotDirIfEmpty(poolName string, volType VolumeType, volName string) error { From 8d83d2f4202dd5b2875402c52070f36ea1b37f72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com> Date: Sun, 15 Dec 2019 20:30:59 -0500 Subject: [PATCH 2/3] lxd/storage/cephfs: Cleanup driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This doesn't affect any of the functional logic. It only: - Splits functions between different files - Adds comments to all functions - Re-order functions in a more readable order. - Removes un-needed checks. Signed-off-by: Stéphane Graber <stgra...@ubuntu.com> --- lxd/storage/drivers/driver_cephfs.go | 749 +------------------ lxd/storage/drivers/driver_cephfs_utils.go | 92 +++ lxd/storage/drivers/driver_cephfs_volumes.go | 609 +++++++++++++++ 3 files changed, 723 insertions(+), 727 deletions(-) create mode 100644 lxd/storage/drivers/driver_cephfs_utils.go create mode 100644 lxd/storage/drivers/driver_cephfs_volumes.go diff --git a/lxd/storage/drivers/driver_cephfs.go b/lxd/storage/drivers/driver_cephfs.go index 7049a0568c..b4923586e3 100644 --- a/lxd/storage/drivers/driver_cephfs.go +++ b/lxd/storage/drivers/driver_cephfs.go @@ -1,23 +1,17 @@ package drivers import ( - "bufio" "fmt" - "io" "io/ioutil" "os" "os/exec" "path/filepath" - "strconv" "strings" "github.com/lxc/lxd/lxd/migration" "github.com/lxc/lxd/lxd/operations" - "github.com/lxc/lxd/lxd/rsync" "github.com/lxc/lxd/shared" "github.com/lxc/lxd/shared/api" - "github.com/lxc/lxd/shared/ioprogress" - "github.com/lxc/lxd/shared/units" ) var cephfsVersion string @@ -27,6 +21,7 @@ type cephfs struct { common } +// load is used to run one-time action per-driver rather than per-pool. func (d *cephfs) load() error { if cephfsLoaded { return nil @@ -54,28 +49,25 @@ func (d *cephfs) load() error { return nil } +// Info returns the pool driver information. func (d *cephfs) Info() Info { return Info{ - Name: "cephfs", - Version: cephfsVersion, - Remote: true, - OptimizedImages: false, - PreservesInodes: false, - VolumeTypes: []VolumeType{VolumeTypeCustom}, - BlockBacking: false, - RunningQuotaResize: true, + Name: "cephfs", + Version: cephfsVersion, + OptimizedImages: false, + PreservesInodes: false, + Remote: true, + VolumeTypes: []VolumeType{VolumeTypeCustom}, + BlockBacking: false, + RunningQuotaResize: true, + RunningSnapshotFreeze: false, } } -func (d *cephfs) HasVolume(vol Volume) bool { - if shared.PathExists(vol.MountPath()) { - return true - } - - return false -} - +// Create is called during pool creation and is effectively using an empty driver struct. +// WARNING: The Create() function cannot rely on any of the struct attributes being set. func (d *cephfs) Create() error { + // Config validation. if d.config["source"] == "" { return fmt.Errorf("Missing required source name/path") } @@ -84,6 +76,7 @@ func (d *cephfs) Create() error { return fmt.Errorf("cephfs.path must match the source") } + // Set default properties if missing. if d.config["cephfs.cluster_name"] == "" { d.config["cephfs.cluster_name"] = "ceph" } @@ -155,6 +148,7 @@ func (d *cephfs) Create() error { return nil } +// Delete clears any local and remote data related to this driver instance. func (d *cephfs) Delete(op *operations.Operation) error { // Parse the namespace / path. fields := strings.SplitN(d.config["cephfs.path"], "/", 2) @@ -237,14 +231,17 @@ func (d *cephfs) Delete(op *operations.Operation) error { return nil } +// Validate checks that all provide keys are supported and that no conflicting or missing configuration is present. func (d *cephfs) Validate(config map[string]string) error { return nil } +// Update applies any driver changes required from a configuration change. func (d *cephfs) Update(changedConfig map[string]string) error { return nil } +// Mount brings up the driver and sets it up to be used. func (d *cephfs) Mount() (bool, error) { // Check if already mounted. if shared.IsMountPoint(GetPoolMountPath(d.name)) { @@ -275,719 +272,17 @@ func (d *cephfs) Mount() (bool, error) { return true, nil } +// Unmount clears any of the runtime state of the driver. func (d *cephfs) Unmount() (bool, error) { return forceUnmount(GetPoolMountPath(d.name)) } +// GetResources returns the pool resource usage information. func (d *cephfs) GetResources() (*api.ResourcesStoragePool, error) { return d.vfsGetResources() } -func (d *cephfs) ValidateVolume(vol Volume, removeUnknownKeys bool) error { - return d.validateVolume(vol, nil, removeUnknownKeys) -} - -// GetVolumeDiskPath returns the location of a root disk block device. -func (d *cephfs) GetVolumeDiskPath(vol Volume) (string, error) { - return "", ErrNotImplemented -} - -func (d *cephfs) CreateVolume(vol Volume, filler *VolumeFiller, op *operations.Operation) error { - if vol.volType != VolumeTypeCustom { - return fmt.Errorf("Volume type not supported") - } - - if vol.contentType != ContentTypeFS { - return fmt.Errorf("Content type not supported") - } - - volPath := vol.MountPath() - - err := os.MkdirAll(volPath, 0711) - if err != nil { - return err - } - - revertPath := true - defer func() { - if revertPath { - os.RemoveAll(volPath) - } - }() - - if filler != nil && filler.Fill != nil { - d.logger.Debug("Running filler function") - err = filler.Fill(volPath, "") - if err != nil { - return err - } - } - - revertPath = false - return nil -} - -func (d *cephfs) CreateVolumeFromCopy(vol Volume, srcVol Volume, copySnapshots bool, op *operations.Operation) error { - if vol.volType != VolumeTypeCustom || srcVol.volType != VolumeTypeCustom { - return fmt.Errorf("Volume type not supported") - } - - if vol.contentType != ContentTypeFS || srcVol.contentType != ContentTypeFS { - return fmt.Errorf("Content type not supported") - } - - bwlimit := d.config["rsync.bwlimit"] - - // Create the main volume path. - volPath := vol.MountPath() - err := vol.CreateMountPath() - if err != nil { - return err - } - - // Create slice of snapshots created if revert needed later. - revertSnaps := []string{} - defer func() { - if revertSnaps == nil { - return - } - - // Remove any paths created if we are reverting. - for _, snapName := range revertSnaps { - fullSnapName := GetSnapshotVolumeName(vol.name, snapName) - - snapVol := NewVolume(d, d.name, vol.volType, vol.contentType, fullSnapName, vol.config) - d.DeleteVolumeSnapshot(snapVol, op) - } - - os.RemoveAll(volPath) - }() - - // Ensure the volume is mounted. - err = vol.MountTask(func(mountPath string, op *operations.Operation) error { - // If copyring snapshots is indicated, check the source isn't itself a snapshot. - if copySnapshots && !srcVol.IsSnapshot() { - // Get the list of snapshots from the source. - srcSnapshots, err := srcVol.Snapshots(op) - if err != nil { - return err - } - - for _, srcSnapshot := range srcSnapshots { - _, snapName, _ := shared.InstanceGetParentAndSnapshotName(srcSnapshot.name) - - // Mount the source snapshot. - err = srcSnapshot.MountTask(func(srcMountPath string, op *operations.Operation) error { - // Copy the snapshot. - _, err = rsync.LocalCopy(srcMountPath, mountPath, bwlimit, false) - return err - }, op) - - // Create the snapshot itself. - err = d.CreateVolumeSnapshot(srcSnapshot, op) - if err != nil { - return err - } - - // Setup the revert. - revertSnaps = append(revertSnaps, snapName) - } - } - - // Apply the volume quota if specified. - err = d.SetVolumeQuota(vol, vol.config["size"], op) - if err != nil { - return err - } - - // Copy source to destination (mounting each volume if needed). - return srcVol.MountTask(func(srcMountPath string, op *operations.Operation) error { - _, err := rsync.LocalCopy(srcMountPath, mountPath, bwlimit, false) - return err - }, op) - }, op) - if err != nil { - return err - } - - revertSnaps = nil // Don't revert. - return nil -} - -func (d *cephfs) RefreshVolume(vol Volume, srcVol Volume, srcSnapshots []Volume, op *operations.Operation) error { - return ErrNotImplemented -} - -func (d *cephfs) DeleteVolume(vol Volume, op *operations.Operation) error { - if vol.volType != VolumeTypeCustom { - return fmt.Errorf("Volume type not supported") - } - - snapshots, err := d.VolumeSnapshots(vol, op) - if err != nil { - return err - } - - if len(snapshots) > 0 { - return fmt.Errorf("Cannot remove a volume that has snapshots") - } - - volPath := GetVolumeMountPath(d.name, vol.volType, vol.name) - - // If the volume doesn't exist, then nothing more to do. - if !shared.PathExists(volPath) { - return nil - } - - // Remove the volume from the storage device. - err = os.RemoveAll(volPath) - if err != nil { - return err - } - - // Although the volume snapshot directory should already be removed, lets remove it here - // to just in case the top-level directory is left. - snapshotDir := GetVolumeSnapshotDir(d.name, vol.volType, vol.name) - - err = os.RemoveAll(snapshotDir) - if err != nil { - return err - } - - return nil -} - -func (d *cephfs) RenameVolume(vol Volume, newName string, op *operations.Operation) error { - if vol.volType != VolumeTypeCustom { - return fmt.Errorf("Volume type not supported") - } - - // Create new snapshots directory. - snapshotDir := GetVolumeSnapshotDir(d.name, vol.volType, newName) - - err := os.MkdirAll(snapshotDir, 0711) - if err != nil { - return err - } - - type volRevert struct { - oldPath string - newPath string - isSymlink bool - } - - // Create slice to record paths renamed if revert needed later. - revertPaths := []volRevert{} - defer func() { - // Remove any paths rename if we are reverting. - for _, vol := range revertPaths { - if vol.isSymlink { - os.Symlink(vol.oldPath, vol.newPath) - } else { - os.Rename(vol.newPath, vol.oldPath) - } - } - - // Remove the new snapshot directory if we are reverting. - if len(revertPaths) > 0 { - err = os.RemoveAll(snapshotDir) - } - }() - - // Rename the snapshot directory first. - srcSnapshotDir := GetVolumeSnapshotDir(d.name, vol.volType, vol.name) - - if shared.PathExists(srcSnapshotDir) { - targetSnapshotDir := GetVolumeSnapshotDir(d.name, vol.volType, newName) - - err = os.Rename(srcSnapshotDir, targetSnapshotDir) - if err != nil { - return err - } - - revertPaths = append(revertPaths, volRevert{ - oldPath: srcSnapshotDir, - newPath: targetSnapshotDir, - }) - } - - // Rename any snapshots of the volume too. - snapshots, err := vol.Snapshots(op) - if err != nil { - return err - } - - sourcePath := GetVolumeMountPath(d.name, vol.volType, newName) - targetPath := GetVolumeMountPath(d.name, vol.volType, newName) - - for _, snapshot := range snapshots { - // Figure out the snapshot paths. - _, snapName, _ := shared.InstanceGetParentAndSnapshotName(snapshot.name) - oldCephSnapPath := filepath.Join(sourcePath, ".snap", snapName) - newCephSnapPath := filepath.Join(targetPath, ".snap", snapName) - oldPath := GetVolumeMountPath(d.name, vol.volType, GetSnapshotVolumeName(vol.name, snapName)) - newPath := GetVolumeMountPath(d.name, vol.volType, GetSnapshotVolumeName(newName, snapName)) - - // Update the symlink. - err = os.Symlink(newCephSnapPath, newPath) - if err != nil { - return err - } - - revertPaths = append(revertPaths, volRevert{ - oldPath: oldPath, - newPath: oldCephSnapPath, - isSymlink: true, - }) - } - - oldPath := GetVolumeMountPath(d.name, vol.volType, vol.name) - newPath := GetVolumeMountPath(d.name, vol.volType, newName) - err = os.Rename(oldPath, newPath) - if err != nil { - return err - } - - revertPaths = append(revertPaths, volRevert{ - oldPath: oldPath, - newPath: newPath, - }) - - revertPaths = nil - return nil -} - -func (d *cephfs) UpdateVolume(vol Volume, changedConfig map[string]string) error { - value, ok := changedConfig["size"] - if !ok { - return nil - } - - return d.SetVolumeQuota(vol, value, nil) -} - -func (d *cephfs) GetVolumeUsage(vol Volume) (int64, error) { - out, err := shared.RunCommand("getfattr", "-n", "ceph.quota.max_bytes", "--only-values", GetVolumeMountPath(d.name, vol.volType, vol.name)) - if err != nil { - return -1, err - } - - size, err := strconv.ParseInt(out, 10, 64) - if err != nil { - return -1, err - } - - return size, nil -} - -func (d *cephfs) SetVolumeQuota(vol Volume, size string, op *operations.Operation) error { - if size == "" || size == "0" { - size = d.config["volume.size"] - } - - sizeBytes, err := units.ParseByteSizeString(size) - if err != nil { - return err - } - - _, err = shared.RunCommand("setfattr", "-n", "ceph.quota.max_bytes", "-v", fmt.Sprintf("%d", sizeBytes), GetVolumeMountPath(d.name, vol.volType, vol.name)) - return err -} - -func (d *cephfs) MountVolume(vol Volume, op *operations.Operation) (bool, error) { - if vol.volType != VolumeTypeCustom { - return false, fmt.Errorf("Volume type not supported") - } - - return false, nil -} - -func (d *cephfs) MountVolumeSnapshot(snapVol Volume, op *operations.Operation) (bool, error) { - if snapVol.volType != VolumeTypeCustom { - return false, fmt.Errorf("Volume type not supported") - } - - return false, nil -} - -func (d *cephfs) UnmountVolume(vol Volume, op *operations.Operation) (bool, error) { - if vol.volType != VolumeTypeCustom { - return false, fmt.Errorf("Volume type not supported") - } - - return false, nil -} - -func (d *cephfs) UnmountVolumeSnapshot(snapVol Volume, op *operations.Operation) (bool, error) { - if snapVol.volType != VolumeTypeCustom { - return false, fmt.Errorf("Volume type not supported") - } - - return false, nil -} - -func (d *cephfs) CreateVolumeSnapshot(snapVol Volume, op *operations.Operation) error { - if snapVol.volType != VolumeTypeCustom { - return fmt.Errorf("Volume type not supported") - } - - parentName, snapName, _ := shared.InstanceGetParentAndSnapshotName(snapVol.name) - - // Create the snapshot. - sourcePath := GetVolumeMountPath(d.name, snapVol.volType, parentName) - cephSnapPath := filepath.Join(sourcePath, ".snap", snapName) - - err := os.Mkdir(cephSnapPath, 0711) - if err != nil { - return err - } - - targetPath := snapVol.MountPath() - - err = os.MkdirAll(filepath.Dir(targetPath), 0711) - if err != nil { - return err - } - - err = os.Symlink(cephSnapPath, targetPath) - if err != nil { - return err - } - - return nil -} - -func (d *cephfs) DeleteVolumeSnapshot(snapVol Volume, op *operations.Operation) error { - if snapVol.volType != VolumeTypeCustom { - return fmt.Errorf("Volume type not supported") - } - - parentName, snapName, _ := shared.InstanceGetParentAndSnapshotName(snapVol.name) - - // Delete the snapshot itself. - sourcePath := GetVolumeMountPath(d.name, snapVol.volType, parentName) - cephSnapPath := filepath.Join(sourcePath, ".snap", snapName) - - err := os.Remove(cephSnapPath) - if err != nil { - return err - } - - // Remove the symlink. - snapPath := snapVol.MountPath() - err = os.Remove(snapPath) - if err != nil { - return err - } - - return nil -} - -func (d *cephfs) RenameVolumeSnapshot(snapVol Volume, newSnapshotName string, op *operations.Operation) error { - if snapVol.volType != VolumeTypeCustom { - return fmt.Errorf("Volume type not supported") - } - - parentName, snapName, _ := shared.InstanceGetParentAndSnapshotName(snapVol.name) - sourcePath := GetVolumeMountPath(d.name, snapVol.volType, parentName) - oldCephSnapPath := filepath.Join(sourcePath, ".snap", snapName) - newCephSnapPath := filepath.Join(sourcePath, ".snap", newSnapshotName) - - err := os.Rename(oldCephSnapPath, newCephSnapPath) - if err != nil { - return err - } - - // Re-generate the snapshot symlink. - oldPath := snapVol.MountPath() - err = os.Remove(oldPath) - if err != nil { - return err - } - - newPath := GetVolumeMountPath(d.name, snapVol.volType, GetSnapshotVolumeName(parentName, newSnapshotName)) - err = os.Symlink(newCephSnapPath, newPath) - if err != nil { - return err - } - - return nil -} - -func (d *cephfs) VolumeSnapshots(vol Volume, op *operations.Operation) ([]string, error) { - if vol.volType != VolumeTypeCustom { - return nil, fmt.Errorf("Volume type not supported") - } - - snapshotDir := GetVolumeSnapshotDir(d.name, vol.volType, vol.name) - snapshots := []string{} - - ents, err := ioutil.ReadDir(snapshotDir) - if err != nil { - // If the snapshots directory doesn't exist, there are no snapshots. - if os.IsNotExist(err) { - return snapshots, nil - } - - return nil, err - } - - for _, ent := range ents { - fileInfo, err := os.Stat(filepath.Join(snapshotDir, ent.Name())) - if err != nil { - return nil, err - } - - if !fileInfo.IsDir() { - continue - } - - snapshots = append(snapshots, ent.Name()) - } - - return snapshots, nil -} - -func (d *cephfs) RestoreVolume(vol Volume, snapshotName string, op *operations.Operation) error { - sourcePath := GetVolumeMountPath(d.name, vol.volType, vol.name) - cephSnapPath := filepath.Join(sourcePath, ".snap", snapshotName) - - // Restore using rsync. - bwlimit := d.config["rsync.bwlimit"] - output, err := rsync.LocalCopy(cephSnapPath, vol.MountPath(), bwlimit, false) - if err != nil { - return fmt.Errorf("Failed to rsync volume: %s: %s", string(output), err) - } - - return nil -} - -func (d *cephfs) MigrateVolume(vol Volume, conn io.ReadWriteCloser, volSrcArgs migration.VolumeSourceArgs, op *operations.Operation) error { - if vol.volType != VolumeTypeCustom { - return fmt.Errorf("Volume type not supported") - } - - if vol.contentType != ContentTypeFS { - return fmt.Errorf("Content type not supported") - } - - if volSrcArgs.MigrationType.FSType != migration.MigrationFSType_RSYNC { - return fmt.Errorf("Migration type not supported") - } - - bwlimit := d.config["rsync.bwlimit"] - - for _, snapName := range volSrcArgs.Snapshots { - snapshot, err := vol.NewSnapshot(snapName) - if err != nil { - return err - } - - // Send snapshot to recipient (ensure local snapshot volume is mounted if needed). - err = snapshot.MountTask(func(mountPath string, op *operations.Operation) error { - var wrapper *ioprogress.ProgressTracker - if volSrcArgs.TrackProgress { - wrapper = migration.ProgressTracker(op, "fs_progress", snapshot.name) - } - - path := shared.AddSlash(mountPath) - return rsync.Send(snapshot.name, path, conn, wrapper, volSrcArgs.MigrationType.Features, bwlimit, d.state.OS.ExecPath) - }, op) - if err != nil { - return err - } - } - - // Send volume to recipient (ensure local volume is mounted if needed). - return vol.MountTask(func(mountPath string, op *operations.Operation) error { - var wrapper *ioprogress.ProgressTracker - if volSrcArgs.TrackProgress { - wrapper = migration.ProgressTracker(op, "fs_progress", vol.name) - } - - path := shared.AddSlash(mountPath) - return rsync.Send(vol.name, path, conn, wrapper, volSrcArgs.MigrationType.Features, bwlimit, d.state.OS.ExecPath) - }, op) -} - -func (d *cephfs) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, volTargetArgs migration.VolumeTargetArgs, preFiller *VolumeFiller, op *operations.Operation) error { - if vol.volType != VolumeTypeCustom { - return fmt.Errorf("Volume type not supported") - } - - if vol.contentType != ContentTypeFS { - return fmt.Errorf("Content type not supported") - } - - if volTargetArgs.MigrationType.FSType != migration.MigrationFSType_RSYNC { - return fmt.Errorf("Migration type not supported") - } - - // Create the main volume path. - volPath := vol.MountPath() - err := vol.CreateMountPath() - if err != nil { - return err - } - - // Create slice of snapshots created if revert needed later. - revertSnaps := []string{} - defer func() { - if revertSnaps == nil { - return - } - - // Remove any paths created if we are reverting. - for _, snapName := range revertSnaps { - fullSnapName := GetSnapshotVolumeName(vol.name, snapName) - snapVol := NewVolume(d, d.name, vol.volType, vol.contentType, fullSnapName, vol.config) - - d.DeleteVolumeSnapshot(snapVol, op) - } - - os.RemoveAll(volPath) - }() - - // Ensure the volume is mounted. - err = vol.MountTask(func(mountPath string, op *operations.Operation) error { - path := shared.AddSlash(mountPath) - - // Snapshots are sent first by the sender, so create these first. - for _, snapName := range volTargetArgs.Snapshots { - // Receive the snapshot. - var wrapper *ioprogress.ProgressTracker - if volTargetArgs.TrackProgress { - wrapper = migration.ProgressTracker(op, "fs_progress", snapName) - } - - err = rsync.Recv(path, conn, wrapper, volTargetArgs.MigrationType.Features) - if err != nil { - return err - } - - fullSnapName := GetSnapshotVolumeName(vol.name, snapName) - snapVol := NewVolume(d, d.name, vol.volType, vol.contentType, fullSnapName, vol.config) - - // Create the snapshot itself. - err = d.CreateVolumeSnapshot(snapVol, op) - if err != nil { - return err - } - - // Setup the revert. - revertSnaps = append(revertSnaps, snapName) - } - - // Apply the volume quota if specified. - err = d.SetVolumeQuota(vol, vol.config["size"], op) - if err != nil { - return err - } - - // Receive the main volume from sender. - var wrapper *ioprogress.ProgressTracker - if volTargetArgs.TrackProgress { - wrapper = migration.ProgressTracker(op, "fs_progress", vol.name) - } - - return rsync.Recv(path, conn, wrapper, volTargetArgs.MigrationType.Features) - }, op) - if err != nil { - return err - } - - revertSnaps = nil - return nil -} - -func (d *cephfs) fsExists(clusterName string, userName string, fsName string) bool { - _, err := shared.RunCommand("ceph", "--name", fmt.Sprintf("client.%s", userName), "--cluster", clusterName, "fs", "get", fsName) - if err != nil { - return false - } - - return true -} - -func (d *cephfs) getConfig(clusterName string, userName string) ([]string, string, error) { - // Parse the CEPH configuration. - cephConf, err := os.Open(fmt.Sprintf("/etc/ceph/%s.conf", clusterName)) - if err != nil { - return nil, "", err - } - - cephMon := []string{} - - scan := bufio.NewScanner(cephConf) - for scan.Scan() { - line := scan.Text() - line = strings.TrimSpace(line) - - if line == "" { - continue - } - - if strings.HasPrefix(line, "mon_host") { - fields := strings.SplitN(line, "=", 2) - if len(fields) < 2 { - continue - } - - servers := strings.Split(fields[1], ",") - for _, server := range servers { - cephMon = append(cephMon, strings.TrimSpace(server)) - } - break - } - } - - if len(cephMon) == 0 { - return nil, "", fmt.Errorf("Couldn't find a CPEH mon") - } - - // Parse the CEPH keyring. - cephKeyring, err := os.Open(fmt.Sprintf("/etc/ceph/%v.client.%v.keyring", clusterName, userName)) - if err != nil { - return nil, "", err - } - - var cephSecret string - - scan = bufio.NewScanner(cephKeyring) - for scan.Scan() { - line := scan.Text() - line = strings.TrimSpace(line) - - if line == "" { - continue - } - - if strings.HasPrefix(line, "key") { - fields := strings.SplitN(line, "=", 2) - if len(fields) < 2 { - continue - } - - cephSecret = strings.TrimSpace(fields[1]) - break - } - } - - if cephSecret == "" { - return nil, "", fmt.Errorf("Couldn't find a keyring entry") - } - - return cephMon, cephSecret, nil -} - -func (d *cephfs) BackupVolume(vol Volume, targetPath string, optimized bool, snapshots bool, op *operations.Operation) error { - return ErrNotImplemented -} - -func (d *cephfs) RestoreBackupVolume(vol Volume, snapshots []string, srcData io.ReadSeeker, optimizedStorage bool, op *operations.Operation) (func(vol Volume) error, func(), error) { - return nil, nil, ErrNotImplemented -} - +// MigrationTypes returns the supported migration types and options supported by the driver. func (d *cephfs) MigrationTypes(contentType ContentType, refresh bool) []migration.Type { if contentType != ContentTypeFS { return nil diff --git a/lxd/storage/drivers/driver_cephfs_utils.go b/lxd/storage/drivers/driver_cephfs_utils.go new file mode 100644 index 0000000000..638bdfe68f --- /dev/null +++ b/lxd/storage/drivers/driver_cephfs_utils.go @@ -0,0 +1,92 @@ +package drivers + +import ( + "bufio" + "fmt" + "os" + "strings" + + "github.com/lxc/lxd/shared" +) + +// fsExists checks that the Ceph FS instance indeed exists. +func (d *cephfs) fsExists(clusterName string, userName string, fsName string) bool { + _, err := shared.RunCommand("ceph", "--name", fmt.Sprintf("client.%s", userName), "--cluster", clusterName, "fs", "get", fsName) + if err != nil { + return false + } + + return true +} + +// getConfig parses the Ceph configuration file and returns the list of monitors and secret key. +func (d *cephfs) getConfig(clusterName string, userName string) ([]string, string, error) { + // Parse the CEPH configuration. + cephConf, err := os.Open(fmt.Sprintf("/etc/ceph/%s.conf", clusterName)) + if err != nil { + return nil, "", err + } + + cephMon := []string{} + + scan := bufio.NewScanner(cephConf) + for scan.Scan() { + line := scan.Text() + line = strings.TrimSpace(line) + + if line == "" { + continue + } + + if strings.HasPrefix(line, "mon_host") { + fields := strings.SplitN(line, "=", 2) + if len(fields) < 2 { + continue + } + + servers := strings.Split(fields[1], ",") + for _, server := range servers { + cephMon = append(cephMon, strings.TrimSpace(server)) + } + break + } + } + + if len(cephMon) == 0 { + return nil, "", fmt.Errorf("Couldn't find a CPEH mon") + } + + // Parse the CEPH keyring. + cephKeyring, err := os.Open(fmt.Sprintf("/etc/ceph/%v.client.%v.keyring", clusterName, userName)) + if err != nil { + return nil, "", err + } + + var cephSecret string + + scan = bufio.NewScanner(cephKeyring) + for scan.Scan() { + line := scan.Text() + line = strings.TrimSpace(line) + + if line == "" { + continue + } + + if strings.HasPrefix(line, "key") { + fields := strings.SplitN(line, "=", 2) + if len(fields) < 2 { + continue + } + + cephSecret = strings.TrimSpace(fields[1]) + break + } + } + + if cephSecret == "" { + return nil, "", fmt.Errorf("Couldn't find a keyring entry") + } + + return cephMon, cephSecret, nil +} diff --git a/lxd/storage/drivers/driver_cephfs_volumes.go b/lxd/storage/drivers/driver_cephfs_volumes.go new file mode 100644 index 0000000000..53f758e690 --- /dev/null +++ b/lxd/storage/drivers/driver_cephfs_volumes.go @@ -0,0 +1,609 @@ +package drivers + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "strconv" + + "github.com/lxc/lxd/lxd/migration" + "github.com/lxc/lxd/lxd/operations" + "github.com/lxc/lxd/lxd/rsync" + "github.com/lxc/lxd/shared" + "github.com/lxc/lxd/shared/ioprogress" + "github.com/lxc/lxd/shared/units" +) + +// CreateVolume creates a new storage volume on disk. +func (d *cephfs) CreateVolume(vol Volume, filler *VolumeFiller, op *operations.Operation) error { + if vol.volType != VolumeTypeCustom { + return fmt.Errorf("Volume type not supported") + } + + if vol.contentType != ContentTypeFS { + return fmt.Errorf("Content type not supported") + } + + volPath := vol.MountPath() + + err := os.MkdirAll(volPath, 0711) + if err != nil { + return err + } + + revertPath := true + defer func() { + if revertPath { + os.RemoveAll(volPath) + } + }() + + if filler != nil && filler.Fill != nil { + d.logger.Debug("Running filler function") + err = filler.Fill(volPath, "") + if err != nil { + return err + } + } + + revertPath = false + return nil +} + +// RestoreBackupVolume re-creates a volume from its exported state. +func (d *cephfs) RestoreBackupVolume(vol Volume, snapshots []string, srcData io.ReadSeeker, optimizedStorage bool, op *operations.Operation) (func(vol Volume) error, func(), error) { + return nil, nil, ErrNotImplemented +} + +// CreateVolumeFromCopy copies an existing storage volume (with or without snapshots) into a new volume. +func (d *cephfs) CreateVolumeFromCopy(vol Volume, srcVol Volume, copySnapshots bool, op *operations.Operation) error { + bwlimit := d.config["rsync.bwlimit"] + + // Create the main volume path. + volPath := vol.MountPath() + err := vol.CreateMountPath() + if err != nil { + return err + } + + // Create slice of snapshots created if revert needed later. + revertSnaps := []string{} + defer func() { + if revertSnaps == nil { + return + } + + // Remove any paths created if we are reverting. + for _, snapName := range revertSnaps { + fullSnapName := GetSnapshotVolumeName(vol.name, snapName) + + snapVol := NewVolume(d, d.name, vol.volType, vol.contentType, fullSnapName, vol.config) + d.DeleteVolumeSnapshot(snapVol, op) + } + + os.RemoveAll(volPath) + }() + + // Ensure the volume is mounted. + err = vol.MountTask(func(mountPath string, op *operations.Operation) error { + // If copyring snapshots is indicated, check the source isn't itself a snapshot. + if copySnapshots && !srcVol.IsSnapshot() { + // Get the list of snapshots from the source. + srcSnapshots, err := srcVol.Snapshots(op) + if err != nil { + return err + } + + for _, srcSnapshot := range srcSnapshots { + _, snapName, _ := shared.InstanceGetParentAndSnapshotName(srcSnapshot.name) + + // Mount the source snapshot. + err = srcSnapshot.MountTask(func(srcMountPath string, op *operations.Operation) error { + // Copy the snapshot. + _, err = rsync.LocalCopy(srcMountPath, mountPath, bwlimit, false) + return err + }, op) + + // Create the snapshot itself. + err = d.CreateVolumeSnapshot(srcSnapshot, op) + if err != nil { + return err + } + + // Setup the revert. + revertSnaps = append(revertSnaps, snapName) + } + } + + // Apply the volume quota if specified. + err = d.SetVolumeQuota(vol, vol.config["size"], op) + if err != nil { + return err + } + + // Copy source to destination (mounting each volume if needed). + return srcVol.MountTask(func(srcMountPath string, op *operations.Operation) error { + _, err := rsync.LocalCopy(srcMountPath, mountPath, bwlimit, false) + return err + }, op) + }, op) + if err != nil { + return err + } + + revertSnaps = nil // Don't revert. + return nil +} + +// CreateVolumeFromMigration creates a new volume (with or without snapshots) from a migration data stream. +func (d *cephfs) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, volTargetArgs migration.VolumeTargetArgs, preFiller *VolumeFiller, op *operations.Operation) error { + if volTargetArgs.MigrationType.FSType != migration.MigrationFSType_RSYNC { + return fmt.Errorf("Migration type not supported") + } + + // Create the main volume path. + volPath := vol.MountPath() + err := vol.CreateMountPath() + if err != nil { + return err + } + + // Create slice of snapshots created if revert needed later. + revertSnaps := []string{} + defer func() { + if revertSnaps == nil { + return + } + + // Remove any paths created if we are reverting. + for _, snapName := range revertSnaps { + fullSnapName := GetSnapshotVolumeName(vol.name, snapName) + snapVol := NewVolume(d, d.name, vol.volType, vol.contentType, fullSnapName, vol.config) + + d.DeleteVolumeSnapshot(snapVol, op) + } + + os.RemoveAll(volPath) + }() + + // Ensure the volume is mounted. + err = vol.MountTask(func(mountPath string, op *operations.Operation) error { + path := shared.AddSlash(mountPath) + + // Snapshots are sent first by the sender, so create these first. + for _, snapName := range volTargetArgs.Snapshots { + // Receive the snapshot. + var wrapper *ioprogress.ProgressTracker + if volTargetArgs.TrackProgress { + wrapper = migration.ProgressTracker(op, "fs_progress", snapName) + } + + err = rsync.Recv(path, conn, wrapper, volTargetArgs.MigrationType.Features) + if err != nil { + return err + } + + fullSnapName := GetSnapshotVolumeName(vol.name, snapName) + snapVol := NewVolume(d, d.name, vol.volType, vol.contentType, fullSnapName, vol.config) + + // Create the snapshot itself. + err = d.CreateVolumeSnapshot(snapVol, op) + if err != nil { + return err + } + + // Setup the revert. + revertSnaps = append(revertSnaps, snapName) + } + + // Apply the volume quota if specified. + err = d.SetVolumeQuota(vol, vol.config["size"], op) + if err != nil { + return err + } + + // Receive the main volume from sender. + var wrapper *ioprogress.ProgressTracker + if volTargetArgs.TrackProgress { + wrapper = migration.ProgressTracker(op, "fs_progress", vol.name) + } + + return rsync.Recv(path, conn, wrapper, volTargetArgs.MigrationType.Features) + }, op) + if err != nil { + return err + } + + revertSnaps = nil + return nil +} + +// RefreshVolume updates an existing volume to match the state of another. +func (d *cephfs) RefreshVolume(vol Volume, srcVol Volume, srcSnapshots []Volume, op *operations.Operation) error { + return ErrNotImplemented +} + +// DeleteVolume destroys the on-disk state of a volume. +func (d *cephfs) DeleteVolume(vol Volume, op *operations.Operation) error { + snapshots, err := d.VolumeSnapshots(vol, op) + if err != nil { + return err + } + + if len(snapshots) > 0 { + return fmt.Errorf("Cannot remove a volume that has snapshots") + } + + volPath := GetVolumeMountPath(d.name, vol.volType, vol.name) + + // If the volume doesn't exist, then nothing more to do. + if !shared.PathExists(volPath) { + return nil + } + + // Remove the volume from the storage device. + err = os.RemoveAll(volPath) + if err != nil { + return err + } + + // Although the volume snapshot directory should already be removed, lets remove it here + // to just in case the top-level directory is left. + snapshotDir := GetVolumeSnapshotDir(d.name, vol.volType, vol.name) + + err = os.RemoveAll(snapshotDir) + if err != nil { + return err + } + + return nil +} + +// HasVolume indicates whether a specific volume exists on the storage pool. +func (d *cephfs) HasVolume(vol Volume) bool { + if shared.PathExists(vol.MountPath()) { + return true + } + + return false +} + +// ValidateVolume validates the supplied volume config. +func (d *cephfs) ValidateVolume(vol Volume, removeUnknownKeys bool) error { + return d.validateVolume(vol, nil, removeUnknownKeys) +} + +// UpdateVolume applies the driver specific changes of a volume configuration change. +func (d *cephfs) UpdateVolume(vol Volume, changedConfig map[string]string) error { + value, ok := changedConfig["size"] + if !ok { + return nil + } + + return d.SetVolumeQuota(vol, value, nil) +} + +// GetVolumeUsage returns the disk space usage of a volume. +func (d *cephfs) GetVolumeUsage(vol Volume) (int64, error) { + out, err := shared.RunCommand("getfattr", "-n", "ceph.quota.max_bytes", "--only-values", GetVolumeMountPath(d.name, vol.volType, vol.name)) + if err != nil { + return -1, err + } + + size, err := strconv.ParseInt(out, 10, 64) + if err != nil { + return -1, err + } + + return size, nil +} + +// SetVolumeQuota applies a size limit on volume. +func (d *cephfs) SetVolumeQuota(vol Volume, size string, op *operations.Operation) error { + if size == "" || size == "0" { + size = d.config["volume.size"] + } + + sizeBytes, err := units.ParseByteSizeString(size) + if err != nil { + return err + } + + _, err = shared.RunCommand("setfattr", "-n", "ceph.quota.max_bytes", "-v", fmt.Sprintf("%d", sizeBytes), GetVolumeMountPath(d.name, vol.volType, vol.name)) + return err +} + +// GetVolumeDiskPath returns the location of a root disk block device. +func (d *cephfs) GetVolumeDiskPath(vol Volume) (string, error) { + return "", ErrNotImplemented +} + +// MountVolume sets up the volume for use. +func (d *cephfs) MountVolume(vol Volume, op *operations.Operation) (bool, error) { + return false, nil +} + +// UnmountVolume clears any runtime state for the volume. +func (d *cephfs) UnmountVolume(vol Volume, op *operations.Operation) (bool, error) { + return false, nil +} + +// RenameVolume renames the volume and all related filesystem entries. +func (d *cephfs) RenameVolume(vol Volume, newName string, op *operations.Operation) error { + // Create new snapshots directory. + snapshotDir := GetVolumeSnapshotDir(d.name, vol.volType, newName) + + err := os.MkdirAll(snapshotDir, 0711) + if err != nil { + return err + } + + type volRevert struct { + oldPath string + newPath string + isSymlink bool + } + + // Create slice to record paths renamed if revert needed later. + revertPaths := []volRevert{} + defer func() { + // Remove any paths rename if we are reverting. + for _, vol := range revertPaths { + if vol.isSymlink { + os.Symlink(vol.oldPath, vol.newPath) + } else { + os.Rename(vol.newPath, vol.oldPath) + } + } + + // Remove the new snapshot directory if we are reverting. + if len(revertPaths) > 0 { + err = os.RemoveAll(snapshotDir) + } + }() + + // Rename the snapshot directory first. + srcSnapshotDir := GetVolumeSnapshotDir(d.name, vol.volType, vol.name) + + if shared.PathExists(srcSnapshotDir) { + targetSnapshotDir := GetVolumeSnapshotDir(d.name, vol.volType, newName) + + err = os.Rename(srcSnapshotDir, targetSnapshotDir) + if err != nil { + return err + } + + revertPaths = append(revertPaths, volRevert{ + oldPath: srcSnapshotDir, + newPath: targetSnapshotDir, + }) + } + + // Rename any snapshots of the volume too. + snapshots, err := vol.Snapshots(op) + if err != nil { + return err + } + + sourcePath := GetVolumeMountPath(d.name, vol.volType, newName) + targetPath := GetVolumeMountPath(d.name, vol.volType, newName) + + for _, snapshot := range snapshots { + // Figure out the snapshot paths. + _, snapName, _ := shared.InstanceGetParentAndSnapshotName(snapshot.name) + oldCephSnapPath := filepath.Join(sourcePath, ".snap", snapName) + newCephSnapPath := filepath.Join(targetPath, ".snap", snapName) + oldPath := GetVolumeMountPath(d.name, vol.volType, GetSnapshotVolumeName(vol.name, snapName)) + newPath := GetVolumeMountPath(d.name, vol.volType, GetSnapshotVolumeName(newName, snapName)) + + // Update the symlink. + err = os.Symlink(newCephSnapPath, newPath) + if err != nil { + return err + } + + revertPaths = append(revertPaths, volRevert{ + oldPath: oldPath, + newPath: oldCephSnapPath, + isSymlink: true, + }) + } + + oldPath := GetVolumeMountPath(d.name, vol.volType, vol.name) + newPath := GetVolumeMountPath(d.name, vol.volType, newName) + err = os.Rename(oldPath, newPath) + if err != nil { + return err + } + + revertPaths = append(revertPaths, volRevert{ + oldPath: oldPath, + newPath: newPath, + }) + + revertPaths = nil + return nil +} + +// MigrateVolume streams the volume (with or without snapshots) +func (d *cephfs) MigrateVolume(vol Volume, conn io.ReadWriteCloser, volSrcArgs migration.VolumeSourceArgs, op *operations.Operation) error { + if volSrcArgs.MigrationType.FSType != migration.MigrationFSType_RSYNC { + return fmt.Errorf("Migration type not supported") + } + + bwlimit := d.config["rsync.bwlimit"] + + for _, snapName := range volSrcArgs.Snapshots { + snapshot, err := vol.NewSnapshot(snapName) + if err != nil { + return err + } + + // Send snapshot to recipient (ensure local snapshot volume is mounted if needed). + err = snapshot.MountTask(func(mountPath string, op *operations.Operation) error { + var wrapper *ioprogress.ProgressTracker + if volSrcArgs.TrackProgress { + wrapper = migration.ProgressTracker(op, "fs_progress", snapshot.name) + } + + path := shared.AddSlash(mountPath) + return rsync.Send(snapshot.name, path, conn, wrapper, volSrcArgs.MigrationType.Features, bwlimit, d.state.OS.ExecPath) + }, op) + if err != nil { + return err + } + } + + // Send volume to recipient (ensure local volume is mounted if needed). + return vol.MountTask(func(mountPath string, op *operations.Operation) error { + var wrapper *ioprogress.ProgressTracker + if volSrcArgs.TrackProgress { + wrapper = migration.ProgressTracker(op, "fs_progress", vol.name) + } + + path := shared.AddSlash(mountPath) + return rsync.Send(vol.name, path, conn, wrapper, volSrcArgs.MigrationType.Features, bwlimit, d.state.OS.ExecPath) + }, op) +} + +// BackupVolume creates an exported version of a volume. +func (d *cephfs) BackupVolume(vol Volume, targetPath string, optimized bool, snapshots bool, op *operations.Operation) error { + return ErrNotImplemented +} + +// CreateVolumeSnapshot creates a new snapshot. +func (d *cephfs) CreateVolumeSnapshot(snapVol Volume, op *operations.Operation) error { + parentName, snapName, _ := shared.InstanceGetParentAndSnapshotName(snapVol.name) + + // Create the snapshot. + sourcePath := GetVolumeMountPath(d.name, snapVol.volType, parentName) + cephSnapPath := filepath.Join(sourcePath, ".snap", snapName) + + err := os.Mkdir(cephSnapPath, 0711) + if err != nil { + return err + } + + targetPath := snapVol.MountPath() + + err = os.MkdirAll(filepath.Dir(targetPath), 0711) + if err != nil { + return err + } + + err = os.Symlink(cephSnapPath, targetPath) + if err != nil { + return err + } + + return nil +} + +// DeleteVolumeSnapshot deletes a snapshot. +func (d *cephfs) DeleteVolumeSnapshot(snapVol Volume, op *operations.Operation) error { + parentName, snapName, _ := shared.InstanceGetParentAndSnapshotName(snapVol.name) + + // Delete the snapshot itself. + sourcePath := GetVolumeMountPath(d.name, snapVol.volType, parentName) + cephSnapPath := filepath.Join(sourcePath, ".snap", snapName) + + err := os.Remove(cephSnapPath) + if err != nil { + return err + } + + // Remove the symlink. + snapPath := snapVol.MountPath() + err = os.Remove(snapPath) + if err != nil { + return err + } + + return nil +} + +// MountVolumeSnapshot makes the snapshot available for use. +func (d *cephfs) MountVolumeSnapshot(snapVol Volume, op *operations.Operation) (bool, error) { + return false, nil +} + +// UnmountVolumeSnapshot clears any runtime state for the snapshot. +func (d *cephfs) UnmountVolumeSnapshot(snapVol Volume, op *operations.Operation) (bool, error) { + return false, nil +} + +// VolumeSnapshots returns a list of snapshot names for the volume. +func (d *cephfs) VolumeSnapshots(vol Volume, op *operations.Operation) ([]string, error) { + snapshotDir := GetVolumeSnapshotDir(d.name, vol.volType, vol.name) + snapshots := []string{} + + ents, err := ioutil.ReadDir(snapshotDir) + if err != nil { + // If the snapshots directory doesn't exist, there are no snapshots. + if os.IsNotExist(err) { + return snapshots, nil + } + + return nil, err + } + + for _, ent := range ents { + fileInfo, err := os.Stat(filepath.Join(snapshotDir, ent.Name())) + if err != nil { + return nil, err + } + + if !fileInfo.IsDir() { + continue + } + + snapshots = append(snapshots, ent.Name()) + } + + return snapshots, nil +} + +// RestoreVolume resets a volume to its snapshotted state. +func (d *cephfs) RestoreVolume(vol Volume, snapshotName string, op *operations.Operation) error { + sourcePath := GetVolumeMountPath(d.name, vol.volType, vol.name) + cephSnapPath := filepath.Join(sourcePath, ".snap", snapshotName) + + // Restore using rsync. + bwlimit := d.config["rsync.bwlimit"] + output, err := rsync.LocalCopy(cephSnapPath, vol.MountPath(), bwlimit, false) + if err != nil { + return fmt.Errorf("Failed to rsync volume: %s: %s", string(output), err) + } + + return nil +} + +// RenameVolumeSnapshot renames a snapshot. +func (d *cephfs) RenameVolumeSnapshot(snapVol Volume, newSnapshotName string, op *operations.Operation) error { + parentName, snapName, _ := shared.InstanceGetParentAndSnapshotName(snapVol.name) + sourcePath := GetVolumeMountPath(d.name, snapVol.volType, parentName) + oldCephSnapPath := filepath.Join(sourcePath, ".snap", snapName) + newCephSnapPath := filepath.Join(sourcePath, ".snap", newSnapshotName) + + err := os.Rename(oldCephSnapPath, newCephSnapPath) + if err != nil { + return err + } + + // Re-generate the snapshot symlink. + oldPath := snapVol.MountPath() + err = os.Remove(oldPath) + if err != nil { + return err + } + + newPath := GetVolumeMountPath(d.name, snapVol.volType, GetSnapshotVolumeName(parentName, newSnapshotName)) + err = os.Symlink(newCephSnapPath, newPath) + if err != nil { + return err + } + + return nil +} From 48d27e5052037af443a31601e0dcdb4e8dc71e5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com> Date: Sun, 15 Dec 2019 20:34:08 -0500 Subject: [PATCH 3/3] lxd/storage: Rename RestoreBackupVolume to CreateVolumeFromBackup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber <stgra...@ubuntu.com> --- lxd/storage/backend_lxd.go | 2 +- lxd/storage/drivers/driver_cephfs_volumes.go | 4 ++-- lxd/storage/drivers/driver_dir.go | 4 ++-- lxd/storage/drivers/interface.go | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go index c2c592a904..203f9590f7 100644 --- a/lxd/storage/backend_lxd.go +++ b/lxd/storage/backend_lxd.go @@ -395,7 +395,7 @@ func (b *lxdBackend) CreateInstanceFromBackup(srcBackup backup.Info, srcData io. }() // Unpack the backup into the new storage volume(s). - volPostHook, revertHook, err := b.driver.RestoreBackupVolume(vol, srcBackup.Snapshots, srcData, srcBackup.OptimizedStorage, op) + volPostHook, revertHook, err := b.driver.CreateVolumeFromBackup(vol, srcBackup.Snapshots, srcData, srcBackup.OptimizedStorage, op) if err != nil { return nil, nil, err } diff --git a/lxd/storage/drivers/driver_cephfs_volumes.go b/lxd/storage/drivers/driver_cephfs_volumes.go index 53f758e690..337cade4cd 100644 --- a/lxd/storage/drivers/driver_cephfs_volumes.go +++ b/lxd/storage/drivers/driver_cephfs_volumes.go @@ -52,8 +52,8 @@ func (d *cephfs) CreateVolume(vol Volume, filler *VolumeFiller, op *operations.O return nil } -// RestoreBackupVolume re-creates a volume from its exported state. -func (d *cephfs) RestoreBackupVolume(vol Volume, snapshots []string, srcData io.ReadSeeker, optimizedStorage bool, op *operations.Operation) (func(vol Volume) error, func(), error) { +// CreateVolumeFromBackup re-creates a volume from its exported state. +func (d *cephfs) CreateVolumeFromBackup(vol Volume, snapshots []string, srcData io.ReadSeeker, optimizedStorage bool, op *operations.Operation) (func(vol Volume) error, func(), error) { return nil, nil, ErrNotImplemented } diff --git a/lxd/storage/drivers/driver_dir.go b/lxd/storage/drivers/driver_dir.go index d54c19f071..7c3afd9f01 100644 --- a/lxd/storage/drivers/driver_dir.go +++ b/lxd/storage/drivers/driver_dir.go @@ -928,8 +928,8 @@ func (d *dir) BackupVolume(vol Volume, targetPath string, _, snapshots bool, op return nil } -// RestoreBackupVolume restores a backup tarball onto the storage device. -func (d *dir) RestoreBackupVolume(vol Volume, snapshots []string, srcData io.ReadSeeker, optimizedStorage bool, op *operations.Operation) (func(vol Volume) error, func(), error) { +// CreateVolumeFromBackup restores a backup tarball onto the storage device. +func (d *dir) CreateVolumeFromBackup(vol Volume, snapshots []string, srcData io.ReadSeeker, optimizedStorage bool, op *operations.Operation) (func(vol Volume) error, func(), error) { revert := true revertPaths := []string{} diff --git a/lxd/storage/drivers/interface.go b/lxd/storage/drivers/interface.go index 6b4260f8f4..e0bad2ee89 100644 --- a/lxd/storage/drivers/interface.go +++ b/lxd/storage/drivers/interface.go @@ -75,5 +75,5 @@ type Driver interface { // Backup. BackupVolume(vol Volume, targetPath string, optimized bool, snapshots bool, op *operations.Operation) error - RestoreBackupVolume(vol Volume, snapshots []string, srcData io.ReadSeeker, optimizedStorage bool, op *operations.Operation) (func(vol Volume) error, func(), error) + CreateVolumeFromBackup(vol Volume, snapshots []string, srcData io.ReadSeeker, optimizedStorage bool, op *operations.Operation) (func(vol Volume) error, func(), error) }
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel