[lxc-devel] [lxd/master] storage: implement local {copy, move} custom storage volumes

brauner on Github lxc-bot at linuxcontainers.org
Tue Jan 16 13:06:43 UTC 2018


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 520 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20180116/9356a25d/attachment.bin>
-------------- next part --------------
From d3d3a0f573dfcc98a809f787eac60fe889a1d012 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Mon, 15 Jan 2018 12:39:40 +0100
Subject: [PATCH 01/10] doc: s/zfs/ceph/

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 doc/storage.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/doc/storage.md b/doc/storage.md
index fe68d8984..2a8eaf422 100644
--- a/doc/storage.md
+++ b/doc/storage.md
@@ -186,7 +186,7 @@ lxc storage create pool2 dir source=/data/lxd
   storage entities is not recommended by Ceph upstream. You may see unexpected
   and erratic failures which are unrelated to LXD itself.
 
-#### The following commands can be used to create ZFS storage pools
+#### The following commands can be used to create Ceph storage pools
 
 - Create a osd storage pool named "pool1" in the CEPH cluster "ceph".
 

From e00b1117d44c1ec1d2db5b67dd22667d52c3094e Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Mon, 15 Jan 2018 13:14:30 +0100
Subject: [PATCH 02/10] shared/api: add StorageVolumeSource struct

Closes #3984.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 shared/api/storage_pool_volume.go | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/shared/api/storage_pool_volume.go b/shared/api/storage_pool_volume.go
index 61e6b8732..2ad98ea4c 100644
--- a/shared/api/storage_pool_volume.go
+++ b/shared/api/storage_pool_volume.go
@@ -8,6 +8,9 @@ type StorageVolumesPost struct {
 
 	Name string `json:"name" yaml:"name"`
 	Type string `json:"type" yaml:"type"`
+
+	// API extension: storage_local_volume_copy
+	Source StorageVolumeSource `json:"source" yaml:"source"`
 }
 
 // StorageVolumePost represents the fields required to rename a LXD storage pool volume
@@ -37,6 +40,15 @@ type StorageVolumePut struct {
 	Description string `json:"description" yaml:"description"`
 }
 
+// StoragePoolVolumeSource represents the creation source for a new storage volume.
+//
+// API extension: storage_local_volume_copy
+type StorageVolumeSource struct {
+	Name string `json:"name" yaml:"name"`
+	Type string `json:"type" yaml:"type"`
+	Pool string `json:"pool" yaml:"pool"`
+}
+
 // Writable converts a full StorageVolume struct into a StorageVolumePut struct
 // (filters read-only fields).
 func (storageVolume *StorageVolume) Writable() StorageVolumePut {

From 964ed393ede22e095574415dac5e3e28f0b9fd0d Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Mon, 15 Jan 2018 17:33:58 +0100
Subject: [PATCH 03/10] client: add CopyStoragePoolVolume()

This also adds a new struct StoragePoolVolumeCopyArgs which is currently empty.
This will likely prove helpful when we need to start passing additional
arguments. We have done similar things for images and containers.

Closes #3984.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 client/interfaces.go          |  6 ++++++
 client/lxd_storage_volumes.go | 13 +++++++++++++
 2 files changed, 19 insertions(+)

diff --git a/client/interfaces.go b/client/interfaces.go
index b88fbef2d..94f2058fe 100644
--- a/client/interfaces.go
+++ b/client/interfaces.go
@@ -159,6 +159,7 @@ type ContainerServer interface {
 	UpdateStoragePoolVolume(pool string, volType string, name string, volume api.StorageVolumePut, ETag string) (err error)
 	DeleteStoragePoolVolume(pool string, volType string, name string) (err error)
 	RenameStoragePoolVolume(pool string, volType string, name string, volume api.StorageVolumePost) (err error)
+	CopyStoragePoolVolume(source ContainerServer, pool string, volume api.StorageVolumesPost, args *StoragePoolVolumeCopyArgs) (err error)
 
 	// Internal functions (for internal use)
 	RawQuery(method string, path string, data interface{}, queryETag string) (resp *api.Response, ETag string, err error)
@@ -254,6 +255,11 @@ type ImageCopyArgs struct {
 	Public bool
 }
 
+// The StoragePoolVolumeCopyArgs struct is used to pass additional options
+// during storage volume copy
+type StoragePoolVolumeCopyArgs struct {
+}
+
 // The ContainerCopyArgs struct is used to pass additional options during container copy
 type ContainerCopyArgs struct {
 	// If set, the container will be renamed on copy
diff --git a/client/lxd_storage_volumes.go b/client/lxd_storage_volumes.go
index 1aa576e7f..78d8e5d05 100644
--- a/client/lxd_storage_volumes.go
+++ b/client/lxd_storage_volumes.go
@@ -71,6 +71,19 @@ func (r *ProtocolLXD) CreateStoragePoolVolume(pool string, volume api.StorageVol
 	return nil
 }
 
+// CopyStoragePoolVolume copies an existing storage volume
+func (r *ProtocolLXD) CopyStoragePoolVolume(source ContainerServer, pool string, volume api.StorageVolumesPost, args *StoragePoolVolumeCopyArgs) error {
+	if !r.HasExtension("storage_api_local_volume_handling") {
+		return fmt.Errorf("The server is missing the required \"storage_api_local_volume_handling\" API extension")
+	}
+
+	if r != source {
+		return fmt.Errorf("Copying storage volumes between remotes is not implemented\n")
+	}
+
+	return r.CreateStoragePoolVolume(pool, volume)
+}
+
 // UpdateStoragePoolVolume updates the volume to match the provided StoragePoolVolume struct
 func (r *ProtocolLXD) UpdateStoragePoolVolume(pool string, volType string, name string, volume api.StorageVolumePut, ETag string) error {
 	// Send the request

From 7f10f3042363db85a3902b628f3414c9afddbac7 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Mon, 15 Jan 2018 17:39:57 +0100
Subject: [PATCH 04/10] storage volumes: non-functional changes

Closes #3984.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/storage_volumes.go       | 2 +-
 lxd/storage_volumes_utils.go | 8 +++++++-
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/lxd/storage_volumes.go b/lxd/storage_volumes.go
index 480029c41..2601bfdb9 100644
--- a/lxd/storage_volumes.go
+++ b/lxd/storage_volumes.go
@@ -177,7 +177,7 @@ func storagePoolVolumesTypePost(d *Daemon, r *http.Request) Response {
 			`storage volumes of type %s`, req.Type))
 	}
 
-	err = storagePoolVolumeCreateInternal(d.State(), poolName, req.Name, req.Description, req.Type, req.Config)
+	err = storagePoolVolumeCreateInternal(d.State(), poolName, &req)
 	if err != nil {
 		return InternalError(err)
 	}
diff --git a/lxd/storage_volumes_utils.go b/lxd/storage_volumes_utils.go
index 7e690e60b..0916ae35b 100644
--- a/lxd/storage_volumes_utils.go
+++ b/lxd/storage_volumes_utils.go
@@ -8,6 +8,7 @@ import (
 	"github.com/lxc/lxd/lxd/db"
 	"github.com/lxc/lxd/lxd/state"
 	"github.com/lxc/lxd/shared"
+	"github.com/lxc/lxd/shared/api"
 	"github.com/lxc/lxd/shared/version"
 )
 
@@ -339,7 +340,12 @@ func storagePoolVolumeDBCreate(s *state.State, poolName string, volumeName, volu
 	return nil
 }
 
-func storagePoolVolumeCreateInternal(state *state.State, poolName string, volumeName, volumeDescription string, volumeTypeName string, volumeConfig map[string]string) error {
+func storagePoolVolumeCreateInternal(state *state.State, poolName string, vol *api.StorageVolumesPost) error {
+	volumeName := vol.Name
+	volumeDescription := vol.Description
+	volumeTypeName := vol.Type
+	volumeConfig := vol.Config
+
 	err := storagePoolVolumeDBCreate(state, poolName, volumeName, volumeDescription, volumeTypeName, volumeConfig)
 	if err != nil {
 		return err

From ae13a9133cc73f2944f281867d13543eba4822d0 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Mon, 15 Jan 2018 17:41:00 +0100
Subject: [PATCH 05/10] storage: local storage volume {move,copy}

Closes #3984.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/storage.go       |   1 +
 lxd/storage_btrfs.go |  62 +++++++++++++++++++++++
 lxd/storage_ceph.go  | 101 ++++++++++++++++++++++++++++++++++---
 lxd/storage_dir.go   |  42 ++++++++++++++++
 lxd/storage_lvm.go   |  76 ++++++++++++++++++++++++++++
 lxd/storage_mock.go  |   4 ++
 lxd/storage_zfs.go   | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 7 files changed, 415 insertions(+), 8 deletions(-)

diff --git a/lxd/storage.go b/lxd/storage.go
index 4a651d70e..fd16649d6 100644
--- a/lxd/storage.go
+++ b/lxd/storage.go
@@ -155,6 +155,7 @@ type storage interface {
 	StoragePoolVolumeUmount() (bool, error)
 	StoragePoolVolumeUpdate(writable *api.StorageVolumePut, changedConfig []string) error
 	StoragePoolVolumeRename(newName string) error
+	StoragePoolVolumeCopy(source *api.StorageVolumeSource) error
 	GetStoragePoolVolumeWritable() api.StorageVolumePut
 	SetStoragePoolVolumeWritable(writable *api.StorageVolumePut)
 
diff --git a/lxd/storage_btrfs.go b/lxd/storage_btrfs.go
index 1218ee271..ee95ecdbc 100644
--- a/lxd/storage_btrfs.go
+++ b/lxd/storage_btrfs.go
@@ -2289,3 +2289,65 @@ func (s *storageBtrfs) StoragePoolResources() (*api.ResourcesStoragePool, error)
 
 	return storageResource(poolMntPoint)
 }
+
+func (s *storageBtrfs) StoragePoolVolumeCopy(source *api.StorageVolumeSource) error {
+	logger.Infof("Copying BTRFS storage volume \"%s\" on storage pool \"%s\" as \"%s\" to storage pool \"%s\"", source.Name, source.Pool, s.volume.Name, s.pool.Name)
+	successMsg := fmt.Sprintf("Copied BTRFS storage volume \"%s\" on storage pool \"%s\" as \"%s\" to storage pool \"%s\"", source.Name, source.Pool, s.volume.Name, s.pool.Name)
+
+	srcMountPoint := getStoragePoolVolumeMountPoint(source.Pool, source.Name)
+	dstMountPoint := getStoragePoolVolumeMountPoint(s.pool.Name, s.volume.Name)
+
+	if s.pool.Name == source.Pool {
+		// Ensure that the directories immediately preceding the subvolume directory exist.
+		customDir := getStoragePoolVolumeMountPoint(s.pool.Name, s.volume.Name)
+		if !shared.PathExists(customDir) {
+			err := os.MkdirAll(customDir, 0700)
+			if err != nil {
+				logger.Errorf("Failed to create directory \"%s\" for storage volume \"%s\" on storage pool \"%s\": %s", customDir, s.volume.Name, s.pool.Name, err)
+				return err
+			}
+		}
+
+		err := s.btrfsPoolVolumesSnapshot(srcMountPoint, dstMountPoint, false)
+		if err != nil {
+			logger.Errorf("Failed to create BTRFS snapshot for storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+			return err
+		}
+
+		logger.Infof(successMsg)
+		return nil
+	}
+
+	// setup storage for the source volume
+	srcStorage, err := storagePoolVolumeInit(s.s, source.Pool, source.Name, storagePoolVolumeTypeCustom)
+	if err != nil {
+		logger.Errorf("Failed to initialize storage for BTRFS storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+		return err
+	}
+
+	ourMount, err := srcStorage.StoragePoolVolumeMount()
+	if err != nil {
+		logger.Errorf("Failed to mount BTRFS storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+		return err
+	}
+	if ourMount {
+		defer srcStorage.StoragePoolVolumeUmount()
+	}
+
+	err = s.StoragePoolVolumeCreate()
+	if err != nil {
+		logger.Errorf("Failed to create BTRFS storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+		return err
+	}
+
+	bwlimit := s.pool.Config["rsync.bwlimit"]
+	_, err = rsyncLocalCopy(srcMountPoint, dstMountPoint, bwlimit)
+	if err != nil {
+		s.StoragePoolVolumeDelete()
+		logger.Errorf("Failed to rsync into BTRFS storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+		return err
+	}
+
+	logger.Infof(successMsg)
+	return nil
+}
diff --git a/lxd/storage_ceph.go b/lxd/storage_ceph.go
index 1af3cc410..60cdac47a 100644
--- a/lxd/storage_ceph.go
+++ b/lxd/storage_ceph.go
@@ -10,6 +10,8 @@ import (
 	"github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/api"
 	"github.com/lxc/lxd/shared/logger"
+
+	"github.com/pborman/uuid"
 )
 
 type storageCeph struct {
@@ -509,15 +511,14 @@ func (s *storageCeph) StoragePoolVolumeDelete() error {
 
 	// delete
 	if rbdVolumeExists {
-		err := cephRBDVolumeDelete(s.ClusterName, s.OSDPoolName, s.volume.Name,
+		ret := cephContainerDelete(s.ClusterName, s.OSDPoolName, s.volume.Name,
 			storagePoolVolumeTypeNameCustom, s.UserName)
-		if err != nil {
-			logger.Errorf(`Failed to delete RBD storage volume "%s" on `+
-				`storage pool "%s": %s`, s.volume.Name, s.pool.Name, err)
-			return err
+		if ret < 0 {
+			msg := fmt.Sprintf(`Failed to delete RBD storage volume "%s" on storage pool "%s"`, s.volume.Name, s.pool.Name)
+			logger.Errorf(msg)
+			return fmt.Errorf(msg)
 		}
-		logger.Debugf(`Deleted RBD storage volume "%s" on storage pool "%s"`,
-			s.volume.Name, s.pool.Name)
+		logger.Debugf(`Deleted RBD storage volume "%s" on storage pool "%s"`, s.volume.Name, s.pool.Name)
 	}
 
 	err = s.db.StoragePoolVolumeDelete(
@@ -2835,3 +2836,89 @@ func (s *storageCeph) StoragePoolResources() (*api.ResourcesStoragePool, error)
 
 	return &res, nil
 }
+
+func (s *storageCeph) StoragePoolVolumeCopy(source *api.StorageVolumeSource) error {
+	logger.Infof("Copying RBD storage volume \"%s\" on storage pool \"%s\" as \"%s\" to storage pool \"%s\"", source.Name, source.Pool, s.volume.Name, s.pool.Name)
+	successMsg := fmt.Sprintf("Copied RBD storage volume \"%s\" on storage pool \"%s\" as \"%s\" to storage pool \"%s\"", source.Name, source.Pool, s.volume.Name, s.pool.Name)
+
+	srcMountPoint := getStoragePoolVolumeMountPoint(source.Pool, source.Name)
+	dstMountPoint := getStoragePoolVolumeMountPoint(s.pool.Name, s.volume.Name)
+	if s.pool.Name == source.Pool {
+		oldVolumeName := fmt.Sprintf("%s/custom_%s", s.OSDPoolName, source.Name)
+		newVolumeName := fmt.Sprintf("%s/custom_%s", s.OSDPoolName, s.volume.Name)
+
+		if s.pool.Config["ceph.rbd.clone_copy"] != "" && !shared.IsTrue(s.pool.Config["ceph.rbd.clone_copy"]) {
+			// create full copy
+			err := cephRBDVolumeCopy(s.ClusterName, oldVolumeName, newVolumeName, s.UserName)
+			if err != nil {
+				logger.Errorf("Failed to create non-sparse copy of RBD storage volume \"%s\" on storage pool \"%s\": %s", source.Name, source.Pool, err)
+				return err
+			}
+		} else {
+			// create sparse copy
+			snapshotName := uuid.NewRandom().String()
+
+			// create snapshot of original volume
+			err := cephRBDSnapshotCreate(s.ClusterName, s.OSDPoolName, source.Name, storagePoolVolumeTypeNameCustom, snapshotName, s.UserName)
+			if err != nil {
+				logger.Errorf("Failed to create snapshot of RBD storage volume \"%s\" on storage pool \"%s\": %s", source.Name, source.Pool, err)
+				return err
+			}
+
+			// protect volume so we can create clones of it
+			err = cephRBDSnapshotProtect(s.ClusterName, s.OSDPoolName, source.Name, storagePoolVolumeTypeNameCustom, snapshotName, s.UserName)
+			if err != nil {
+				logger.Errorf("Failed to protect snapshot for RBD storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+				return err
+			}
+
+			// create new clone
+			err = cephRBDCloneCreate(s.ClusterName, s.OSDPoolName, source.Name, storagePoolVolumeTypeNameCustom, snapshotName, s.OSDPoolName, s.volume.Name, storagePoolVolumeTypeNameCustom, s.UserName)
+			if err != nil {
+				logger.Errorf("Failed to clone RBD storage volume \"%s\" on storage pool \"%s\": %s", source.Name, source.Pool, err)
+				return err
+			}
+		}
+
+		RBDDevPath, err := cephRBDVolumeMap(s.ClusterName, s.OSDPoolName, s.volume.Name, storagePoolVolumeTypeNameCustom, s.UserName)
+		if err != nil {
+			logger.Errorf("Failed to map RBD storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+			return err
+		}
+
+		// Generate a new xfs's UUID
+		RBDFilesystem := s.getRBDFilesystem()
+		msg, err := fsGenerateNewUUID(RBDFilesystem, RBDDevPath)
+		if err != nil {
+			logger.Errorf("Failed to create new UUID for filesystem \"%s\" for RBD storage volume \"%s\" on storage pool \"%s\": %s: %s", RBDFilesystem, s.volume.Name, s.pool.Name, msg, err)
+			return err
+		}
+
+		volumeMntPoint := getStoragePoolVolumeMountPoint(s.pool.Name, s.volume.Name)
+		err = os.MkdirAll(volumeMntPoint, 0711)
+		if err != nil {
+			logger.Errorf("Failed to create mountpoint \"%s\" for RBD storage volume \"%s\" on storage pool \"%s\": %s", volumeMntPoint, s.volume.Name, s.pool.Name, err)
+			return err
+		}
+
+		logger.Infof(successMsg)
+		return nil
+	}
+
+	err := s.StoragePoolVolumeCreate()
+	if err != nil {
+		logger.Errorf("Failed to create RBD storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+		return err
+	}
+
+	bwlimit := s.pool.Config["rsync.bwlimit"]
+	_, err = rsyncLocalCopy(srcMountPoint, dstMountPoint, bwlimit)
+	if err != nil {
+		os.RemoveAll(dstMountPoint)
+		logger.Errorf("Failed to rsync into RBD storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+		return err
+	}
+
+	logger.Infof(successMsg)
+	return nil
+}
diff --git a/lxd/storage_dir.go b/lxd/storage_dir.go
index 78e562fa7..771153d70 100644
--- a/lxd/storage_dir.go
+++ b/lxd/storage_dir.go
@@ -1060,3 +1060,45 @@ func (s *storageDir) StoragePoolResources() (*api.ResourcesStoragePool, error) {
 
 	return storageResource(poolMntPoint)
 }
+
+func (s *storageDir) StoragePoolVolumeCopy(source *api.StorageVolumeSource) error {
+	logger.Infof("Copying DIR storage volume \"%s\" on storage pool \"%s\" as \"%s\" to storage pool \"%s\"", source.Name, source.Pool, s.volume.Name, s.pool.Name)
+	successMsg := fmt.Sprintf("Copied DIR storage volume \"%s\" on storage pool \"%s\" as \"%s\" to storage pool \"%s\"", source.Name, source.Pool, s.volume.Name, s.pool.Name)
+
+	if s.pool.Name != source.Pool {
+		// setup storage for the source volume
+		srcStorage, err := storagePoolVolumeInit(s.s, source.Pool, source.Name, storagePoolVolumeTypeCustom)
+		if err != nil {
+			logger.Errorf("Failed to initialize DIR storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+			return err
+		}
+
+		ourMount, err := srcStorage.StoragePoolVolumeMount()
+		if err != nil {
+			logger.Errorf("Failed to mount DIR storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+			return err
+		}
+		if ourMount {
+			defer srcStorage.StoragePoolVolumeUmount()
+		}
+	}
+
+	err := s.StoragePoolVolumeCreate()
+	if err != nil {
+		logger.Errorf("Failed to create DIR storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+		return err
+	}
+
+	srcMountPoint := getStoragePoolVolumeMountPoint(source.Pool, source.Name)
+	dstMountPoint := getStoragePoolVolumeMountPoint(s.pool.Name, s.volume.Name)
+	bwlimit := s.pool.Config["rsync.bwlimit"]
+	_, err = rsyncLocalCopy(srcMountPoint, dstMountPoint, bwlimit)
+	if err != nil {
+		os.RemoveAll(dstMountPoint)
+		logger.Errorf("Failed to rsync into DIR storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+		return err
+	}
+
+	logger.Infof(successMsg)
+	return nil
+}
diff --git a/lxd/storage_lvm.go b/lxd/storage_lvm.go
index 95c596b1c..d74b24d2f 100644
--- a/lxd/storage_lvm.go
+++ b/lxd/storage_lvm.go
@@ -1845,3 +1845,79 @@ func (s *storageLvm) StoragePoolResources() (*api.ResourcesStoragePool, error) {
 
 	return &res, nil
 }
+
+func (s *storageLvm) StoragePoolVolumeCopy(source *api.StorageVolumeSource) error {
+	logger.Infof("Copying LVM storage volume \"%s\" on storage pool \"%s\" as \"%s\" to storage pool \"%s\"", source.Name, source.Pool, s.volume.Name, s.pool.Name)
+	successMsg := fmt.Sprintf("Copied LVM storage volume \"%s\" on storage pool \"%s\" as \"%s\" to storage pool \"%s\"", source.Name, source.Pool, s.volume.Name, s.pool.Name)
+
+	srcMountPoint := getStoragePoolVolumeMountPoint(source.Pool, source.Name)
+	dstMountPoint := getStoragePoolVolumeMountPoint(s.pool.Name, s.volume.Name)
+
+	if s.pool.Name == source.Pool && s.useThinpool {
+		err := os.MkdirAll(dstMountPoint, 0711)
+		if err != nil {
+			logger.Errorf("Failed to create mountpoint \"%s\" for LVM storage volume \"%s\" on storage pool \"%s\": %s", dstMountPoint, s.volume.Name, s.pool.Name, err)
+			return err
+		}
+
+		poolName := s.getOnDiskPoolName()
+		lvFsType := s.getLvmFilesystem()
+		lvSize, err := s.getLvmVolumeSize()
+		if lvSize == "" {
+			logger.Errorf("Failed to get size for LVM storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+			return err
+		}
+
+		_, err = s.createSnapshotLV(poolName, source.Name, storagePoolVolumeAPIEndpointCustom, s.volume.Name, storagePoolVolumeAPIEndpointCustom, false, s.useThinpool)
+		if err != nil {
+			logger.Errorf("Failed to create snapshot for LVM storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+			return err
+		}
+
+		lvDevPath := getLvmDevPath(poolName, storagePoolVolumeAPIEndpointCustom, s.volume.Name)
+		msg, err := fsGenerateNewUUID(lvFsType, lvDevPath)
+		if err != nil {
+			logger.Errorf("Failed to create new UUID for filesystem \"%s\" for RBD storage volume \"%s\" on storage pool \"%s\": %s: %s", lvFsType, s.volume.Name, s.pool.Name, msg, err)
+			return err
+		}
+
+		logger.Infof(successMsg)
+		return nil
+	}
+
+	if s.pool.Name != source.Pool {
+		// setup storage for the source volume
+		srcStorage, err := storagePoolVolumeInit(s.s, source.Pool, source.Name, storagePoolVolumeTypeCustom)
+		if err != nil {
+			logger.Errorf("Failed to initialize LVM storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+			return err
+		}
+
+		ourMount, err := srcStorage.StoragePoolVolumeMount()
+		if err != nil {
+			logger.Errorf("Failed to mount LVM storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+			return err
+		}
+
+		if ourMount {
+			defer srcStorage.StoragePoolVolumeUmount()
+		}
+	}
+
+	err := s.StoragePoolVolumeCreate()
+	if err != nil {
+		logger.Errorf("Failed to create LVM storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+		return err
+	}
+
+	bwlimit := s.pool.Config["rsync.bwlimit"]
+	_, err = rsyncLocalCopy(srcMountPoint, dstMountPoint, bwlimit)
+	if err != nil {
+		os.RemoveAll(dstMountPoint)
+		logger.Errorf("Failed to rsync into LVM storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+		return err
+	}
+
+	logger.Infof(successMsg)
+	return nil
+}
diff --git a/lxd/storage_mock.go b/lxd/storage_mock.go
index aacf7cdc0..5019237f7 100644
--- a/lxd/storage_mock.go
+++ b/lxd/storage_mock.go
@@ -226,3 +226,7 @@ func (s *storageMock) StorageEntitySetQuota(volumeType int, size int64, data int
 func (s *storageMock) StoragePoolResources() (*api.ResourcesStoragePool, error) {
 	return &api.ResourcesStoragePool{}, nil
 }
+
+func (s *storageMock) StoragePoolVolumeCopy(source *api.StorageVolumeSource) error {
+	return nil
+}
diff --git a/lxd/storage_zfs.go b/lxd/storage_zfs.go
index 30a616b93..cd39b8bd9 100644
--- a/lxd/storage_zfs.go
+++ b/lxd/storage_zfs.go
@@ -423,10 +423,52 @@ func (s *storageZfs) StoragePoolVolumeDelete() error {
 
 	poolName := s.getOnDiskPoolName()
 	if zfsFilesystemEntityExists(poolName, fs) {
-		err := zfsPoolVolumeDestroy(s.getOnDiskPoolName(), fs)
+		removable := true
+		snaps, err := zfsPoolListSnapshots(poolName, fs)
 		if err != nil {
 			return err
 		}
+
+		for _, snap := range snaps {
+			var err error
+			removable, err = zfsPoolVolumeSnapshotRemovable(poolName, fs, snap)
+			if err != nil {
+				return err
+			}
+
+			if !removable {
+				break
+			}
+		}
+
+		if removable {
+			origin, err := zfsFilesystemEntityPropertyGet(poolName, fs, "origin")
+			if err != nil {
+				return err
+			}
+			poolName := s.getOnDiskPoolName()
+			origin = strings.TrimPrefix(origin, fmt.Sprintf("%s/", poolName))
+
+			err = zfsPoolVolumeDestroy(poolName, fs)
+			if err != nil {
+				return err
+			}
+
+			err = zfsPoolVolumeCleanup(poolName, origin)
+			if err != nil {
+				return err
+			}
+		} else {
+			err := zfsPoolVolumeSet(poolName, fs, "mountpoint", "none")
+			if err != nil {
+				return err
+			}
+
+			err = zfsPoolVolumeRename(poolName, fs, fmt.Sprintf("deleted/custom/%s", uuid.NewRandom().String()))
+			if err != nil {
+				return err
+			}
+		}
 	}
 
 	if shared.PathExists(customPoolVolumeMntPoint) {
@@ -2414,3 +2456,96 @@ func (s *storageZfs) StoragePoolResources() (*api.ResourcesStoragePool, error) {
 
 	return &res, nil
 }
+
+func (s *storageZfs) StoragePoolVolumeCopy(source *api.StorageVolumeSource) error {
+	logger.Infof("Copying ZFS storage volume \"%s\" on storage pool \"%s\" as \"%s\" to storage pool \"%s\"", source.Name, source.Pool, s.volume.Name, s.pool.Name)
+	successMsg := fmt.Sprintf("Copied ZFS storage volume \"%s\" on storage pool \"%s\" as \"%s\" to storage pool \"%s\"", source.Name, source.Pool, s.volume.Name, s.pool.Name)
+
+	srcMountPoint := getStoragePoolVolumeMountPoint(source.Pool, source.Name)
+	dstMountPoint := getStoragePoolVolumeMountPoint(s.pool.Name, s.volume.Name)
+
+	if s.pool.Name == source.Pool && (s.pool.Config["zfs.clone_copy"] == "" || shared.IsTrue(s.pool.Config["zfs.clone_copy"])) {
+		poolName := s.getOnDiskPoolName()
+		snapUUID := fmt.Sprintf("copy-%s", uuid.NewRandom().String())
+
+		// create snapshot for zfs to clone from
+		err := zfsPoolVolumeSnapshotCreate(poolName, storagePoolVolumeTypeNameCustom, snapUUID)
+		if err != nil {
+			logger.Errorf("Failed to create snapshot for ZFS storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+			return err
+		}
+
+		srcDataset := fmt.Sprintf("custom/%s", source.Name)
+		dstDataset := fmt.Sprintf("custom/%s", s.volume.Name)
+
+		// clone snapshot
+		err = zfsPoolVolumeClone(poolName, srcDataset, snapUUID, dstDataset, dstMountPoint)
+		if err != nil {
+			logger.Errorf("Failed to create clone for ZFS storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+			return err
+		}
+
+		err = zfsPoolVolumeSet(poolName, dstDataset, "mountpoint", dstMountPoint)
+		if err != nil {
+			logger.Errorf("Failed to set mountpoint \"%s\" for ZFS storage volume \"%s\" on storage pool \"%s\": %s", dstMountPoint, s.volume.Name, s.pool.Name, err)
+			return err
+		}
+
+		if !shared.IsMountPoint(dstMountPoint) {
+			zfsMount(poolName, dstDataset)
+		}
+
+		// apply quota
+		if s.volume.Config["size"] != "" {
+			size, err := shared.ParseByteSizeString(s.volume.Config["size"])
+			if err != nil {
+				logger.Errorf("Failed to parse size for ZFS storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+				return err
+			}
+
+			err = s.StorageEntitySetQuota(storagePoolVolumeTypeCustom, size, nil)
+			if err != nil {
+				logger.Errorf("Failed to set quota for ZFS storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+				return err
+			}
+		}
+
+		logger.Infof(successMsg)
+		return nil
+	}
+
+	if s.pool.Name != source.Pool {
+		// setup storage for the source volume
+		srcStorage, err := storagePoolVolumeInit(s.s, source.Pool, source.Name, storagePoolVolumeTypeCustom)
+		if err != nil {
+			logger.Errorf("Failed to initialize ZFS storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+			return err
+		}
+
+		ourMount, err := srcStorage.StoragePoolVolumeMount()
+		if err != nil {
+			logger.Errorf("Failed to mount ZFS storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+			return err
+		}
+		if ourMount {
+			defer srcStorage.StoragePoolVolumeUmount()
+		}
+	}
+
+	err := s.StoragePoolVolumeCreate()
+	if err != nil {
+		logger.Errorf("Failed to create ZFS storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+		return err
+	}
+
+	bwlimit := s.pool.Config["rsync.bwlimit"]
+	_, err = rsyncLocalCopy(srcMountPoint, dstMountPoint, bwlimit)
+	if err != nil {
+		os.RemoveAll(dstMountPoint)
+		logger.Errorf("Failed to rsync into ZFS storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
+		return err
+	}
+
+	logger.Infof(successMsg)
+	return nil
+}

From 3bdbf71f26b758b5eb73db525bd42ae8ab8b5939 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Mon, 15 Jan 2018 17:41:17 +0100
Subject: [PATCH 06/10] storage volumes: local storage volume {move,copy}

Closes #3984.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/storage_btrfs.go         | 2 +-
 lxd/storage_volumes_utils.go | 9 +++++++--
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/lxd/storage_btrfs.go b/lxd/storage_btrfs.go
index ee95ecdbc..2eca2c6a8 100644
--- a/lxd/storage_btrfs.go
+++ b/lxd/storage_btrfs.go
@@ -2299,7 +2299,7 @@ func (s *storageBtrfs) StoragePoolVolumeCopy(source *api.StorageVolumeSource) er
 
 	if s.pool.Name == source.Pool {
 		// Ensure that the directories immediately preceding the subvolume directory exist.
-		customDir := getStoragePoolVolumeMountPoint(s.pool.Name, s.volume.Name)
+		customDir := getStoragePoolVolumeMountPoint(s.pool.Name, "")
 		if !shared.PathExists(customDir) {
 			err := os.MkdirAll(customDir, 0700)
 			if err != nil {
diff --git a/lxd/storage_volumes_utils.go b/lxd/storage_volumes_utils.go
index 0916ae35b..40da0fb78 100644
--- a/lxd/storage_volumes_utils.go
+++ b/lxd/storage_volumes_utils.go
@@ -364,8 +364,13 @@ func storagePoolVolumeCreateInternal(state *state.State, poolName string, vol *a
 
 	poolID, _, _ := s.GetContainerPoolInfo()
 
-	// Create storage volume.
-	err = s.StoragePoolVolumeCreate()
+	if vol.Source.Name == "" {
+		// Create storage volume.
+		err = s.StoragePoolVolumeCreate()
+	} else {
+		// Copy storage volume.
+		err = s.StoragePoolVolumeCopy(&vol.Source)
+	}
 	if err != nil {
 		state.DB.StoragePoolVolumeDelete(volumeName, volumeType, poolID)
 		return err

From 6cc466dba34cb4556ce905e52ed570af9f85e2b5 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Tue, 16 Jan 2018 13:01:13 +0100
Subject: [PATCH 07/10] storage volumes: translate volume properties

Closes #3984.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/storage_pools_utils.go    |  2 ++
 lxd/storage_volumes_config.go | 84 ++++++++++++++++++++++++++++++++++++-------
 lxd/storage_volumes_utils.go  | 17 ++++++++-
 3 files changed, 90 insertions(+), 13 deletions(-)

diff --git a/lxd/storage_pools_utils.go b/lxd/storage_pools_utils.go
index 6df16c870..34efd0ecd 100644
--- a/lxd/storage_pools_utils.go
+++ b/lxd/storage_pools_utils.go
@@ -10,6 +10,8 @@ import (
 	"github.com/lxc/lxd/shared/version"
 )
 
+var supportedPoolTypes = []string{"btrfs", "ceph", "dir", "lvm", "zfs"}
+
 func storagePoolUpdate(state *state.State, name, newDescription string, newConfig map[string]string) error {
 	s, err := storagePoolInit(state, name)
 	if err != nil {
diff --git a/lxd/storage_volumes_config.go b/lxd/storage_volumes_config.go
index 8e64f9454..5d59404d4 100644
--- a/lxd/storage_volumes_config.go
+++ b/lxd/storage_volumes_config.go
@@ -8,6 +8,36 @@ import (
 	"github.com/lxc/lxd/shared/api"
 )
 
+func storageVolumePropertiesTranslate(targetConfig map[string]string, targetParentPoolDriver string) (map[string]string, error) {
+	newConfig := make(map[string]string, len(targetConfig))
+	for key, val := range targetConfig {
+		// User keys are not validated.
+		if strings.HasPrefix(key, "user.") {
+			continue
+		}
+
+		// Validate storage volume config keys.
+		validator, ok := storageVolumeConfigKeys[key]
+		if !ok {
+			return nil, fmt.Errorf("Invalid storage volume configuration key: %s", key)
+		}
+
+		validStorageDrivers, err := validator(val)
+		if err != nil {
+			return nil, err
+		}
+
+		// Drop invalid keys.
+		if !shared.StringInSlice(targetParentPoolDriver, validStorageDrivers) {
+			continue
+		}
+
+		newConfig[key] = val
+	}
+
+	return newConfig, nil
+}
+
 func updateStoragePoolVolumeError(unchangeable []string, driverName string) error {
 	return fmt.Errorf(`The %v properties cannot be changed for "%s" `+
 		`storage volumes`, unchangeable, driverName)
@@ -37,23 +67,53 @@ var changeableStoragePoolVolumeProperties = map[string][]string{
 		"zfs.use_refquota"},
 }
 
-var storageVolumeConfigKeys = map[string]func(value string) error{
-	"block.filesystem": func(value string) error {
-		return shared.IsOneOf(value, []string{"btrfs", "ext4", "xfs"})
+// btrfs, ceph, dir, lvm, zfs
+var storageVolumeConfigKeys = map[string]func(value string) ([]string, error){
+	"block.filesystem": func(value string) ([]string, error) {
+		err := shared.IsOneOf(value, []string{"btrfs", "ext4", "xfs"})
+		if err != nil {
+			return nil, err
+		}
+
+		return []string{"ceph", "lvm"}, nil
+	},
+	"block.mount_options": func(value string) ([]string, error) {
+		return []string{"ceph", "lvm"}, shared.IsAny(value)
 	},
-	"block.mount_options": shared.IsAny,
-	"size": func(value string) error {
+	"size": func(value string) ([]string, error) {
 		if value == "" {
-			return nil
+			return []string{"btrfs", "ceph", "lvm", "zfs"}, nil
 		}
 
 		_, err := shared.ParseByteSizeString(value)
-		return err
+		if err != nil {
+			return nil, err
+		}
+
+		return []string{"btrfs", "ceph", "lvm", "zfs"}, nil
+	},
+	"volatile.idmap.last": func(value string) ([]string, error) {
+		return supportedPoolTypes, shared.IsAny(value)
+	},
+	"volatile.idmap.next": func(value string) ([]string, error) {
+		return supportedPoolTypes, shared.IsAny(value)
+	},
+	"zfs.remove_snapshots": func(value string) ([]string, error) {
+		err := shared.IsBool(value)
+		if err != nil {
+			return nil, err
+		}
+
+		return []string{"zfs"}, nil
+	},
+	"zfs.use_refquota": func(value string) ([]string, error) {
+		err := shared.IsBool(value)
+		if err != nil {
+			return nil, err
+		}
+
+		return []string{"zfs"}, nil
 	},
-	"volatile.idmap.last":  shared.IsAny,
-	"volatile.idmap.next":  shared.IsAny,
-	"zfs.remove_snapshots": shared.IsBool,
-	"zfs.use_refquota":     shared.IsBool,
 }
 
 func storageVolumeValidateConfig(name string, config map[string]string, parentPool *api.StoragePool) error {
@@ -69,7 +129,7 @@ func storageVolumeValidateConfig(name string, config map[string]string, parentPo
 			return fmt.Errorf("Invalid storage volume configuration key: %s", key)
 		}
 
-		err := validator(val)
+		_, err := validator(val)
 		if err != nil {
 			return err
 		}
diff --git a/lxd/storage_volumes_utils.go b/lxd/storage_volumes_utils.go
index 40da0fb78..7f068715e 100644
--- a/lxd/storage_volumes_utils.go
+++ b/lxd/storage_volumes_utils.go
@@ -346,6 +346,22 @@ func storagePoolVolumeCreateInternal(state *state.State, poolName string, vol *a
 	volumeTypeName := vol.Type
 	volumeConfig := vol.Config
 
+	if vol.Source.Name != "" {
+		s, err := storagePoolInit(state, poolName)
+		if err != nil {
+			return err
+		}
+
+		driver := s.GetStorageTypeName()
+		newConfig, err := storageVolumePropertiesTranslate(vol.Config, driver)
+		if err != nil {
+			return err
+		}
+
+		vol.Config = newConfig
+		volumeConfig = newConfig
+	}
+
 	err := storagePoolVolumeDBCreate(state, poolName, volumeName, volumeDescription, volumeTypeName, volumeConfig)
 	if err != nil {
 		return err
@@ -363,7 +379,6 @@ func storagePoolVolumeCreateInternal(state *state.State, poolName string, vol *a
 	}
 
 	poolID, _, _ := s.GetContainerPoolInfo()
-
 	if vol.Source.Name == "" {
 		// Create storage volume.
 		err = s.StoragePoolVolumeCreate()

From 5efce19e505583545bf81f74712ad1345af900cf Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Mon, 15 Jan 2018 17:47:07 +0100
Subject: [PATCH 08/10] lxc: implement local storage {move,copy}

Closes #3984.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxc/storage.go | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++------
 po/de.po       |  60 +++++++++++++++++-----------
 po/el.po       |  59 ++++++++++++++++-----------
 po/es.po       |  59 ++++++++++++++++-----------
 po/fi.po       |  59 ++++++++++++++++-----------
 po/fr.po       |  60 +++++++++++++++++-----------
 po/id.po       |  59 ++++++++++++++++-----------
 po/it.po       |  59 ++++++++++++++++-----------
 po/ja.po       |  60 +++++++++++++++++-----------
 po/lxd.pot     |  58 ++++++++++++++++-----------
 po/nb_NO.po    |  59 ++++++++++++++++-----------
 po/nl.po       |  59 ++++++++++++++++-----------
 po/pl.po       |  59 ++++++++++++++++-----------
 po/pt_BR.po    |  59 ++++++++++++++++-----------
 po/ru.po       |  59 ++++++++++++++++-----------
 po/sr.po       |  59 ++++++++++++++++-----------
 po/sv.po       |  59 ++++++++++++++++-----------
 po/tr.po       |  59 ++++++++++++++++-----------
 po/zh.po       |  59 ++++++++++++++++-----------
 po/zh_Hans.po  |  59 ++++++++++++++++-----------
 20 files changed, 777 insertions(+), 469 deletions(-)

diff --git a/lxc/storage.go b/lxc/storage.go
index 5f294761a..24ddaf0a8 100644
--- a/lxc/storage.go
+++ b/lxc/storage.go
@@ -23,6 +23,7 @@ import (
 
 type storageCmd struct {
 	resources bool
+	confArgs  configList
 }
 
 func (c *storageCmd) showByDefault() bool {
@@ -129,7 +130,13 @@ lxc storage volume detach [<remote>:]<pool> <volume> <container> [device name]
     Detach a storage volume from the specified container.
 
 lxc storage volume detach-profile [<remote:>]<pool> <volume> <profile> [device name]
-    Detach a storage volume from the specified profile.
+	Detach a storage volume from the specified profile.
+
+lxc storage volume copy [<pool>/]<volume> [<pool>/]<volume> [--config|-c <key=value>...]
+    Copy an existing volume to a new volume at the specified pool.
+
+lxc storage volume move [<pool>/]<volume> [<pool>/]<volume>
+    Move an existing volume to the specified pool.
 
 Unless specified through a prefix, all volume operations affect "custom" (user created) volumes.
 
@@ -148,6 +155,7 @@ lxc storage volume show default container/data
 }
 
 func (c *storageCmd) flags() {
+	gnuflag.Var(&c.confArgs, "config", i18n.G("Config key/value to apply to the new storage volume"))
 	gnuflag.BoolVar(&c.resources, "resources", false, i18n.G("Show the resources available to the storage pool"))
 }
 
@@ -270,6 +278,22 @@ func (c *storageCmd) run(conf *config.Config, args []string) error {
 			pool := sub
 			volume := args[3]
 			return c.doStoragePoolVolumeShow(client, pool, volume)
+		case "copy":
+			// only support non remote for now
+			if len(args) != 4 {
+				return errArgs
+			}
+			src := sub
+			dst := args[3]
+			return c.doStoragePoolVolumeCopy(client, src, dst, false)
+		case "move":
+			// only support non remote for now
+			if len(args) != 4 {
+				return errArgs
+			}
+			src := sub
+			dst := args[3]
+			return c.doStoragePoolVolumeCopy(client, src, dst, true)
 		default:
 			return errArgs
 		}
@@ -322,9 +346,7 @@ func (c *storageCmd) run(conf *config.Config, args []string) error {
 	}
 }
 
-func (c *storageCmd) parseVolume(name string) (string, string) {
-	defaultType := "custom"
-
+func (c *storageCmd) parseVolume(defaultType string, name string) (string, string) {
 	fields := strings.SplitN(name, "/", 2)
 	if len(fields) == 1 {
 		return fields[0], defaultType
@@ -350,7 +372,7 @@ func (c *storageCmd) doStoragePoolVolumeAttach(client lxd.ContainerServer, pool
 		devPath = args[2]
 	}
 
-	volName, volType := c.parseVolume(volume)
+	volName, volType := c.parseVolume("custom", volume)
 	if volType != "custom" {
 		return fmt.Errorf(i18n.G("Only \"custom\" volumes can be attached to containers."))
 	}
@@ -443,7 +465,7 @@ func (c *storageCmd) doStoragePoolVolumeAttachProfile(client lxd.ContainerServer
 		devPath = args[2]
 	}
 
-	volName, volType := c.parseVolume(volume)
+	volName, volType := c.parseVolume("custom", volume)
 	if volType != "custom" {
 		return fmt.Errorf(i18n.G("Only \"custom\" volumes can be attached to containers."))
 	}
@@ -805,7 +827,7 @@ func (c *storageCmd) doStoragePoolVolumesList(conf *config.Config, remote string
 
 func (c *storageCmd) doStoragePoolVolumeCreate(client lxd.ContainerServer, pool string, volume string, args []string) error {
 	// Parse the input
-	volName, volType := c.parseVolume(volume)
+	volName, volType := c.parseVolume("custom", volume)
 
 	// Create the storage volume entry
 	vol := api.StorageVolumesPost{}
@@ -834,7 +856,7 @@ func (c *storageCmd) doStoragePoolVolumeCreate(client lxd.ContainerServer, pool
 
 func (c *storageCmd) doStoragePoolVolumeDelete(client lxd.ContainerServer, pool string, volume string) error {
 	// Parse the input
-	volName, volType := c.parseVolume(volume)
+	volName, volType := c.parseVolume("custom", volume)
 
 	// Delete the volume
 	err := client.DeleteStoragePoolVolume(pool, volType, volName)
@@ -853,7 +875,7 @@ func (c *storageCmd) doStoragePoolVolumeGet(client lxd.ContainerServer, pool str
 	}
 
 	// Parse input
-	volName, volType := c.parseVolume(volume)
+	volName, volType := c.parseVolume("custom", volume)
 
 	// Get the storage volume entry
 	resp, _, err := client.GetStoragePoolVolume(pool, volType, volName)
@@ -876,7 +898,7 @@ func (c *storageCmd) doStoragePoolVolumeSet(client lxd.ContainerServer, pool str
 	}
 
 	// Parse the input
-	volName, volType := c.parseVolume(volume)
+	volName, volType := c.parseVolume("custom", volume)
 
 	// Get the storage volume entry
 	vol, etag, err := client.GetStoragePoolVolume(pool, volType, volName)
@@ -913,7 +935,7 @@ func (c *storageCmd) doStoragePoolVolumeSet(client lxd.ContainerServer, pool str
 
 func (c *storageCmd) doStoragePoolVolumeShow(client lxd.ContainerServer, pool string, volume string) error {
 	// Parse the input
-	volName, volType := c.parseVolume(volume)
+	volName, volType := c.parseVolume("custom", volume)
 
 	// Get the storage volume entry
 	vol, _, err := client.GetStoragePoolVolume(pool, volType, volName)
@@ -933,9 +955,84 @@ func (c *storageCmd) doStoragePoolVolumeShow(client lxd.ContainerServer, pool st
 	return nil
 }
 
+func (c *storageCmd) doStoragePoolVolumeCopy(client lxd.ContainerServer, src string, dst string, rm bool) error {
+	// validate both src and dst string
+	dstVolName, dstVolPool := c.parseVolume("", dst)
+	srcVolName, srcVolPool := c.parseVolume("", src)
+	if dstVolPool == "" || srcVolPool == "" {
+		defaultProfile, _, err := client.GetProfile("default")
+		if err != nil {
+			return fmt.Errorf("No storage pool for source or target volume specified")
+		}
+
+		rootDiskDevice := defaultProfile.Devices["root"]
+		if rootDiskDevice != nil &&
+			rootDiskDevice["pool"] != "" &&
+			rootDiskDevice["type"] == "disk" &&
+			rootDiskDevice["source"] == "" &&
+			rootDiskDevice["path"] == "/" {
+
+			if srcVolPool == "" {
+				srcVolPool = rootDiskDevice["pool"]
+			}
+
+			if dstVolPool == "" {
+				dstVolPool = rootDiskDevice["pool"]
+			}
+		} else {
+			return fmt.Errorf("No storage pool for source or target volume specified")
+		}
+	}
+
+	// Check if the requested storage volume actually exists
+	srcVol, _, err := client.GetStoragePoolVolume(srcVolPool, "custom", srcVolName)
+	if err != nil {
+		return err
+	}
+	client.GetProfile("default")
+
+	if rm && len(srcVol.UsedBy) > 0 {
+		return fmt.Errorf("Storage volume \"%s\" is still in use by profile or containers", srcVol.Name)
+	}
+
+	// Create the storage volume entry
+	dstVol := api.StorageVolumesPost{}
+	dstVol.Name = dstVolName
+	dstVol.Type = "custom"
+	dstVol.Config = srcVol.Config
+	dstVol.Source = api.StorageVolumeSource{
+		Name: srcVol.Name,
+		Type: "custom",
+		Pool: srcVolPool,
+	}
+
+	// Allow setting additional config keys
+	if configMap != nil {
+		for key, value := range configMap {
+			dstVol.Config[key] = value
+		}
+	}
+
+	// copy is a special case of create
+	err = client.CreateStoragePoolVolume(dstVolPool, dstVol)
+	if err != nil {
+		return err
+	}
+
+	if rm {
+		err = client.DeleteStoragePoolVolume(srcVolPool, "custom", srcVolName)
+		if err != nil {
+			return err
+		}
+	}
+
+	fmt.Printf("Successfully copied %s to %s \n", src, dst)
+	return nil
+}
+
 func (c *storageCmd) doStoragePoolVolumeEdit(client lxd.ContainerServer, pool string, volume string) error {
 	// Parse the input
-	volName, volType := c.parseVolume(volume)
+	volName, volType := c.parseVolume("custom", volume)
 
 	// If stdin isn't a terminal, read text from it
 	if !termios.IsTerminal(int(syscall.Stdin)) {
@@ -1001,7 +1098,7 @@ func (c *storageCmd) doStoragePoolVolumeEdit(client lxd.ContainerServer, pool st
 
 func (c *storageCmd) doStoragePoolVolumeRename(client lxd.ContainerServer, pool string, volume string, args []string) error {
 	// Parse the input
-	volName, volType := c.parseVolume(volume)
+	volName, volType := c.parseVolume("custom", volume)
 
 	// Create the storage volume entry
 	vol := api.StorageVolumePost{}
diff --git a/po/de.po b/po/de.po
index 1dd7fd420..fc926d175 100644
--- a/po/de.po
+++ b/po/de.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: LXD\n"
 "Report-Msgid-Bugs-To: lxc-devel at lists.linuxcontainers.org\n"
-"POT-Creation-Date: 2018-01-11 17:16-0500\n"
+"POT-Creation-Date: 2018-01-16 11:17+0100\n"
 "PO-Revision-Date: 2017-02-14 17:11+0000\n"
 "Last-Translator: Tim Rose <tim at netlope.de>\n"
 "Language-Team: German <https://hosted.weblate.org/projects/linux-containers/"
@@ -19,7 +19,7 @@ msgstr ""
 "Plural-Forms: nplurals=2; plural=n != 1;\n"
 "X-Generator: Weblate 2.14-dev\n"
 
-#: lxc/storage.go:33
+#: lxc/storage.go:34
 #, fuzzy
 msgid ""
 "### This is a yaml representation of a storage pool.\n"
@@ -54,7 +54,7 @@ msgstr ""
 "###\n"
 "### Der Name wird zwar angezeigt, lässt sich jedoch nicht ändern.\n"
 
-#: lxc/storage.go:50
+#: lxc/storage.go:51
 #, fuzzy
 msgid ""
 "### This is a yaml representation of a storage volume.\n"
@@ -402,7 +402,7 @@ msgstr ""
 msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
 
-#: lxc/profile.go:546 lxc/storage.go:653
+#: lxc/profile.go:546 lxc/storage.go:675
 msgid "Cannot provide container name to list"
 msgstr ""
 
@@ -428,8 +428,13 @@ msgstr ""
 msgid "Config key/value to apply to the new container"
 msgstr "kann nicht zum selben Container Namen kopieren"
 
+#: lxc/storage.go:158
+#, fuzzy
+msgid "Config key/value to apply to the new storage volume"
+msgstr "kann nicht zum selben Container Namen kopieren"
+
 #: lxc/config.go:816 lxc/config.go:881 lxc/config.go:1331 lxc/image.go:1190
-#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:604 lxc/storage.go:979
+#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:626 lxc/storage.go:1058
 #, fuzzy, c-format
 msgid "Config parsing error: %s"
 msgstr "YAML Analyse Fehler %v\n"
@@ -498,11 +503,11 @@ msgid "Creating the container"
 msgstr "kann nicht zum selben Container Namen kopieren"
 
 #: lxc/image.go:234 lxc/image.go:1137 lxc/list.go:465 lxc/network.go:525
-#: lxc/storage.go:682 lxc/storage.go:793
+#: lxc/storage.go:704 lxc/storage.go:819
 msgid "DESCRIPTION"
 msgstr ""
 
-#: lxc/storage.go:683
+#: lxc/storage.go:705
 msgid "DRIVER"
 msgstr ""
 
@@ -827,7 +832,7 @@ msgstr ""
 msgid "Missing summary."
 msgstr "Fehlende Zusammenfassung."
 
-#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:402 lxc/storage.go:522
+#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:424 lxc/storage.go:544
 msgid "More than one device matches, specify the device name."
 msgstr ""
 
@@ -851,7 +856,7 @@ msgid "Must supply container name for: "
 msgstr "der Name des Ursprung Containers muss angegeben werden"
 
 #: lxc/list.go:467 lxc/network.go:522 lxc/profile.go:573 lxc/remote.go:409
-#: lxc/storage.go:681 lxc/storage.go:792
+#: lxc/storage.go:703 lxc/storage.go:818
 msgid "NAME"
 msgstr ""
 
@@ -902,7 +907,7 @@ msgstr "Kein Zertifikat zum hinzufügen bereitgestellt"
 msgid "No device found for this network"
 msgstr "Kein Zertifikat für diese Verbindung"
 
-#: lxc/storage.go:411 lxc/storage.go:531
+#: lxc/storage.go:433 lxc/storage.go:553
 #, fuzzy
 msgid "No device found for this storage volume."
 msgstr "Kein Zertifikat für diese Verbindung"
@@ -911,7 +916,7 @@ msgstr "Kein Zertifikat für diese Verbindung"
 msgid "No fingerprint specified."
 msgstr "Kein Fingerabdruck angegeben."
 
-#: lxc/storage.go:355 lxc/storage.go:448
+#: lxc/storage.go:377 lxc/storage.go:470
 msgid "Only \"custom\" volumes can be attached to containers."
 msgstr ""
 
@@ -996,7 +1001,7 @@ msgstr ""
 msgid "Pid: %d"
 msgstr ""
 
-#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:605 lxc/storage.go:980
+#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:627 lxc/storage.go:1059
 msgid "Press enter to open the editor again"
 msgstr ""
 
@@ -1108,7 +1113,7 @@ msgstr ""
 msgid "Remove %s (yes/no): "
 msgstr ""
 
-#: lxc/storage.go:1011
+#: lxc/storage.go:1090
 #, c-format
 msgid "Renamed storage volume from \"%s\" to \"%s\""
 msgstr ""
@@ -1148,7 +1153,7 @@ msgstr ""
 msgid "SNAPSHOTS"
 msgstr ""
 
-#: lxc/storage.go:684
+#: lxc/storage.go:706
 msgid "SOURCE"
 msgstr ""
 
@@ -1218,7 +1223,7 @@ msgstr ""
 msgid "Show the resources available to the server"
 msgstr ""
 
-#: lxc/storage.go:151
+#: lxc/storage.go:159
 msgid "Show the resources available to the storage pool"
 msgstr ""
 
@@ -1273,12 +1278,12 @@ msgstr "Anhalten des Containers fehlgeschlagen!"
 msgid "Stopping the container failed: %s"
 msgstr "Anhalten des Containers fehlgeschlagen!"
 
-#: lxc/storage.go:496
+#: lxc/storage.go:518
 #, fuzzy, c-format
 msgid "Storage pool %s created"
 msgstr "Profil %s erstellt\n"
 
-#: lxc/storage.go:555
+#: lxc/storage.go:577
 #, fuzzy, c-format
 msgid "Storage pool %s deleted"
 msgstr "Profil %s gelöscht\n"
@@ -1288,12 +1293,12 @@ msgstr "Profil %s gelöscht\n"
 msgid "Storage pool name"
 msgstr "Profilname kann nicht geändert werden"
 
-#: lxc/storage.go:826
+#: lxc/storage.go:852
 #, fuzzy, c-format
 msgid "Storage volume %s created"
 msgstr "Profil %s erstellt\n"
 
-#: lxc/storage.go:841
+#: lxc/storage.go:867
 #, fuzzy, c-format
 msgid "Storage volume %s deleted"
 msgstr "Profil %s gelöscht\n"
@@ -1311,7 +1316,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:791
+#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:817
 msgid "TYPE"
 msgstr ""
 
@@ -1349,7 +1354,7 @@ msgstr ""
 msgid "The opposite of \"lxc pause\" is \"lxc start\"."
 msgstr ""
 
-#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:416 lxc/storage.go:536
+#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:438 lxc/storage.go:558
 #, fuzzy
 msgid "The specified device doesn't exist"
 msgstr "entfernte Instanz %s existiert nicht"
@@ -1432,7 +1437,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:685 lxc/storage.go:794
+#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:707 lxc/storage.go:820
 msgid "USED BY"
 msgstr ""
 
@@ -2351,7 +2356,7 @@ msgid ""
 "    Create a snapshot of \"u1\" called \"snap0\"."
 msgstr ""
 
-#: lxc/storage.go:64
+#: lxc/storage.go:65
 msgid ""
 "Usage: lxc storage <subcommand> [options]\n"
 "\n"
@@ -2426,7 +2431,14 @@ msgid ""
 "\n"
 "lxc storage volume detach-profile [<remote:>]<pool> <volume> <profile> "
 "[device name]\n"
-"    Detach a storage volume from the specified profile.\n"
+"\tDetach a storage volume from the specified profile.\n"
+"\n"
+"lxc storage volume copy [<pool>/]<volume> [<pool>/]<volume> [--config|-c "
+"<key=value>...]\n"
+"    Copy an existing volume to a new volume at the specified pool.\n"
+"\n"
+"lxc storage volume move [<pool>/]<volume> [<pool>/]<volume>\n"
+"    Move an existing volume to the specified pool.\n"
 "\n"
 "Unless specified through a prefix, all volume operations affect \"custom"
 "\" (user created) volumes.\n"
diff --git a/po/el.po b/po/el.po
index c4db31451..ffc7b595c 100644
--- a/po/el.po
+++ b/po/el.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: lxd\n"
 "Report-Msgid-Bugs-To: lxc-devel at lists.linuxcontainers.org\n"
-"POT-Creation-Date: 2018-01-11 17:16-0500\n"
+"POT-Creation-Date: 2018-01-16 11:17+0100\n"
 "PO-Revision-Date: 2017-02-14 08:00+0000\n"
 "Last-Translator: Simos Xenitellis <simos.65 at gmail.com>\n"
 "Language-Team: Greek <https://hosted.weblate.org/projects/linux-containers/"
@@ -19,7 +19,7 @@ msgstr ""
 "Plural-Forms: nplurals=2; plural=n != 1;\n"
 "X-Generator: Weblate 2.12-dev\n"
 
-#: lxc/storage.go:33
+#: lxc/storage.go:34
 msgid ""
 "### This is a yaml representation of a storage pool.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -36,7 +36,7 @@ msgid ""
 "###   zfs.pool_name: default"
 msgstr ""
 
-#: lxc/storage.go:50
+#: lxc/storage.go:51
 msgid ""
 "### This is a yaml representation of a storage volume.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -292,7 +292,7 @@ msgstr ""
 msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
 
-#: lxc/profile.go:546 lxc/storage.go:653
+#: lxc/profile.go:546 lxc/storage.go:675
 msgid "Cannot provide container name to list"
 msgstr ""
 
@@ -317,8 +317,12 @@ msgstr ""
 msgid "Config key/value to apply to the new container"
 msgstr ""
 
+#: lxc/storage.go:158
+msgid "Config key/value to apply to the new storage volume"
+msgstr ""
+
 #: lxc/config.go:816 lxc/config.go:881 lxc/config.go:1331 lxc/image.go:1190
-#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:604 lxc/storage.go:979
+#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:626 lxc/storage.go:1058
 #, c-format
 msgid "Config parsing error: %s"
 msgstr ""
@@ -385,11 +389,11 @@ msgid "Creating the container"
 msgstr ""
 
 #: lxc/image.go:234 lxc/image.go:1137 lxc/list.go:465 lxc/network.go:525
-#: lxc/storage.go:682 lxc/storage.go:793
+#: lxc/storage.go:704 lxc/storage.go:819
 msgid "DESCRIPTION"
 msgstr ""
 
-#: lxc/storage.go:683
+#: lxc/storage.go:705
 msgid "DRIVER"
 msgstr ""
 
@@ -704,7 +708,7 @@ msgstr "  Χρήση μνήμης:"
 msgid "Missing summary."
 msgstr ""
 
-#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:402 lxc/storage.go:522
+#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:424 lxc/storage.go:544
 msgid "More than one device matches, specify the device name."
 msgstr ""
 
@@ -725,7 +729,7 @@ msgid "Must supply container name for: "
 msgstr ""
 
 #: lxc/list.go:467 lxc/network.go:522 lxc/profile.go:573 lxc/remote.go:409
-#: lxc/storage.go:681 lxc/storage.go:792
+#: lxc/storage.go:703 lxc/storage.go:818
 msgid "NAME"
 msgstr ""
 
@@ -774,7 +778,7 @@ msgstr ""
 msgid "No device found for this network"
 msgstr ""
 
-#: lxc/storage.go:411 lxc/storage.go:531
+#: lxc/storage.go:433 lxc/storage.go:553
 msgid "No device found for this storage volume."
 msgstr ""
 
@@ -782,7 +786,7 @@ msgstr ""
 msgid "No fingerprint specified."
 msgstr ""
 
-#: lxc/storage.go:355 lxc/storage.go:448
+#: lxc/storage.go:377 lxc/storage.go:470
 msgid "Only \"custom\" volumes can be attached to containers."
 msgstr ""
 
@@ -864,7 +868,7 @@ msgstr ""
 msgid "Pid: %d"
 msgstr ""
 
-#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:605 lxc/storage.go:980
+#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:627 lxc/storage.go:1059
 msgid "Press enter to open the editor again"
 msgstr ""
 
@@ -973,7 +977,7 @@ msgstr ""
 msgid "Remove %s (yes/no): "
 msgstr ""
 
-#: lxc/storage.go:1011
+#: lxc/storage.go:1090
 #, c-format
 msgid "Renamed storage volume from \"%s\" to \"%s\""
 msgstr ""
@@ -1011,7 +1015,7 @@ msgstr ""
 msgid "SNAPSHOTS"
 msgstr ""
 
-#: lxc/storage.go:684
+#: lxc/storage.go:706
 msgid "SOURCE"
 msgstr ""
 
@@ -1079,7 +1083,7 @@ msgstr ""
 msgid "Show the resources available to the server"
 msgstr ""
 
-#: lxc/storage.go:151
+#: lxc/storage.go:159
 msgid "Show the resources available to the storage pool"
 msgstr ""
 
@@ -1132,12 +1136,12 @@ msgstr ""
 msgid "Stopping the container failed: %s"
 msgstr ""
 
-#: lxc/storage.go:496
+#: lxc/storage.go:518
 #, c-format
 msgid "Storage pool %s created"
 msgstr ""
 
-#: lxc/storage.go:555
+#: lxc/storage.go:577
 #, c-format
 msgid "Storage pool %s deleted"
 msgstr ""
@@ -1146,12 +1150,12 @@ msgstr ""
 msgid "Storage pool name"
 msgstr ""
 
-#: lxc/storage.go:826
+#: lxc/storage.go:852
 #, c-format
 msgid "Storage volume %s created"
 msgstr ""
 
-#: lxc/storage.go:841
+#: lxc/storage.go:867
 #, c-format
 msgid "Storage volume %s deleted"
 msgstr ""
@@ -1168,7 +1172,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:791
+#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:817
 msgid "TYPE"
 msgstr ""
 
@@ -1204,7 +1208,7 @@ msgstr ""
 msgid "The opposite of \"lxc pause\" is \"lxc start\"."
 msgstr ""
 
-#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:416 lxc/storage.go:536
+#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:438 lxc/storage.go:558
 msgid "The specified device doesn't exist"
 msgstr ""
 
@@ -1283,7 +1287,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:685 lxc/storage.go:794
+#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:707 lxc/storage.go:820
 msgid "USED BY"
 msgstr ""
 
@@ -2042,7 +2046,7 @@ msgid ""
 "    Create a snapshot of \"u1\" called \"snap0\"."
 msgstr ""
 
-#: lxc/storage.go:64
+#: lxc/storage.go:65
 msgid ""
 "Usage: lxc storage <subcommand> [options]\n"
 "\n"
@@ -2117,7 +2121,14 @@ msgid ""
 "\n"
 "lxc storage volume detach-profile [<remote:>]<pool> <volume> <profile> "
 "[device name]\n"
-"    Detach a storage volume from the specified profile.\n"
+"\tDetach a storage volume from the specified profile.\n"
+"\n"
+"lxc storage volume copy [<pool>/]<volume> [<pool>/]<volume> [--config|-c "
+"<key=value>...]\n"
+"    Copy an existing volume to a new volume at the specified pool.\n"
+"\n"
+"lxc storage volume move [<pool>/]<volume> [<pool>/]<volume>\n"
+"    Move an existing volume to the specified pool.\n"
 "\n"
 "Unless specified through a prefix, all volume operations affect \"custom"
 "\" (user created) volumes.\n"
diff --git a/po/es.po b/po/es.po
index d2af4eaa1..267b9373f 100644
--- a/po/es.po
+++ b/po/es.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: lxd\n"
 "Report-Msgid-Bugs-To: lxc-devel at lists.linuxcontainers.org\n"
-"POT-Creation-Date: 2018-01-11 17:16-0500\n"
+"POT-Creation-Date: 2018-01-16 11:17+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -16,7 +16,7 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: lxc/storage.go:33
+#: lxc/storage.go:34
 msgid ""
 "### This is a yaml representation of a storage pool.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -33,7 +33,7 @@ msgid ""
 "###   zfs.pool_name: default"
 msgstr ""
 
-#: lxc/storage.go:50
+#: lxc/storage.go:51
 msgid ""
 "### This is a yaml representation of a storage volume.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -288,7 +288,7 @@ msgstr ""
 msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
 
-#: lxc/profile.go:546 lxc/storage.go:653
+#: lxc/profile.go:546 lxc/storage.go:675
 msgid "Cannot provide container name to list"
 msgstr ""
 
@@ -313,8 +313,12 @@ msgstr ""
 msgid "Config key/value to apply to the new container"
 msgstr ""
 
+#: lxc/storage.go:158
+msgid "Config key/value to apply to the new storage volume"
+msgstr ""
+
 #: lxc/config.go:816 lxc/config.go:881 lxc/config.go:1331 lxc/image.go:1190
-#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:604 lxc/storage.go:979
+#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:626 lxc/storage.go:1058
 #, c-format
 msgid "Config parsing error: %s"
 msgstr ""
@@ -381,11 +385,11 @@ msgid "Creating the container"
 msgstr ""
 
 #: lxc/image.go:234 lxc/image.go:1137 lxc/list.go:465 lxc/network.go:525
-#: lxc/storage.go:682 lxc/storage.go:793
+#: lxc/storage.go:704 lxc/storage.go:819
 msgid "DESCRIPTION"
 msgstr ""
 
-#: lxc/storage.go:683
+#: lxc/storage.go:705
 msgid "DRIVER"
 msgstr ""
 
@@ -698,7 +702,7 @@ msgstr ""
 msgid "Missing summary."
 msgstr ""
 
-#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:402 lxc/storage.go:522
+#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:424 lxc/storage.go:544
 msgid "More than one device matches, specify the device name."
 msgstr ""
 
@@ -719,7 +723,7 @@ msgid "Must supply container name for: "
 msgstr ""
 
 #: lxc/list.go:467 lxc/network.go:522 lxc/profile.go:573 lxc/remote.go:409
-#: lxc/storage.go:681 lxc/storage.go:792
+#: lxc/storage.go:703 lxc/storage.go:818
 msgid "NAME"
 msgstr ""
 
@@ -767,7 +771,7 @@ msgstr ""
 msgid "No device found for this network"
 msgstr ""
 
-#: lxc/storage.go:411 lxc/storage.go:531
+#: lxc/storage.go:433 lxc/storage.go:553
 msgid "No device found for this storage volume."
 msgstr ""
 
@@ -775,7 +779,7 @@ msgstr ""
 msgid "No fingerprint specified."
 msgstr ""
 
-#: lxc/storage.go:355 lxc/storage.go:448
+#: lxc/storage.go:377 lxc/storage.go:470
 msgid "Only \"custom\" volumes can be attached to containers."
 msgstr ""
 
@@ -857,7 +861,7 @@ msgstr ""
 msgid "Pid: %d"
 msgstr ""
 
-#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:605 lxc/storage.go:980
+#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:627 lxc/storage.go:1059
 msgid "Press enter to open the editor again"
 msgstr ""
 
@@ -966,7 +970,7 @@ msgstr ""
 msgid "Remove %s (yes/no): "
 msgstr ""
 
-#: lxc/storage.go:1011
+#: lxc/storage.go:1090
 #, c-format
 msgid "Renamed storage volume from \"%s\" to \"%s\""
 msgstr ""
@@ -1004,7 +1008,7 @@ msgstr ""
 msgid "SNAPSHOTS"
 msgstr ""
 
-#: lxc/storage.go:684
+#: lxc/storage.go:706
 msgid "SOURCE"
 msgstr ""
 
@@ -1072,7 +1076,7 @@ msgstr ""
 msgid "Show the resources available to the server"
 msgstr ""
 
-#: lxc/storage.go:151
+#: lxc/storage.go:159
 msgid "Show the resources available to the storage pool"
 msgstr ""
 
@@ -1125,12 +1129,12 @@ msgstr ""
 msgid "Stopping the container failed: %s"
 msgstr ""
 
-#: lxc/storage.go:496
+#: lxc/storage.go:518
 #, c-format
 msgid "Storage pool %s created"
 msgstr ""
 
-#: lxc/storage.go:555
+#: lxc/storage.go:577
 #, c-format
 msgid "Storage pool %s deleted"
 msgstr ""
@@ -1139,12 +1143,12 @@ msgstr ""
 msgid "Storage pool name"
 msgstr ""
 
-#: lxc/storage.go:826
+#: lxc/storage.go:852
 #, c-format
 msgid "Storage volume %s created"
 msgstr ""
 
-#: lxc/storage.go:841
+#: lxc/storage.go:867
 #, c-format
 msgid "Storage volume %s deleted"
 msgstr ""
@@ -1161,7 +1165,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:791
+#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:817
 msgid "TYPE"
 msgstr ""
 
@@ -1197,7 +1201,7 @@ msgstr ""
 msgid "The opposite of \"lxc pause\" is \"lxc start\"."
 msgstr ""
 
-#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:416 lxc/storage.go:536
+#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:438 lxc/storage.go:558
 msgid "The specified device doesn't exist"
 msgstr ""
 
@@ -1276,7 +1280,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:685 lxc/storage.go:794
+#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:707 lxc/storage.go:820
 msgid "USED BY"
 msgstr ""
 
@@ -2035,7 +2039,7 @@ msgid ""
 "    Create a snapshot of \"u1\" called \"snap0\"."
 msgstr ""
 
-#: lxc/storage.go:64
+#: lxc/storage.go:65
 msgid ""
 "Usage: lxc storage <subcommand> [options]\n"
 "\n"
@@ -2110,7 +2114,14 @@ msgid ""
 "\n"
 "lxc storage volume detach-profile [<remote:>]<pool> <volume> <profile> "
 "[device name]\n"
-"    Detach a storage volume from the specified profile.\n"
+"\tDetach a storage volume from the specified profile.\n"
+"\n"
+"lxc storage volume copy [<pool>/]<volume> [<pool>/]<volume> [--config|-c "
+"<key=value>...]\n"
+"    Copy an existing volume to a new volume at the specified pool.\n"
+"\n"
+"lxc storage volume move [<pool>/]<volume> [<pool>/]<volume>\n"
+"    Move an existing volume to the specified pool.\n"
 "\n"
 "Unless specified through a prefix, all volume operations affect \"custom"
 "\" (user created) volumes.\n"
diff --git a/po/fi.po b/po/fi.po
index d6167f5f4..e0c0cd531 100644
--- a/po/fi.po
+++ b/po/fi.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: lxd\n"
 "Report-Msgid-Bugs-To: lxc-devel at lists.linuxcontainers.org\n"
-"POT-Creation-Date: 2018-01-11 17:16-0500\n"
+"POT-Creation-Date: 2018-01-16 11:17+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -16,7 +16,7 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: lxc/storage.go:33
+#: lxc/storage.go:34
 msgid ""
 "### This is a yaml representation of a storage pool.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -33,7 +33,7 @@ msgid ""
 "###   zfs.pool_name: default"
 msgstr ""
 
-#: lxc/storage.go:50
+#: lxc/storage.go:51
 msgid ""
 "### This is a yaml representation of a storage volume.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -288,7 +288,7 @@ msgstr ""
 msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
 
-#: lxc/profile.go:546 lxc/storage.go:653
+#: lxc/profile.go:546 lxc/storage.go:675
 msgid "Cannot provide container name to list"
 msgstr ""
 
@@ -313,8 +313,12 @@ msgstr ""
 msgid "Config key/value to apply to the new container"
 msgstr ""
 
+#: lxc/storage.go:158
+msgid "Config key/value to apply to the new storage volume"
+msgstr ""
+
 #: lxc/config.go:816 lxc/config.go:881 lxc/config.go:1331 lxc/image.go:1190
-#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:604 lxc/storage.go:979
+#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:626 lxc/storage.go:1058
 #, c-format
 msgid "Config parsing error: %s"
 msgstr ""
@@ -381,11 +385,11 @@ msgid "Creating the container"
 msgstr ""
 
 #: lxc/image.go:234 lxc/image.go:1137 lxc/list.go:465 lxc/network.go:525
-#: lxc/storage.go:682 lxc/storage.go:793
+#: lxc/storage.go:704 lxc/storage.go:819
 msgid "DESCRIPTION"
 msgstr ""
 
-#: lxc/storage.go:683
+#: lxc/storage.go:705
 msgid "DRIVER"
 msgstr ""
 
@@ -698,7 +702,7 @@ msgstr ""
 msgid "Missing summary."
 msgstr ""
 
-#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:402 lxc/storage.go:522
+#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:424 lxc/storage.go:544
 msgid "More than one device matches, specify the device name."
 msgstr ""
 
@@ -719,7 +723,7 @@ msgid "Must supply container name for: "
 msgstr ""
 
 #: lxc/list.go:467 lxc/network.go:522 lxc/profile.go:573 lxc/remote.go:409
-#: lxc/storage.go:681 lxc/storage.go:792
+#: lxc/storage.go:703 lxc/storage.go:818
 msgid "NAME"
 msgstr ""
 
@@ -767,7 +771,7 @@ msgstr ""
 msgid "No device found for this network"
 msgstr ""
 
-#: lxc/storage.go:411 lxc/storage.go:531
+#: lxc/storage.go:433 lxc/storage.go:553
 msgid "No device found for this storage volume."
 msgstr ""
 
@@ -775,7 +779,7 @@ msgstr ""
 msgid "No fingerprint specified."
 msgstr ""
 
-#: lxc/storage.go:355 lxc/storage.go:448
+#: lxc/storage.go:377 lxc/storage.go:470
 msgid "Only \"custom\" volumes can be attached to containers."
 msgstr ""
 
@@ -857,7 +861,7 @@ msgstr ""
 msgid "Pid: %d"
 msgstr ""
 
-#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:605 lxc/storage.go:980
+#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:627 lxc/storage.go:1059
 msgid "Press enter to open the editor again"
 msgstr ""
 
@@ -966,7 +970,7 @@ msgstr ""
 msgid "Remove %s (yes/no): "
 msgstr ""
 
-#: lxc/storage.go:1011
+#: lxc/storage.go:1090
 #, c-format
 msgid "Renamed storage volume from \"%s\" to \"%s\""
 msgstr ""
@@ -1004,7 +1008,7 @@ msgstr ""
 msgid "SNAPSHOTS"
 msgstr ""
 
-#: lxc/storage.go:684
+#: lxc/storage.go:706
 msgid "SOURCE"
 msgstr ""
 
@@ -1072,7 +1076,7 @@ msgstr ""
 msgid "Show the resources available to the server"
 msgstr ""
 
-#: lxc/storage.go:151
+#: lxc/storage.go:159
 msgid "Show the resources available to the storage pool"
 msgstr ""
 
@@ -1125,12 +1129,12 @@ msgstr ""
 msgid "Stopping the container failed: %s"
 msgstr ""
 
-#: lxc/storage.go:496
+#: lxc/storage.go:518
 #, c-format
 msgid "Storage pool %s created"
 msgstr ""
 
-#: lxc/storage.go:555
+#: lxc/storage.go:577
 #, c-format
 msgid "Storage pool %s deleted"
 msgstr ""
@@ -1139,12 +1143,12 @@ msgstr ""
 msgid "Storage pool name"
 msgstr ""
 
-#: lxc/storage.go:826
+#: lxc/storage.go:852
 #, c-format
 msgid "Storage volume %s created"
 msgstr ""
 
-#: lxc/storage.go:841
+#: lxc/storage.go:867
 #, c-format
 msgid "Storage volume %s deleted"
 msgstr ""
@@ -1161,7 +1165,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:791
+#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:817
 msgid "TYPE"
 msgstr ""
 
@@ -1197,7 +1201,7 @@ msgstr ""
 msgid "The opposite of \"lxc pause\" is \"lxc start\"."
 msgstr ""
 
-#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:416 lxc/storage.go:536
+#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:438 lxc/storage.go:558
 msgid "The specified device doesn't exist"
 msgstr ""
 
@@ -1276,7 +1280,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:685 lxc/storage.go:794
+#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:707 lxc/storage.go:820
 msgid "USED BY"
 msgstr ""
 
@@ -2035,7 +2039,7 @@ msgid ""
 "    Create a snapshot of \"u1\" called \"snap0\"."
 msgstr ""
 
-#: lxc/storage.go:64
+#: lxc/storage.go:65
 msgid ""
 "Usage: lxc storage <subcommand> [options]\n"
 "\n"
@@ -2110,7 +2114,14 @@ msgid ""
 "\n"
 "lxc storage volume detach-profile [<remote:>]<pool> <volume> <profile> "
 "[device name]\n"
-"    Detach a storage volume from the specified profile.\n"
+"\tDetach a storage volume from the specified profile.\n"
+"\n"
+"lxc storage volume copy [<pool>/]<volume> [<pool>/]<volume> [--config|-c "
+"<key=value>...]\n"
+"    Copy an existing volume to a new volume at the specified pool.\n"
+"\n"
+"lxc storage volume move [<pool>/]<volume> [<pool>/]<volume>\n"
+"    Move an existing volume to the specified pool.\n"
 "\n"
 "Unless specified through a prefix, all volume operations affect \"custom"
 "\" (user created) volumes.\n"
diff --git a/po/fr.po b/po/fr.po
index e38fd1091..1c026d3de 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: LXD\n"
 "Report-Msgid-Bugs-To: lxc-devel at lists.linuxcontainers.org\n"
-"POT-Creation-Date: 2018-01-11 17:16-0500\n"
+"POT-Creation-Date: 2018-01-16 11:17+0100\n"
 "PO-Revision-Date: 2018-01-02 10:52+0000\n"
 "Last-Translator: Bruno Perel <brunoperel at gmail.com>\n"
 "Language-Team: French <https://hosted.weblate.org/projects/linux-containers/"
@@ -19,7 +19,7 @@ msgstr ""
 "Plural-Forms: nplurals=2; plural=n > 1;\n"
 "X-Generator: Weblate 2.19-dev\n"
 
-#: lxc/storage.go:33
+#: lxc/storage.go:34
 msgid ""
 "### This is a yaml representation of a storage pool.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -50,7 +50,7 @@ msgstr ""
 "###   source: /home/chb/mnt/lxd_test/default.img\n"
 "###   zfs.pool_name: default"
 
-#: lxc/storage.go:50
+#: lxc/storage.go:51
 #, fuzzy
 msgid ""
 "### This is a yaml representation of a storage volume.\n"
@@ -392,7 +392,7 @@ msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
 "Impossible de désaffecter la clé '%s', elle n'est pas définie actuellement."
 
-#: lxc/profile.go:546 lxc/storage.go:653
+#: lxc/profile.go:546 lxc/storage.go:675
 msgid "Cannot provide container name to list"
 msgstr "Impossible de fournir le nom du conteneur à lister"
 
@@ -417,8 +417,13 @@ msgstr "Commandes :"
 msgid "Config key/value to apply to the new container"
 msgstr "Clé/valeur de configuration à appliquer au nouveau conteneur"
 
+#: lxc/storage.go:158
+#, fuzzy
+msgid "Config key/value to apply to the new storage volume"
+msgstr "Clé/valeur de configuration à appliquer au nouveau conteneur"
+
 #: lxc/config.go:816 lxc/config.go:881 lxc/config.go:1331 lxc/image.go:1190
-#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:604 lxc/storage.go:979
+#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:626 lxc/storage.go:1058
 #, c-format
 msgid "Config parsing error: %s"
 msgstr "Erreur lors de la lecture de la configuration : %s"
@@ -486,11 +491,11 @@ msgid "Creating the container"
 msgstr "Création du conteneur"
 
 #: lxc/image.go:234 lxc/image.go:1137 lxc/list.go:465 lxc/network.go:525
-#: lxc/storage.go:682 lxc/storage.go:793
+#: lxc/storage.go:704 lxc/storage.go:819
 msgid "DESCRIPTION"
 msgstr "DESCRIPTION"
 
-#: lxc/storage.go:683
+#: lxc/storage.go:705
 msgid "DRIVER"
 msgstr "PILOTE"
 
@@ -815,7 +820,7 @@ msgstr "  Mémoire utilisée :"
 msgid "Missing summary."
 msgstr "Résumé manquant."
 
-#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:402 lxc/storage.go:522
+#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:424 lxc/storage.go:544
 msgid "More than one device matches, specify the device name."
 msgstr "Plus d'un périphérique correspond, spécifier le nom du périphérique."
 
@@ -838,7 +843,7 @@ msgid "Must supply container name for: "
 msgstr "Vous devez fournir le nom d'un conteneur pour : "
 
 #: lxc/list.go:467 lxc/network.go:522 lxc/profile.go:573 lxc/remote.go:409
-#: lxc/storage.go:681 lxc/storage.go:792
+#: lxc/storage.go:703 lxc/storage.go:818
 msgid "NAME"
 msgstr "NOM"
 
@@ -887,7 +892,7 @@ msgstr "Un certificat à ajouter n'a pas été fourni"
 msgid "No device found for this network"
 msgstr "Aucun périphérique existant pour ce réseau"
 
-#: lxc/storage.go:411 lxc/storage.go:531
+#: lxc/storage.go:433 lxc/storage.go:553
 #, fuzzy
 msgid "No device found for this storage volume."
 msgstr "Aucun périphérique existant pour ce réseau"
@@ -896,7 +901,7 @@ msgstr "Aucun périphérique existant pour ce réseau"
 msgid "No fingerprint specified."
 msgstr "Aucune empreinte n'a été indiquée."
 
-#: lxc/storage.go:355 lxc/storage.go:448
+#: lxc/storage.go:377 lxc/storage.go:470
 msgid "Only \"custom\" volumes can be attached to containers."
 msgstr ""
 "Seuls les volumes \"personnalisés\" peuvent être attachés aux conteneurs."
@@ -980,7 +985,7 @@ msgstr "Permission refusée, êtes-vous dans le groupe lxd ?"
 msgid "Pid: %d"
 msgstr "Pid : %d"
 
-#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:605 lxc/storage.go:980
+#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:627 lxc/storage.go:1059
 msgid "Press enter to open the editor again"
 msgstr "Appuyer sur Entrée pour ouvrir à nouveau l'éditeur"
 
@@ -1090,7 +1095,7 @@ msgstr "Serveur distant : %s"
 msgid "Remove %s (yes/no): "
 msgstr "Supprimer %s (oui/non) : "
 
-#: lxc/storage.go:1011
+#: lxc/storage.go:1090
 #, c-format
 msgid "Renamed storage volume from \"%s\" to \"%s\""
 msgstr ""
@@ -1130,7 +1135,7 @@ msgstr "TAILLE"
 msgid "SNAPSHOTS"
 msgstr "INSTANTANÉS"
 
-#: lxc/storage.go:684
+#: lxc/storage.go:706
 msgid "SOURCE"
 msgstr "SOURCE"
 
@@ -1201,7 +1206,7 @@ msgstr "Afficher la configuration étendue"
 msgid "Show the resources available to the server"
 msgstr ""
 
-#: lxc/storage.go:151
+#: lxc/storage.go:159
 msgid "Show the resources available to the storage pool"
 msgstr ""
 
@@ -1256,12 +1261,12 @@ msgstr "L'arrêt du conteneur a échoué !"
 msgid "Stopping the container failed: %s"
 msgstr "L'arrêt du conteneur a échoué !"
 
-#: lxc/storage.go:496
+#: lxc/storage.go:518
 #, fuzzy, c-format
 msgid "Storage pool %s created"
 msgstr "Le réseau %s a été créé"
 
-#: lxc/storage.go:555
+#: lxc/storage.go:577
 #, fuzzy, c-format
 msgid "Storage pool %s deleted"
 msgstr "Le réseau %s a été supprimé"
@@ -1270,12 +1275,12 @@ msgstr "Le réseau %s a été supprimé"
 msgid "Storage pool name"
 msgstr "Nom de l'ensemble de stockage"
 
-#: lxc/storage.go:826
+#: lxc/storage.go:852
 #, fuzzy, c-format
 msgid "Storage volume %s created"
 msgstr "Profil %s créé"
 
-#: lxc/storage.go:841
+#: lxc/storage.go:867
 #, fuzzy, c-format
 msgid "Storage volume %s deleted"
 msgstr "Profil %s supprimé"
@@ -1292,7 +1297,7 @@ msgstr "Swap (courant)"
 msgid "Swap (peak)"
 msgstr "Swap (pointe)"
 
-#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:791
+#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:817
 msgid "TYPE"
 msgstr "TYPE"
 
@@ -1334,7 +1339,7 @@ msgstr "L'image locale '%s' n'a pas été trouvée, essayer '%s:' à la place."
 msgid "The opposite of \"lxc pause\" is \"lxc start\"."
 msgstr "Le pendant de `lxc pause` est `lxc start`."
 
-#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:416 lxc/storage.go:536
+#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:438 lxc/storage.go:558
 msgid "The specified device doesn't exist"
 msgstr "Le périphérique indiqué n'existe pas"
 
@@ -1419,7 +1424,7 @@ msgstr "DATE DE PUBLICATION"
 msgid "URL"
 msgstr "URL"
 
-#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:685 lxc/storage.go:794
+#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:707 lxc/storage.go:820
 msgid "USED BY"
 msgstr "UTILISÉ PAR"
 
@@ -2635,7 +2640,7 @@ msgstr ""
 "Exemple :\n"
 "    lxc snapshot u1 snap0"
 
-#: lxc/storage.go:64
+#: lxc/storage.go:65
 msgid ""
 "Usage: lxc storage <subcommand> [options]\n"
 "\n"
@@ -2710,7 +2715,14 @@ msgid ""
 "\n"
 "lxc storage volume detach-profile [<remote:>]<pool> <volume> <profile> "
 "[device name]\n"
-"    Detach a storage volume from the specified profile.\n"
+"\tDetach a storage volume from the specified profile.\n"
+"\n"
+"lxc storage volume copy [<pool>/]<volume> [<pool>/]<volume> [--config|-c "
+"<key=value>...]\n"
+"    Copy an existing volume to a new volume at the specified pool.\n"
+"\n"
+"lxc storage volume move [<pool>/]<volume> [<pool>/]<volume>\n"
+"    Move an existing volume to the specified pool.\n"
 "\n"
 "Unless specified through a prefix, all volume operations affect \"custom"
 "\" (user created) volumes.\n"
diff --git a/po/id.po b/po/id.po
index b7583208a..4857a6ea0 100644
--- a/po/id.po
+++ b/po/id.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: lxd\n"
 "Report-Msgid-Bugs-To: lxc-devel at lists.linuxcontainers.org\n"
-"POT-Creation-Date: 2018-01-11 17:16-0500\n"
+"POT-Creation-Date: 2018-01-16 11:17+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -16,7 +16,7 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: lxc/storage.go:33
+#: lxc/storage.go:34
 msgid ""
 "### This is a yaml representation of a storage pool.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -33,7 +33,7 @@ msgid ""
 "###   zfs.pool_name: default"
 msgstr ""
 
-#: lxc/storage.go:50
+#: lxc/storage.go:51
 msgid ""
 "### This is a yaml representation of a storage volume.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -288,7 +288,7 @@ msgstr ""
 msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
 
-#: lxc/profile.go:546 lxc/storage.go:653
+#: lxc/profile.go:546 lxc/storage.go:675
 msgid "Cannot provide container name to list"
 msgstr ""
 
@@ -313,8 +313,12 @@ msgstr ""
 msgid "Config key/value to apply to the new container"
 msgstr ""
 
+#: lxc/storage.go:158
+msgid "Config key/value to apply to the new storage volume"
+msgstr ""
+
 #: lxc/config.go:816 lxc/config.go:881 lxc/config.go:1331 lxc/image.go:1190
-#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:604 lxc/storage.go:979
+#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:626 lxc/storage.go:1058
 #, c-format
 msgid "Config parsing error: %s"
 msgstr ""
@@ -381,11 +385,11 @@ msgid "Creating the container"
 msgstr ""
 
 #: lxc/image.go:234 lxc/image.go:1137 lxc/list.go:465 lxc/network.go:525
-#: lxc/storage.go:682 lxc/storage.go:793
+#: lxc/storage.go:704 lxc/storage.go:819
 msgid "DESCRIPTION"
 msgstr ""
 
-#: lxc/storage.go:683
+#: lxc/storage.go:705
 msgid "DRIVER"
 msgstr ""
 
@@ -698,7 +702,7 @@ msgstr ""
 msgid "Missing summary."
 msgstr ""
 
-#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:402 lxc/storage.go:522
+#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:424 lxc/storage.go:544
 msgid "More than one device matches, specify the device name."
 msgstr ""
 
@@ -719,7 +723,7 @@ msgid "Must supply container name for: "
 msgstr ""
 
 #: lxc/list.go:467 lxc/network.go:522 lxc/profile.go:573 lxc/remote.go:409
-#: lxc/storage.go:681 lxc/storage.go:792
+#: lxc/storage.go:703 lxc/storage.go:818
 msgid "NAME"
 msgstr ""
 
@@ -767,7 +771,7 @@ msgstr ""
 msgid "No device found for this network"
 msgstr ""
 
-#: lxc/storage.go:411 lxc/storage.go:531
+#: lxc/storage.go:433 lxc/storage.go:553
 msgid "No device found for this storage volume."
 msgstr ""
 
@@ -775,7 +779,7 @@ msgstr ""
 msgid "No fingerprint specified."
 msgstr ""
 
-#: lxc/storage.go:355 lxc/storage.go:448
+#: lxc/storage.go:377 lxc/storage.go:470
 msgid "Only \"custom\" volumes can be attached to containers."
 msgstr ""
 
@@ -857,7 +861,7 @@ msgstr ""
 msgid "Pid: %d"
 msgstr ""
 
-#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:605 lxc/storage.go:980
+#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:627 lxc/storage.go:1059
 msgid "Press enter to open the editor again"
 msgstr ""
 
@@ -966,7 +970,7 @@ msgstr ""
 msgid "Remove %s (yes/no): "
 msgstr ""
 
-#: lxc/storage.go:1011
+#: lxc/storage.go:1090
 #, c-format
 msgid "Renamed storage volume from \"%s\" to \"%s\""
 msgstr ""
@@ -1004,7 +1008,7 @@ msgstr ""
 msgid "SNAPSHOTS"
 msgstr ""
 
-#: lxc/storage.go:684
+#: lxc/storage.go:706
 msgid "SOURCE"
 msgstr ""
 
@@ -1072,7 +1076,7 @@ msgstr ""
 msgid "Show the resources available to the server"
 msgstr ""
 
-#: lxc/storage.go:151
+#: lxc/storage.go:159
 msgid "Show the resources available to the storage pool"
 msgstr ""
 
@@ -1125,12 +1129,12 @@ msgstr ""
 msgid "Stopping the container failed: %s"
 msgstr ""
 
-#: lxc/storage.go:496
+#: lxc/storage.go:518
 #, c-format
 msgid "Storage pool %s created"
 msgstr ""
 
-#: lxc/storage.go:555
+#: lxc/storage.go:577
 #, c-format
 msgid "Storage pool %s deleted"
 msgstr ""
@@ -1139,12 +1143,12 @@ msgstr ""
 msgid "Storage pool name"
 msgstr ""
 
-#: lxc/storage.go:826
+#: lxc/storage.go:852
 #, c-format
 msgid "Storage volume %s created"
 msgstr ""
 
-#: lxc/storage.go:841
+#: lxc/storage.go:867
 #, c-format
 msgid "Storage volume %s deleted"
 msgstr ""
@@ -1161,7 +1165,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:791
+#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:817
 msgid "TYPE"
 msgstr ""
 
@@ -1197,7 +1201,7 @@ msgstr ""
 msgid "The opposite of \"lxc pause\" is \"lxc start\"."
 msgstr ""
 
-#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:416 lxc/storage.go:536
+#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:438 lxc/storage.go:558
 msgid "The specified device doesn't exist"
 msgstr ""
 
@@ -1276,7 +1280,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:685 lxc/storage.go:794
+#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:707 lxc/storage.go:820
 msgid "USED BY"
 msgstr ""
 
@@ -2035,7 +2039,7 @@ msgid ""
 "    Create a snapshot of \"u1\" called \"snap0\"."
 msgstr ""
 
-#: lxc/storage.go:64
+#: lxc/storage.go:65
 msgid ""
 "Usage: lxc storage <subcommand> [options]\n"
 "\n"
@@ -2110,7 +2114,14 @@ msgid ""
 "\n"
 "lxc storage volume detach-profile [<remote:>]<pool> <volume> <profile> "
 "[device name]\n"
-"    Detach a storage volume from the specified profile.\n"
+"\tDetach a storage volume from the specified profile.\n"
+"\n"
+"lxc storage volume copy [<pool>/]<volume> [<pool>/]<volume> [--config|-c "
+"<key=value>...]\n"
+"    Copy an existing volume to a new volume at the specified pool.\n"
+"\n"
+"lxc storage volume move [<pool>/]<volume> [<pool>/]<volume>\n"
+"    Move an existing volume to the specified pool.\n"
 "\n"
 "Unless specified through a prefix, all volume operations affect \"custom"
 "\" (user created) volumes.\n"
diff --git a/po/it.po b/po/it.po
index f92d967e0..0cdc30769 100644
--- a/po/it.po
+++ b/po/it.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: lxd\n"
 "Report-Msgid-Bugs-To: lxc-devel at lists.linuxcontainers.org\n"
-"POT-Creation-Date: 2018-01-11 17:16-0500\n"
+"POT-Creation-Date: 2018-01-16 11:17+0100\n"
 "PO-Revision-Date: 2017-08-18 14:22+0000\n"
 "Last-Translator: Alberto Donato <alberto.donato at gmail.com>\n"
 "Language-Team: Italian <https://hosted.weblate.org/projects/linux-containers/"
@@ -19,7 +19,7 @@ msgstr ""
 "Plural-Forms: nplurals=2; plural=n != 1;\n"
 "X-Generator: Weblate 2.17-dev\n"
 
-#: lxc/storage.go:33
+#: lxc/storage.go:34
 msgid ""
 "### This is a yaml representation of a storage pool.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -50,7 +50,7 @@ msgstr ""
 "###   source: /home/chb/mnt/lxd_test/default.img\n"
 "###   zfs.pool_name: default"
 
-#: lxc/storage.go:50
+#: lxc/storage.go:51
 msgid ""
 "### This is a yaml representation of a storage volume.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -313,7 +313,7 @@ msgstr ""
 msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
 
-#: lxc/profile.go:546 lxc/storage.go:653
+#: lxc/profile.go:546 lxc/storage.go:675
 msgid "Cannot provide container name to list"
 msgstr ""
 
@@ -338,8 +338,12 @@ msgstr "Comandi:"
 msgid "Config key/value to apply to the new container"
 msgstr ""
 
+#: lxc/storage.go:158
+msgid "Config key/value to apply to the new storage volume"
+msgstr ""
+
 #: lxc/config.go:816 lxc/config.go:881 lxc/config.go:1331 lxc/image.go:1190
-#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:604 lxc/storage.go:979
+#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:626 lxc/storage.go:1058
 #, c-format
 msgid "Config parsing error: %s"
 msgstr ""
@@ -406,11 +410,11 @@ msgid "Creating the container"
 msgstr "Creazione del container in corso"
 
 #: lxc/image.go:234 lxc/image.go:1137 lxc/list.go:465 lxc/network.go:525
-#: lxc/storage.go:682 lxc/storage.go:793
+#: lxc/storage.go:704 lxc/storage.go:819
 msgid "DESCRIPTION"
 msgstr "DESCRIZIONE"
 
-#: lxc/storage.go:683
+#: lxc/storage.go:705
 msgid "DRIVER"
 msgstr "DRIVER"
 
@@ -724,7 +728,7 @@ msgstr ""
 msgid "Missing summary."
 msgstr ""
 
-#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:402 lxc/storage.go:522
+#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:424 lxc/storage.go:544
 msgid "More than one device matches, specify the device name."
 msgstr ""
 
@@ -745,7 +749,7 @@ msgid "Must supply container name for: "
 msgstr ""
 
 #: lxc/list.go:467 lxc/network.go:522 lxc/profile.go:573 lxc/remote.go:409
-#: lxc/storage.go:681 lxc/storage.go:792
+#: lxc/storage.go:703 lxc/storage.go:818
 msgid "NAME"
 msgstr ""
 
@@ -793,7 +797,7 @@ msgstr ""
 msgid "No device found for this network"
 msgstr ""
 
-#: lxc/storage.go:411 lxc/storage.go:531
+#: lxc/storage.go:433 lxc/storage.go:553
 msgid "No device found for this storage volume."
 msgstr ""
 
@@ -801,7 +805,7 @@ msgstr ""
 msgid "No fingerprint specified."
 msgstr ""
 
-#: lxc/storage.go:355 lxc/storage.go:448
+#: lxc/storage.go:377 lxc/storage.go:470
 msgid "Only \"custom\" volumes can be attached to containers."
 msgstr ""
 
@@ -883,7 +887,7 @@ msgstr ""
 msgid "Pid: %d"
 msgstr ""
 
-#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:605 lxc/storage.go:980
+#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:627 lxc/storage.go:1059
 msgid "Press enter to open the editor again"
 msgstr ""
 
@@ -992,7 +996,7 @@ msgstr ""
 msgid "Remove %s (yes/no): "
 msgstr ""
 
-#: lxc/storage.go:1011
+#: lxc/storage.go:1090
 #, c-format
 msgid "Renamed storage volume from \"%s\" to \"%s\""
 msgstr ""
@@ -1030,7 +1034,7 @@ msgstr ""
 msgid "SNAPSHOTS"
 msgstr ""
 
-#: lxc/storage.go:684
+#: lxc/storage.go:706
 msgid "SOURCE"
 msgstr ""
 
@@ -1098,7 +1102,7 @@ msgstr ""
 msgid "Show the resources available to the server"
 msgstr ""
 
-#: lxc/storage.go:151
+#: lxc/storage.go:159
 msgid "Show the resources available to the storage pool"
 msgstr ""
 
@@ -1151,12 +1155,12 @@ msgstr ""
 msgid "Stopping the container failed: %s"
 msgstr ""
 
-#: lxc/storage.go:496
+#: lxc/storage.go:518
 #, c-format
 msgid "Storage pool %s created"
 msgstr ""
 
-#: lxc/storage.go:555
+#: lxc/storage.go:577
 #, c-format
 msgid "Storage pool %s deleted"
 msgstr ""
@@ -1165,12 +1169,12 @@ msgstr ""
 msgid "Storage pool name"
 msgstr ""
 
-#: lxc/storage.go:826
+#: lxc/storage.go:852
 #, c-format
 msgid "Storage volume %s created"
 msgstr ""
 
-#: lxc/storage.go:841
+#: lxc/storage.go:867
 #, c-format
 msgid "Storage volume %s deleted"
 msgstr ""
@@ -1187,7 +1191,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:791
+#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:817
 msgid "TYPE"
 msgstr ""
 
@@ -1223,7 +1227,7 @@ msgstr ""
 msgid "The opposite of \"lxc pause\" is \"lxc start\"."
 msgstr ""
 
-#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:416 lxc/storage.go:536
+#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:438 lxc/storage.go:558
 msgid "The specified device doesn't exist"
 msgstr ""
 
@@ -1302,7 +1306,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:685 lxc/storage.go:794
+#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:707 lxc/storage.go:820
 msgid "USED BY"
 msgstr ""
 
@@ -2061,7 +2065,7 @@ msgid ""
 "    Create a snapshot of \"u1\" called \"snap0\"."
 msgstr ""
 
-#: lxc/storage.go:64
+#: lxc/storage.go:65
 msgid ""
 "Usage: lxc storage <subcommand> [options]\n"
 "\n"
@@ -2136,7 +2140,14 @@ msgid ""
 "\n"
 "lxc storage volume detach-profile [<remote:>]<pool> <volume> <profile> "
 "[device name]\n"
-"    Detach a storage volume from the specified profile.\n"
+"\tDetach a storage volume from the specified profile.\n"
+"\n"
+"lxc storage volume copy [<pool>/]<volume> [<pool>/]<volume> [--config|-c "
+"<key=value>...]\n"
+"    Copy an existing volume to a new volume at the specified pool.\n"
+"\n"
+"lxc storage volume move [<pool>/]<volume> [<pool>/]<volume>\n"
+"    Move an existing volume to the specified pool.\n"
 "\n"
 "Unless specified through a prefix, all volume operations affect \"custom"
 "\" (user created) volumes.\n"
diff --git a/po/ja.po b/po/ja.po
index 31d2bafb5..84b0c992c 100644
--- a/po/ja.po
+++ b/po/ja.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: LXD\n"
 "Report-Msgid-Bugs-To: lxc-devel at lists.linuxcontainers.org\n"
-"POT-Creation-Date: 2018-01-11 17:16-0500\n"
+"POT-Creation-Date: 2018-01-16 11:17+0100\n"
 "PO-Revision-Date: 2018-01-02 10:52+0000\n"
 "Last-Translator: KATOH Yasufumi <karma at jazz.email.ne.jp>\n"
 "Language-Team: Japanese <https://hosted.weblate.org/projects/linux-"
@@ -19,7 +19,7 @@ msgstr ""
 "Plural-Forms: nplurals=1; plural=0;\n"
 "X-Generator: Weblate 2.19-dev\n"
 
-#: lxc/storage.go:33
+#: lxc/storage.go:34
 msgid ""
 "### This is a yaml representation of a storage pool.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -36,7 +36,7 @@ msgid ""
 "###   zfs.pool_name: default"
 msgstr ""
 
-#: lxc/storage.go:50
+#: lxc/storage.go:51
 msgid ""
 "### This is a yaml representation of a storage volume.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -293,7 +293,7 @@ msgstr "キー '%s' が設定されていないので削除できません"
 msgid "Can't unset key '%s', it's not currently set."
 msgstr "キー '%s' が指定されていないので削除できません。"
 
-#: lxc/profile.go:546 lxc/storage.go:653
+#: lxc/profile.go:546 lxc/storage.go:675
 msgid "Cannot provide container name to list"
 msgstr "コンテナ名を取得できません"
 
@@ -318,8 +318,13 @@ msgstr "コマンド:"
 msgid "Config key/value to apply to the new container"
 msgstr "新しいコンテナに適用するキー/値の設定"
 
+#: lxc/storage.go:158
+#, fuzzy
+msgid "Config key/value to apply to the new storage volume"
+msgstr "新しいコンテナに適用するキー/値の設定"
+
 #: lxc/config.go:816 lxc/config.go:881 lxc/config.go:1331 lxc/image.go:1190
-#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:604 lxc/storage.go:979
+#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:626 lxc/storage.go:1058
 #, c-format
 msgid "Config parsing error: %s"
 msgstr "設定の構文エラー: %s"
@@ -386,11 +391,11 @@ msgid "Creating the container"
 msgstr "コンテナを作成中"
 
 #: lxc/image.go:234 lxc/image.go:1137 lxc/list.go:465 lxc/network.go:525
-#: lxc/storage.go:682 lxc/storage.go:793
+#: lxc/storage.go:704 lxc/storage.go:819
 msgid "DESCRIPTION"
 msgstr ""
 
-#: lxc/storage.go:683
+#: lxc/storage.go:705
 msgid "DRIVER"
 msgstr ""
 
@@ -704,7 +709,7 @@ msgstr "メモリ消費量:"
 msgid "Missing summary."
 msgstr "サマリーはありません。"
 
-#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:402 lxc/storage.go:522
+#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:424 lxc/storage.go:544
 msgid "More than one device matches, specify the device name."
 msgstr "複数のデバイスとマッチします。デバイス名を指定してください。"
 
@@ -727,7 +732,7 @@ msgid "Must supply container name for: "
 msgstr "コンテナ名を指定する必要があります: "
 
 #: lxc/list.go:467 lxc/network.go:522 lxc/profile.go:573 lxc/remote.go:409
-#: lxc/storage.go:681 lxc/storage.go:792
+#: lxc/storage.go:703 lxc/storage.go:818
 msgid "NAME"
 msgstr ""
 
@@ -775,7 +780,7 @@ msgstr "追加すべき証明書が提供されていません"
 msgid "No device found for this network"
 msgstr "このネットワークに対するデバイスがありません"
 
-#: lxc/storage.go:411 lxc/storage.go:531
+#: lxc/storage.go:433 lxc/storage.go:553
 msgid "No device found for this storage volume."
 msgstr "このストレージボリュームに対するデバイスがありません。"
 
@@ -783,7 +788,7 @@ msgstr "このストレージボリュームに対するデバイスがありま
 msgid "No fingerprint specified."
 msgstr "フィンガープリントが指定されていません。"
 
-#: lxc/storage.go:355 lxc/storage.go:448
+#: lxc/storage.go:377 lxc/storage.go:470
 msgid "Only \"custom\" volumes can be attached to containers."
 msgstr "\"カスタム\" のボリュームのみがコンテナにアタッチできます。"
 
@@ -865,7 +870,7 @@ msgstr "アクセスが拒否されました。lxd グループに所属して
 msgid "Pid: %d"
 msgstr "Pid: %d"
 
-#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:605 lxc/storage.go:980
+#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:627 lxc/storage.go:1059
 msgid "Press enter to open the editor again"
 msgstr "再度エディタを開くためには Enter キーを押します"
 
@@ -974,7 +979,7 @@ msgstr "リモート名: %s"
 msgid "Remove %s (yes/no): "
 msgstr "%s を消去しますか (yes/no): "
 
-#: lxc/storage.go:1011
+#: lxc/storage.go:1090
 #, c-format
 msgid "Renamed storage volume from \"%s\" to \"%s\""
 msgstr "ストレージボリューム名 \"%s\" を \"%s\" に変更しました"
@@ -1012,7 +1017,7 @@ msgstr ""
 msgid "SNAPSHOTS"
 msgstr ""
 
-#: lxc/storage.go:684
+#: lxc/storage.go:706
 msgid "SOURCE"
 msgstr ""
 
@@ -1080,7 +1085,7 @@ msgstr "拡張した設定を表示する"
 msgid "Show the resources available to the server"
 msgstr "サーバで使用可能なリソースを表示します"
 
-#: lxc/storage.go:151
+#: lxc/storage.go:159
 msgid "Show the resources available to the storage pool"
 msgstr "ストレージプールで利用可能なリソースを表示します"
 
@@ -1133,12 +1138,12 @@ msgstr "コンテナの停止に失敗しました!"
 msgid "Stopping the container failed: %s"
 msgstr "コンテナの停止に失敗しました: %s"
 
-#: lxc/storage.go:496
+#: lxc/storage.go:518
 #, c-format
 msgid "Storage pool %s created"
 msgstr "ストレージプール %s を作成しました"
 
-#: lxc/storage.go:555
+#: lxc/storage.go:577
 #, c-format
 msgid "Storage pool %s deleted"
 msgstr "ストレージプール %s を削除しました"
@@ -1147,12 +1152,12 @@ msgstr "ストレージプール %s を削除しました"
 msgid "Storage pool name"
 msgstr "ストレージプール名"
 
-#: lxc/storage.go:826
+#: lxc/storage.go:852
 #, c-format
 msgid "Storage volume %s created"
 msgstr "ストレージボリューム %s を作成しました"
 
-#: lxc/storage.go:841
+#: lxc/storage.go:867
 #, c-format
 msgid "Storage volume %s deleted"
 msgstr "ストレージボリューム %s を削除しました"
@@ -1169,7 +1174,7 @@ msgstr "Swap (現在値)"
 msgid "Swap (peak)"
 msgstr "Swap (ピーク)"
 
-#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:791
+#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:817
 msgid "TYPE"
 msgstr ""
 
@@ -1208,7 +1213,7 @@ msgstr ""
 msgid "The opposite of \"lxc pause\" is \"lxc start\"."
 msgstr "\"lxc pause\" の反対のコマンドは \"lxc start\" です。"
 
-#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:416 lxc/storage.go:536
+#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:438 lxc/storage.go:558
 msgid "The specified device doesn't exist"
 msgstr "指定したデバイスが存在しません"
 
@@ -1297,7 +1302,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:685 lxc/storage.go:794
+#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:707 lxc/storage.go:820
 msgid "USED BY"
 msgstr ""
 
@@ -2685,7 +2690,7 @@ msgstr ""
 "lxc snapshot u1 snap0\n"
 "    \"u1\" のスナップショットを \"snap0\" という名前で作成します。"
 
-#: lxc/storage.go:64
+#: lxc/storage.go:65
 #, fuzzy
 msgid ""
 "Usage: lxc storage <subcommand> [options]\n"
@@ -2761,7 +2766,14 @@ msgid ""
 "\n"
 "lxc storage volume detach-profile [<remote:>]<pool> <volume> <profile> "
 "[device name]\n"
-"    Detach a storage volume from the specified profile.\n"
+"\tDetach a storage volume from the specified profile.\n"
+"\n"
+"lxc storage volume copy [<pool>/]<volume> [<pool>/]<volume> [--config|-c "
+"<key=value>...]\n"
+"    Copy an existing volume to a new volume at the specified pool.\n"
+"\n"
+"lxc storage volume move [<pool>/]<volume> [<pool>/]<volume>\n"
+"    Move an existing volume to the specified pool.\n"
 "\n"
 "Unless specified through a prefix, all volume operations affect \"custom"
 "\" (user created) volumes.\n"
diff --git a/po/lxd.pot b/po/lxd.pot
index 30bd65ad6..65f811777 100644
--- a/po/lxd.pot
+++ b/po/lxd.pot
@@ -7,7 +7,7 @@
 msgid   ""
 msgstr  "Project-Id-Version: lxd\n"
         "Report-Msgid-Bugs-To: lxc-devel at lists.linuxcontainers.org\n"
-        "POT-Creation-Date: 2018-01-11 17:16-0500\n"
+        "POT-Creation-Date: 2018-01-16 11:17+0100\n"
         "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
         "Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
         "Language-Team: LANGUAGE <LL at li.org>\n"
@@ -16,7 +16,7 @@ msgstr  "Project-Id-Version: lxd\n"
         "Content-Type: text/plain; charset=CHARSET\n"
         "Content-Transfer-Encoding: 8bit\n"
 
-#: lxc/storage.go:33
+#: lxc/storage.go:34
 msgid   "### This is a yaml representation of a storage pool.\n"
         "### Any line starting with a '# will be ignored.\n"
         "###\n"
@@ -32,7 +32,7 @@ msgid   "### This is a yaml representation of a storage pool.\n"
         "###   zfs.pool_name: default"
 msgstr  ""
 
-#: lxc/storage.go:50
+#: lxc/storage.go:51
 msgid   "### This is a yaml representation of a storage volume.\n"
         "### Any line starting with a '# will be ignored.\n"
         "###\n"
@@ -281,7 +281,7 @@ msgstr  ""
 msgid   "Can't unset key '%s', it's not currently set."
 msgstr  ""
 
-#: lxc/profile.go:546 lxc/storage.go:653
+#: lxc/profile.go:546 lxc/storage.go:675
 msgid   "Cannot provide container name to list"
 msgstr  ""
 
@@ -306,7 +306,11 @@ msgstr  ""
 msgid   "Config key/value to apply to the new container"
 msgstr  ""
 
-#: lxc/config.go:816 lxc/config.go:881 lxc/config.go:1331 lxc/image.go:1190 lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:604 lxc/storage.go:979
+#: lxc/storage.go:158
+msgid   "Config key/value to apply to the new storage volume"
+msgstr  ""
+
+#: lxc/config.go:816 lxc/config.go:881 lxc/config.go:1331 lxc/image.go:1190 lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:626 lxc/storage.go:1058
 #, c-format
 msgid   "Config parsing error: %s"
 msgstr  ""
@@ -372,11 +376,11 @@ msgstr  ""
 msgid   "Creating the container"
 msgstr  ""
 
-#: lxc/image.go:234 lxc/image.go:1137 lxc/list.go:465 lxc/network.go:525 lxc/storage.go:682 lxc/storage.go:793
+#: lxc/image.go:234 lxc/image.go:1137 lxc/list.go:465 lxc/network.go:525 lxc/storage.go:704 lxc/storage.go:819
 msgid   "DESCRIPTION"
 msgstr  ""
 
-#: lxc/storage.go:683
+#: lxc/storage.go:705
 msgid   "DRIVER"
 msgstr  ""
 
@@ -687,7 +691,7 @@ msgstr  ""
 msgid   "Missing summary."
 msgstr  ""
 
-#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:402 lxc/storage.go:522
+#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:424 lxc/storage.go:544
 msgid   "More than one device matches, specify the device name."
 msgstr  ""
 
@@ -707,7 +711,7 @@ msgstr  ""
 msgid   "Must supply container name for: "
 msgstr  ""
 
-#: lxc/list.go:467 lxc/network.go:522 lxc/profile.go:573 lxc/remote.go:409 lxc/storage.go:681 lxc/storage.go:792
+#: lxc/list.go:467 lxc/network.go:522 lxc/profile.go:573 lxc/remote.go:409 lxc/storage.go:703 lxc/storage.go:818
 msgid   "NAME"
 msgstr  ""
 
@@ -755,7 +759,7 @@ msgstr  ""
 msgid   "No device found for this network"
 msgstr  ""
 
-#: lxc/storage.go:411 lxc/storage.go:531
+#: lxc/storage.go:433 lxc/storage.go:553
 msgid   "No device found for this storage volume."
 msgstr  ""
 
@@ -763,7 +767,7 @@ msgstr  ""
 msgid   "No fingerprint specified."
 msgstr  ""
 
-#: lxc/storage.go:355 lxc/storage.go:448
+#: lxc/storage.go:377 lxc/storage.go:470
 msgid   "Only \"custom\" volumes can be attached to containers."
 msgstr  ""
 
@@ -845,7 +849,7 @@ msgstr  ""
 msgid   "Pid: %d"
 msgstr  ""
 
-#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:605 lxc/storage.go:980
+#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:627 lxc/storage.go:1059
 msgid   "Press enter to open the editor again"
 msgstr  ""
 
@@ -953,7 +957,7 @@ msgstr  ""
 msgid   "Remove %s (yes/no): "
 msgstr  ""
 
-#: lxc/storage.go:1011
+#: lxc/storage.go:1090
 #, c-format
 msgid   "Renamed storage volume from \"%s\" to \"%s\""
 msgstr  ""
@@ -991,7 +995,7 @@ msgstr  ""
 msgid   "SNAPSHOTS"
 msgstr  ""
 
-#: lxc/storage.go:684
+#: lxc/storage.go:706
 msgid   "SOURCE"
 msgstr  ""
 
@@ -1059,7 +1063,7 @@ msgstr  ""
 msgid   "Show the resources available to the server"
 msgstr  ""
 
-#: lxc/storage.go:151
+#: lxc/storage.go:159
 msgid   "Show the resources available to the storage pool"
 msgstr  ""
 
@@ -1112,12 +1116,12 @@ msgstr  ""
 msgid   "Stopping the container failed: %s"
 msgstr  ""
 
-#: lxc/storage.go:496
+#: lxc/storage.go:518
 #, c-format
 msgid   "Storage pool %s created"
 msgstr  ""
 
-#: lxc/storage.go:555
+#: lxc/storage.go:577
 #, c-format
 msgid   "Storage pool %s deleted"
 msgstr  ""
@@ -1126,12 +1130,12 @@ msgstr  ""
 msgid   "Storage pool name"
 msgstr  ""
 
-#: lxc/storage.go:826
+#: lxc/storage.go:852
 #, c-format
 msgid   "Storage volume %s created"
 msgstr  ""
 
-#: lxc/storage.go:841
+#: lxc/storage.go:867
 #, c-format
 msgid   "Storage volume %s deleted"
 msgstr  ""
@@ -1148,7 +1152,7 @@ msgstr  ""
 msgid   "Swap (peak)"
 msgstr  ""
 
-#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:791
+#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:817
 msgid   "TYPE"
 msgstr  ""
 
@@ -1181,7 +1185,7 @@ msgstr  ""
 msgid   "The opposite of \"lxc pause\" is \"lxc start\"."
 msgstr  ""
 
-#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:416 lxc/storage.go:536
+#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:438 lxc/storage.go:558
 msgid   "The specified device doesn't exist"
 msgstr  ""
 
@@ -1259,7 +1263,7 @@ msgstr  ""
 msgid   "URL"
 msgstr  ""
 
-#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:685 lxc/storage.go:794
+#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:707 lxc/storage.go:820
 msgid   "USED BY"
 msgstr  ""
 
@@ -1941,7 +1945,7 @@ msgid   "Usage: lxc snapshot [<remote>:]<container> <snapshot name> [--stateful]
         "    Create a snapshot of \"u1\" called \"snap0\"."
 msgstr  ""
 
-#: lxc/storage.go:64
+#: lxc/storage.go:65
 msgid   "Usage: lxc storage <subcommand> [options]\n"
         "\n"
         "Manage storage pools and volumes.\n"
@@ -2009,7 +2013,13 @@ msgid   "Usage: lxc storage <subcommand> [options]\n"
         "    Detach a storage volume from the specified container.\n"
         "\n"
         "lxc storage volume detach-profile [<remote:>]<pool> <volume> <profile> [device name]\n"
-        "    Detach a storage volume from the specified profile.\n"
+        "	Detach a storage volume from the specified profile.\n"
+        "\n"
+        "lxc storage volume copy [<pool>/]<volume> [<pool>/]<volume> [--config|-c <key=value>...]\n"
+        "    Copy an existing volume to a new volume at the specified pool.\n"
+        "\n"
+        "lxc storage volume move [<pool>/]<volume> [<pool>/]<volume>\n"
+        "    Move an existing volume to the specified pool.\n"
         "\n"
         "Unless specified through a prefix, all volume operations affect \"custom\" (user created) volumes.\n"
         "\n"
diff --git a/po/nb_NO.po b/po/nb_NO.po
index f41956143..cb2eed63d 100644
--- a/po/nb_NO.po
+++ b/po/nb_NO.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: lxd\n"
 "Report-Msgid-Bugs-To: lxc-devel at lists.linuxcontainers.org\n"
-"POT-Creation-Date: 2018-01-11 17:16-0500\n"
+"POT-Creation-Date: 2018-01-16 11:17+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -16,7 +16,7 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: lxc/storage.go:33
+#: lxc/storage.go:34
 msgid ""
 "### This is a yaml representation of a storage pool.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -33,7 +33,7 @@ msgid ""
 "###   zfs.pool_name: default"
 msgstr ""
 
-#: lxc/storage.go:50
+#: lxc/storage.go:51
 msgid ""
 "### This is a yaml representation of a storage volume.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -288,7 +288,7 @@ msgstr ""
 msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
 
-#: lxc/profile.go:546 lxc/storage.go:653
+#: lxc/profile.go:546 lxc/storage.go:675
 msgid "Cannot provide container name to list"
 msgstr ""
 
@@ -313,8 +313,12 @@ msgstr ""
 msgid "Config key/value to apply to the new container"
 msgstr ""
 
+#: lxc/storage.go:158
+msgid "Config key/value to apply to the new storage volume"
+msgstr ""
+
 #: lxc/config.go:816 lxc/config.go:881 lxc/config.go:1331 lxc/image.go:1190
-#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:604 lxc/storage.go:979
+#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:626 lxc/storage.go:1058
 #, c-format
 msgid "Config parsing error: %s"
 msgstr ""
@@ -381,11 +385,11 @@ msgid "Creating the container"
 msgstr ""
 
 #: lxc/image.go:234 lxc/image.go:1137 lxc/list.go:465 lxc/network.go:525
-#: lxc/storage.go:682 lxc/storage.go:793
+#: lxc/storage.go:704 lxc/storage.go:819
 msgid "DESCRIPTION"
 msgstr ""
 
-#: lxc/storage.go:683
+#: lxc/storage.go:705
 msgid "DRIVER"
 msgstr ""
 
@@ -698,7 +702,7 @@ msgstr ""
 msgid "Missing summary."
 msgstr ""
 
-#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:402 lxc/storage.go:522
+#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:424 lxc/storage.go:544
 msgid "More than one device matches, specify the device name."
 msgstr ""
 
@@ -719,7 +723,7 @@ msgid "Must supply container name for: "
 msgstr ""
 
 #: lxc/list.go:467 lxc/network.go:522 lxc/profile.go:573 lxc/remote.go:409
-#: lxc/storage.go:681 lxc/storage.go:792
+#: lxc/storage.go:703 lxc/storage.go:818
 msgid "NAME"
 msgstr ""
 
@@ -767,7 +771,7 @@ msgstr ""
 msgid "No device found for this network"
 msgstr ""
 
-#: lxc/storage.go:411 lxc/storage.go:531
+#: lxc/storage.go:433 lxc/storage.go:553
 msgid "No device found for this storage volume."
 msgstr ""
 
@@ -775,7 +779,7 @@ msgstr ""
 msgid "No fingerprint specified."
 msgstr ""
 
-#: lxc/storage.go:355 lxc/storage.go:448
+#: lxc/storage.go:377 lxc/storage.go:470
 msgid "Only \"custom\" volumes can be attached to containers."
 msgstr ""
 
@@ -857,7 +861,7 @@ msgstr ""
 msgid "Pid: %d"
 msgstr ""
 
-#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:605 lxc/storage.go:980
+#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:627 lxc/storage.go:1059
 msgid "Press enter to open the editor again"
 msgstr ""
 
@@ -966,7 +970,7 @@ msgstr ""
 msgid "Remove %s (yes/no): "
 msgstr ""
 
-#: lxc/storage.go:1011
+#: lxc/storage.go:1090
 #, c-format
 msgid "Renamed storage volume from \"%s\" to \"%s\""
 msgstr ""
@@ -1004,7 +1008,7 @@ msgstr ""
 msgid "SNAPSHOTS"
 msgstr ""
 
-#: lxc/storage.go:684
+#: lxc/storage.go:706
 msgid "SOURCE"
 msgstr ""
 
@@ -1072,7 +1076,7 @@ msgstr ""
 msgid "Show the resources available to the server"
 msgstr ""
 
-#: lxc/storage.go:151
+#: lxc/storage.go:159
 msgid "Show the resources available to the storage pool"
 msgstr ""
 
@@ -1125,12 +1129,12 @@ msgstr ""
 msgid "Stopping the container failed: %s"
 msgstr ""
 
-#: lxc/storage.go:496
+#: lxc/storage.go:518
 #, c-format
 msgid "Storage pool %s created"
 msgstr ""
 
-#: lxc/storage.go:555
+#: lxc/storage.go:577
 #, c-format
 msgid "Storage pool %s deleted"
 msgstr ""
@@ -1139,12 +1143,12 @@ msgstr ""
 msgid "Storage pool name"
 msgstr ""
 
-#: lxc/storage.go:826
+#: lxc/storage.go:852
 #, c-format
 msgid "Storage volume %s created"
 msgstr ""
 
-#: lxc/storage.go:841
+#: lxc/storage.go:867
 #, c-format
 msgid "Storage volume %s deleted"
 msgstr ""
@@ -1161,7 +1165,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:791
+#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:817
 msgid "TYPE"
 msgstr ""
 
@@ -1197,7 +1201,7 @@ msgstr ""
 msgid "The opposite of \"lxc pause\" is \"lxc start\"."
 msgstr ""
 
-#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:416 lxc/storage.go:536
+#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:438 lxc/storage.go:558
 msgid "The specified device doesn't exist"
 msgstr ""
 
@@ -1276,7 +1280,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:685 lxc/storage.go:794
+#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:707 lxc/storage.go:820
 msgid "USED BY"
 msgstr ""
 
@@ -2035,7 +2039,7 @@ msgid ""
 "    Create a snapshot of \"u1\" called \"snap0\"."
 msgstr ""
 
-#: lxc/storage.go:64
+#: lxc/storage.go:65
 msgid ""
 "Usage: lxc storage <subcommand> [options]\n"
 "\n"
@@ -2110,7 +2114,14 @@ msgid ""
 "\n"
 "lxc storage volume detach-profile [<remote:>]<pool> <volume> <profile> "
 "[device name]\n"
-"    Detach a storage volume from the specified profile.\n"
+"\tDetach a storage volume from the specified profile.\n"
+"\n"
+"lxc storage volume copy [<pool>/]<volume> [<pool>/]<volume> [--config|-c "
+"<key=value>...]\n"
+"    Copy an existing volume to a new volume at the specified pool.\n"
+"\n"
+"lxc storage volume move [<pool>/]<volume> [<pool>/]<volume>\n"
+"    Move an existing volume to the specified pool.\n"
 "\n"
 "Unless specified through a prefix, all volume operations affect \"custom"
 "\" (user created) volumes.\n"
diff --git a/po/nl.po b/po/nl.po
index 0fd7dc570..dade54117 100644
--- a/po/nl.po
+++ b/po/nl.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: lxd\n"
 "Report-Msgid-Bugs-To: lxc-devel at lists.linuxcontainers.org\n"
-"POT-Creation-Date: 2018-01-11 17:16-0500\n"
+"POT-Creation-Date: 2018-01-16 11:17+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -16,7 +16,7 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: lxc/storage.go:33
+#: lxc/storage.go:34
 msgid ""
 "### This is a yaml representation of a storage pool.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -33,7 +33,7 @@ msgid ""
 "###   zfs.pool_name: default"
 msgstr ""
 
-#: lxc/storage.go:50
+#: lxc/storage.go:51
 msgid ""
 "### This is a yaml representation of a storage volume.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -288,7 +288,7 @@ msgstr ""
 msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
 
-#: lxc/profile.go:546 lxc/storage.go:653
+#: lxc/profile.go:546 lxc/storage.go:675
 msgid "Cannot provide container name to list"
 msgstr ""
 
@@ -313,8 +313,12 @@ msgstr ""
 msgid "Config key/value to apply to the new container"
 msgstr ""
 
+#: lxc/storage.go:158
+msgid "Config key/value to apply to the new storage volume"
+msgstr ""
+
 #: lxc/config.go:816 lxc/config.go:881 lxc/config.go:1331 lxc/image.go:1190
-#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:604 lxc/storage.go:979
+#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:626 lxc/storage.go:1058
 #, c-format
 msgid "Config parsing error: %s"
 msgstr ""
@@ -381,11 +385,11 @@ msgid "Creating the container"
 msgstr ""
 
 #: lxc/image.go:234 lxc/image.go:1137 lxc/list.go:465 lxc/network.go:525
-#: lxc/storage.go:682 lxc/storage.go:793
+#: lxc/storage.go:704 lxc/storage.go:819
 msgid "DESCRIPTION"
 msgstr ""
 
-#: lxc/storage.go:683
+#: lxc/storage.go:705
 msgid "DRIVER"
 msgstr ""
 
@@ -698,7 +702,7 @@ msgstr ""
 msgid "Missing summary."
 msgstr ""
 
-#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:402 lxc/storage.go:522
+#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:424 lxc/storage.go:544
 msgid "More than one device matches, specify the device name."
 msgstr ""
 
@@ -719,7 +723,7 @@ msgid "Must supply container name for: "
 msgstr ""
 
 #: lxc/list.go:467 lxc/network.go:522 lxc/profile.go:573 lxc/remote.go:409
-#: lxc/storage.go:681 lxc/storage.go:792
+#: lxc/storage.go:703 lxc/storage.go:818
 msgid "NAME"
 msgstr ""
 
@@ -767,7 +771,7 @@ msgstr ""
 msgid "No device found for this network"
 msgstr ""
 
-#: lxc/storage.go:411 lxc/storage.go:531
+#: lxc/storage.go:433 lxc/storage.go:553
 msgid "No device found for this storage volume."
 msgstr ""
 
@@ -775,7 +779,7 @@ msgstr ""
 msgid "No fingerprint specified."
 msgstr ""
 
-#: lxc/storage.go:355 lxc/storage.go:448
+#: lxc/storage.go:377 lxc/storage.go:470
 msgid "Only \"custom\" volumes can be attached to containers."
 msgstr ""
 
@@ -857,7 +861,7 @@ msgstr ""
 msgid "Pid: %d"
 msgstr ""
 
-#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:605 lxc/storage.go:980
+#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:627 lxc/storage.go:1059
 msgid "Press enter to open the editor again"
 msgstr ""
 
@@ -966,7 +970,7 @@ msgstr ""
 msgid "Remove %s (yes/no): "
 msgstr ""
 
-#: lxc/storage.go:1011
+#: lxc/storage.go:1090
 #, c-format
 msgid "Renamed storage volume from \"%s\" to \"%s\""
 msgstr ""
@@ -1004,7 +1008,7 @@ msgstr ""
 msgid "SNAPSHOTS"
 msgstr ""
 
-#: lxc/storage.go:684
+#: lxc/storage.go:706
 msgid "SOURCE"
 msgstr ""
 
@@ -1072,7 +1076,7 @@ msgstr ""
 msgid "Show the resources available to the server"
 msgstr ""
 
-#: lxc/storage.go:151
+#: lxc/storage.go:159
 msgid "Show the resources available to the storage pool"
 msgstr ""
 
@@ -1125,12 +1129,12 @@ msgstr ""
 msgid "Stopping the container failed: %s"
 msgstr ""
 
-#: lxc/storage.go:496
+#: lxc/storage.go:518
 #, c-format
 msgid "Storage pool %s created"
 msgstr ""
 
-#: lxc/storage.go:555
+#: lxc/storage.go:577
 #, c-format
 msgid "Storage pool %s deleted"
 msgstr ""
@@ -1139,12 +1143,12 @@ msgstr ""
 msgid "Storage pool name"
 msgstr ""
 
-#: lxc/storage.go:826
+#: lxc/storage.go:852
 #, c-format
 msgid "Storage volume %s created"
 msgstr ""
 
-#: lxc/storage.go:841
+#: lxc/storage.go:867
 #, c-format
 msgid "Storage volume %s deleted"
 msgstr ""
@@ -1161,7 +1165,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:791
+#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:817
 msgid "TYPE"
 msgstr ""
 
@@ -1197,7 +1201,7 @@ msgstr ""
 msgid "The opposite of \"lxc pause\" is \"lxc start\"."
 msgstr ""
 
-#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:416 lxc/storage.go:536
+#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:438 lxc/storage.go:558
 msgid "The specified device doesn't exist"
 msgstr ""
 
@@ -1276,7 +1280,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:685 lxc/storage.go:794
+#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:707 lxc/storage.go:820
 msgid "USED BY"
 msgstr ""
 
@@ -2035,7 +2039,7 @@ msgid ""
 "    Create a snapshot of \"u1\" called \"snap0\"."
 msgstr ""
 
-#: lxc/storage.go:64
+#: lxc/storage.go:65
 msgid ""
 "Usage: lxc storage <subcommand> [options]\n"
 "\n"
@@ -2110,7 +2114,14 @@ msgid ""
 "\n"
 "lxc storage volume detach-profile [<remote:>]<pool> <volume> <profile> "
 "[device name]\n"
-"    Detach a storage volume from the specified profile.\n"
+"\tDetach a storage volume from the specified profile.\n"
+"\n"
+"lxc storage volume copy [<pool>/]<volume> [<pool>/]<volume> [--config|-c "
+"<key=value>...]\n"
+"    Copy an existing volume to a new volume at the specified pool.\n"
+"\n"
+"lxc storage volume move [<pool>/]<volume> [<pool>/]<volume>\n"
+"    Move an existing volume to the specified pool.\n"
 "\n"
 "Unless specified through a prefix, all volume operations affect \"custom"
 "\" (user created) volumes.\n"
diff --git a/po/pl.po b/po/pl.po
index 3b311bcea..e13462c6b 100644
--- a/po/pl.po
+++ b/po/pl.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: lxd\n"
 "Report-Msgid-Bugs-To: lxc-devel at lists.linuxcontainers.org\n"
-"POT-Creation-Date: 2018-01-11 17:16-0500\n"
+"POT-Creation-Date: 2018-01-16 11:17+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -16,7 +16,7 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: lxc/storage.go:33
+#: lxc/storage.go:34
 msgid ""
 "### This is a yaml representation of a storage pool.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -33,7 +33,7 @@ msgid ""
 "###   zfs.pool_name: default"
 msgstr ""
 
-#: lxc/storage.go:50
+#: lxc/storage.go:51
 msgid ""
 "### This is a yaml representation of a storage volume.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -288,7 +288,7 @@ msgstr ""
 msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
 
-#: lxc/profile.go:546 lxc/storage.go:653
+#: lxc/profile.go:546 lxc/storage.go:675
 msgid "Cannot provide container name to list"
 msgstr ""
 
@@ -313,8 +313,12 @@ msgstr ""
 msgid "Config key/value to apply to the new container"
 msgstr ""
 
+#: lxc/storage.go:158
+msgid "Config key/value to apply to the new storage volume"
+msgstr ""
+
 #: lxc/config.go:816 lxc/config.go:881 lxc/config.go:1331 lxc/image.go:1190
-#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:604 lxc/storage.go:979
+#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:626 lxc/storage.go:1058
 #, c-format
 msgid "Config parsing error: %s"
 msgstr ""
@@ -381,11 +385,11 @@ msgid "Creating the container"
 msgstr ""
 
 #: lxc/image.go:234 lxc/image.go:1137 lxc/list.go:465 lxc/network.go:525
-#: lxc/storage.go:682 lxc/storage.go:793
+#: lxc/storage.go:704 lxc/storage.go:819
 msgid "DESCRIPTION"
 msgstr ""
 
-#: lxc/storage.go:683
+#: lxc/storage.go:705
 msgid "DRIVER"
 msgstr ""
 
@@ -698,7 +702,7 @@ msgstr ""
 msgid "Missing summary."
 msgstr ""
 
-#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:402 lxc/storage.go:522
+#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:424 lxc/storage.go:544
 msgid "More than one device matches, specify the device name."
 msgstr ""
 
@@ -719,7 +723,7 @@ msgid "Must supply container name for: "
 msgstr ""
 
 #: lxc/list.go:467 lxc/network.go:522 lxc/profile.go:573 lxc/remote.go:409
-#: lxc/storage.go:681 lxc/storage.go:792
+#: lxc/storage.go:703 lxc/storage.go:818
 msgid "NAME"
 msgstr ""
 
@@ -767,7 +771,7 @@ msgstr ""
 msgid "No device found for this network"
 msgstr ""
 
-#: lxc/storage.go:411 lxc/storage.go:531
+#: lxc/storage.go:433 lxc/storage.go:553
 msgid "No device found for this storage volume."
 msgstr ""
 
@@ -775,7 +779,7 @@ msgstr ""
 msgid "No fingerprint specified."
 msgstr ""
 
-#: lxc/storage.go:355 lxc/storage.go:448
+#: lxc/storage.go:377 lxc/storage.go:470
 msgid "Only \"custom\" volumes can be attached to containers."
 msgstr ""
 
@@ -857,7 +861,7 @@ msgstr ""
 msgid "Pid: %d"
 msgstr ""
 
-#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:605 lxc/storage.go:980
+#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:627 lxc/storage.go:1059
 msgid "Press enter to open the editor again"
 msgstr ""
 
@@ -966,7 +970,7 @@ msgstr ""
 msgid "Remove %s (yes/no): "
 msgstr ""
 
-#: lxc/storage.go:1011
+#: lxc/storage.go:1090
 #, c-format
 msgid "Renamed storage volume from \"%s\" to \"%s\""
 msgstr ""
@@ -1004,7 +1008,7 @@ msgstr ""
 msgid "SNAPSHOTS"
 msgstr ""
 
-#: lxc/storage.go:684
+#: lxc/storage.go:706
 msgid "SOURCE"
 msgstr ""
 
@@ -1072,7 +1076,7 @@ msgstr ""
 msgid "Show the resources available to the server"
 msgstr ""
 
-#: lxc/storage.go:151
+#: lxc/storage.go:159
 msgid "Show the resources available to the storage pool"
 msgstr ""
 
@@ -1125,12 +1129,12 @@ msgstr ""
 msgid "Stopping the container failed: %s"
 msgstr ""
 
-#: lxc/storage.go:496
+#: lxc/storage.go:518
 #, c-format
 msgid "Storage pool %s created"
 msgstr ""
 
-#: lxc/storage.go:555
+#: lxc/storage.go:577
 #, c-format
 msgid "Storage pool %s deleted"
 msgstr ""
@@ -1139,12 +1143,12 @@ msgstr ""
 msgid "Storage pool name"
 msgstr ""
 
-#: lxc/storage.go:826
+#: lxc/storage.go:852
 #, c-format
 msgid "Storage volume %s created"
 msgstr ""
 
-#: lxc/storage.go:841
+#: lxc/storage.go:867
 #, c-format
 msgid "Storage volume %s deleted"
 msgstr ""
@@ -1161,7 +1165,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:791
+#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:817
 msgid "TYPE"
 msgstr ""
 
@@ -1197,7 +1201,7 @@ msgstr ""
 msgid "The opposite of \"lxc pause\" is \"lxc start\"."
 msgstr ""
 
-#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:416 lxc/storage.go:536
+#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:438 lxc/storage.go:558
 msgid "The specified device doesn't exist"
 msgstr ""
 
@@ -1276,7 +1280,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:685 lxc/storage.go:794
+#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:707 lxc/storage.go:820
 msgid "USED BY"
 msgstr ""
 
@@ -2035,7 +2039,7 @@ msgid ""
 "    Create a snapshot of \"u1\" called \"snap0\"."
 msgstr ""
 
-#: lxc/storage.go:64
+#: lxc/storage.go:65
 msgid ""
 "Usage: lxc storage <subcommand> [options]\n"
 "\n"
@@ -2110,7 +2114,14 @@ msgid ""
 "\n"
 "lxc storage volume detach-profile [<remote:>]<pool> <volume> <profile> "
 "[device name]\n"
-"    Detach a storage volume from the specified profile.\n"
+"\tDetach a storage volume from the specified profile.\n"
+"\n"
+"lxc storage volume copy [<pool>/]<volume> [<pool>/]<volume> [--config|-c "
+"<key=value>...]\n"
+"    Copy an existing volume to a new volume at the specified pool.\n"
+"\n"
+"lxc storage volume move [<pool>/]<volume> [<pool>/]<volume>\n"
+"    Move an existing volume to the specified pool.\n"
 "\n"
 "Unless specified through a prefix, all volume operations affect \"custom"
 "\" (user created) volumes.\n"
diff --git a/po/pt_BR.po b/po/pt_BR.po
index c983b3390..9dd9f611c 100644
--- a/po/pt_BR.po
+++ b/po/pt_BR.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: lxd\n"
 "Report-Msgid-Bugs-To: lxc-devel at lists.linuxcontainers.org\n"
-"POT-Creation-Date: 2018-01-11 17:16-0500\n"
+"POT-Creation-Date: 2018-01-16 11:17+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -16,7 +16,7 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: lxc/storage.go:33
+#: lxc/storage.go:34
 msgid ""
 "### This is a yaml representation of a storage pool.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -33,7 +33,7 @@ msgid ""
 "###   zfs.pool_name: default"
 msgstr ""
 
-#: lxc/storage.go:50
+#: lxc/storage.go:51
 msgid ""
 "### This is a yaml representation of a storage volume.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -288,7 +288,7 @@ msgstr ""
 msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
 
-#: lxc/profile.go:546 lxc/storage.go:653
+#: lxc/profile.go:546 lxc/storage.go:675
 msgid "Cannot provide container name to list"
 msgstr ""
 
@@ -313,8 +313,12 @@ msgstr ""
 msgid "Config key/value to apply to the new container"
 msgstr ""
 
+#: lxc/storage.go:158
+msgid "Config key/value to apply to the new storage volume"
+msgstr ""
+
 #: lxc/config.go:816 lxc/config.go:881 lxc/config.go:1331 lxc/image.go:1190
-#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:604 lxc/storage.go:979
+#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:626 lxc/storage.go:1058
 #, c-format
 msgid "Config parsing error: %s"
 msgstr ""
@@ -381,11 +385,11 @@ msgid "Creating the container"
 msgstr ""
 
 #: lxc/image.go:234 lxc/image.go:1137 lxc/list.go:465 lxc/network.go:525
-#: lxc/storage.go:682 lxc/storage.go:793
+#: lxc/storage.go:704 lxc/storage.go:819
 msgid "DESCRIPTION"
 msgstr ""
 
-#: lxc/storage.go:683
+#: lxc/storage.go:705
 msgid "DRIVER"
 msgstr ""
 
@@ -698,7 +702,7 @@ msgstr ""
 msgid "Missing summary."
 msgstr ""
 
-#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:402 lxc/storage.go:522
+#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:424 lxc/storage.go:544
 msgid "More than one device matches, specify the device name."
 msgstr ""
 
@@ -719,7 +723,7 @@ msgid "Must supply container name for: "
 msgstr ""
 
 #: lxc/list.go:467 lxc/network.go:522 lxc/profile.go:573 lxc/remote.go:409
-#: lxc/storage.go:681 lxc/storage.go:792
+#: lxc/storage.go:703 lxc/storage.go:818
 msgid "NAME"
 msgstr ""
 
@@ -767,7 +771,7 @@ msgstr ""
 msgid "No device found for this network"
 msgstr ""
 
-#: lxc/storage.go:411 lxc/storage.go:531
+#: lxc/storage.go:433 lxc/storage.go:553
 msgid "No device found for this storage volume."
 msgstr ""
 
@@ -775,7 +779,7 @@ msgstr ""
 msgid "No fingerprint specified."
 msgstr ""
 
-#: lxc/storage.go:355 lxc/storage.go:448
+#: lxc/storage.go:377 lxc/storage.go:470
 msgid "Only \"custom\" volumes can be attached to containers."
 msgstr ""
 
@@ -857,7 +861,7 @@ msgstr ""
 msgid "Pid: %d"
 msgstr ""
 
-#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:605 lxc/storage.go:980
+#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:627 lxc/storage.go:1059
 msgid "Press enter to open the editor again"
 msgstr ""
 
@@ -966,7 +970,7 @@ msgstr ""
 msgid "Remove %s (yes/no): "
 msgstr ""
 
-#: lxc/storage.go:1011
+#: lxc/storage.go:1090
 #, c-format
 msgid "Renamed storage volume from \"%s\" to \"%s\""
 msgstr ""
@@ -1004,7 +1008,7 @@ msgstr ""
 msgid "SNAPSHOTS"
 msgstr ""
 
-#: lxc/storage.go:684
+#: lxc/storage.go:706
 msgid "SOURCE"
 msgstr ""
 
@@ -1072,7 +1076,7 @@ msgstr ""
 msgid "Show the resources available to the server"
 msgstr ""
 
-#: lxc/storage.go:151
+#: lxc/storage.go:159
 msgid "Show the resources available to the storage pool"
 msgstr ""
 
@@ -1125,12 +1129,12 @@ msgstr ""
 msgid "Stopping the container failed: %s"
 msgstr ""
 
-#: lxc/storage.go:496
+#: lxc/storage.go:518
 #, c-format
 msgid "Storage pool %s created"
 msgstr ""
 
-#: lxc/storage.go:555
+#: lxc/storage.go:577
 #, c-format
 msgid "Storage pool %s deleted"
 msgstr ""
@@ -1139,12 +1143,12 @@ msgstr ""
 msgid "Storage pool name"
 msgstr ""
 
-#: lxc/storage.go:826
+#: lxc/storage.go:852
 #, c-format
 msgid "Storage volume %s created"
 msgstr ""
 
-#: lxc/storage.go:841
+#: lxc/storage.go:867
 #, c-format
 msgid "Storage volume %s deleted"
 msgstr ""
@@ -1161,7 +1165,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:791
+#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:817
 msgid "TYPE"
 msgstr ""
 
@@ -1197,7 +1201,7 @@ msgstr ""
 msgid "The opposite of \"lxc pause\" is \"lxc start\"."
 msgstr ""
 
-#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:416 lxc/storage.go:536
+#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:438 lxc/storage.go:558
 msgid "The specified device doesn't exist"
 msgstr ""
 
@@ -1276,7 +1280,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:685 lxc/storage.go:794
+#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:707 lxc/storage.go:820
 msgid "USED BY"
 msgstr ""
 
@@ -2035,7 +2039,7 @@ msgid ""
 "    Create a snapshot of \"u1\" called \"snap0\"."
 msgstr ""
 
-#: lxc/storage.go:64
+#: lxc/storage.go:65
 msgid ""
 "Usage: lxc storage <subcommand> [options]\n"
 "\n"
@@ -2110,7 +2114,14 @@ msgid ""
 "\n"
 "lxc storage volume detach-profile [<remote:>]<pool> <volume> <profile> "
 "[device name]\n"
-"    Detach a storage volume from the specified profile.\n"
+"\tDetach a storage volume from the specified profile.\n"
+"\n"
+"lxc storage volume copy [<pool>/]<volume> [<pool>/]<volume> [--config|-c "
+"<key=value>...]\n"
+"    Copy an existing volume to a new volume at the specified pool.\n"
+"\n"
+"lxc storage volume move [<pool>/]<volume> [<pool>/]<volume>\n"
+"    Move an existing volume to the specified pool.\n"
 "\n"
 "Unless specified through a prefix, all volume operations affect \"custom"
 "\" (user created) volumes.\n"
diff --git a/po/ru.po b/po/ru.po
index 986d4b729..60920b371 100644
--- a/po/ru.po
+++ b/po/ru.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: lxd\n"
 "Report-Msgid-Bugs-To: lxc-devel at lists.linuxcontainers.org\n"
-"POT-Creation-Date: 2018-01-11 17:16-0500\n"
+"POT-Creation-Date: 2018-01-16 11:17+0100\n"
 "PO-Revision-Date: 2017-09-05 16:48+0000\n"
 "Last-Translator: Ilya Yakimavets <ilya.yakimavets at backend.expert>\n"
 "Language-Team: Russian <https://hosted.weblate.org/projects/linux-containers/"
@@ -20,7 +20,7 @@ msgstr ""
 "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
 "X-Generator: Weblate 2.17-dev\n"
 
-#: lxc/storage.go:33
+#: lxc/storage.go:34
 msgid ""
 "### This is a yaml representation of a storage pool.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -50,7 +50,7 @@ msgstr ""
 "###   source: /home/chb/mnt/lxd_test/default.img\n"
 "###   zfs.pool_name: default"
 
-#: lxc/storage.go:50
+#: lxc/storage.go:51
 msgid ""
 "### This is a yaml representation of a storage volume.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -376,7 +376,7 @@ msgstr ""
 msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
 
-#: lxc/profile.go:546 lxc/storage.go:653
+#: lxc/profile.go:546 lxc/storage.go:675
 msgid "Cannot provide container name to list"
 msgstr "Невозможно добавить имя контейнера в список"
 
@@ -401,8 +401,12 @@ msgstr ""
 msgid "Config key/value to apply to the new container"
 msgstr ""
 
+#: lxc/storage.go:158
+msgid "Config key/value to apply to the new storage volume"
+msgstr ""
+
 #: lxc/config.go:816 lxc/config.go:881 lxc/config.go:1331 lxc/image.go:1190
-#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:604 lxc/storage.go:979
+#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:626 lxc/storage.go:1058
 #, c-format
 msgid "Config parsing error: %s"
 msgstr ""
@@ -469,11 +473,11 @@ msgid "Creating the container"
 msgstr ""
 
 #: lxc/image.go:234 lxc/image.go:1137 lxc/list.go:465 lxc/network.go:525
-#: lxc/storage.go:682 lxc/storage.go:793
+#: lxc/storage.go:704 lxc/storage.go:819
 msgid "DESCRIPTION"
 msgstr ""
 
-#: lxc/storage.go:683
+#: lxc/storage.go:705
 msgid "DRIVER"
 msgstr ""
 
@@ -788,7 +792,7 @@ msgstr " Использование памяти:"
 msgid "Missing summary."
 msgstr ""
 
-#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:402 lxc/storage.go:522
+#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:424 lxc/storage.go:544
 msgid "More than one device matches, specify the device name."
 msgstr ""
 
@@ -809,7 +813,7 @@ msgid "Must supply container name for: "
 msgstr ""
 
 #: lxc/list.go:467 lxc/network.go:522 lxc/profile.go:573 lxc/remote.go:409
-#: lxc/storage.go:681 lxc/storage.go:792
+#: lxc/storage.go:703 lxc/storage.go:818
 msgid "NAME"
 msgstr ""
 
@@ -858,7 +862,7 @@ msgstr ""
 msgid "No device found for this network"
 msgstr ""
 
-#: lxc/storage.go:411 lxc/storage.go:531
+#: lxc/storage.go:433 lxc/storage.go:553
 msgid "No device found for this storage volume."
 msgstr ""
 
@@ -866,7 +870,7 @@ msgstr ""
 msgid "No fingerprint specified."
 msgstr ""
 
-#: lxc/storage.go:355 lxc/storage.go:448
+#: lxc/storage.go:377 lxc/storage.go:470
 msgid "Only \"custom\" volumes can be attached to containers."
 msgstr ""
 
@@ -948,7 +952,7 @@ msgstr ""
 msgid "Pid: %d"
 msgstr ""
 
-#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:605 lxc/storage.go:980
+#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:627 lxc/storage.go:1059
 msgid "Press enter to open the editor again"
 msgstr ""
 
@@ -1057,7 +1061,7 @@ msgstr ""
 msgid "Remove %s (yes/no): "
 msgstr ""
 
-#: lxc/storage.go:1011
+#: lxc/storage.go:1090
 #, c-format
 msgid "Renamed storage volume from \"%s\" to \"%s\""
 msgstr ""
@@ -1095,7 +1099,7 @@ msgstr ""
 msgid "SNAPSHOTS"
 msgstr ""
 
-#: lxc/storage.go:684
+#: lxc/storage.go:706
 msgid "SOURCE"
 msgstr ""
 
@@ -1163,7 +1167,7 @@ msgstr ""
 msgid "Show the resources available to the server"
 msgstr ""
 
-#: lxc/storage.go:151
+#: lxc/storage.go:159
 msgid "Show the resources available to the storage pool"
 msgstr ""
 
@@ -1216,12 +1220,12 @@ msgstr ""
 msgid "Stopping the container failed: %s"
 msgstr "Невозможно добавить имя контейнера в список"
 
-#: lxc/storage.go:496
+#: lxc/storage.go:518
 #, c-format
 msgid "Storage pool %s created"
 msgstr ""
 
-#: lxc/storage.go:555
+#: lxc/storage.go:577
 #, c-format
 msgid "Storage pool %s deleted"
 msgstr ""
@@ -1230,12 +1234,12 @@ msgstr ""
 msgid "Storage pool name"
 msgstr ""
 
-#: lxc/storage.go:826
+#: lxc/storage.go:852
 #, c-format
 msgid "Storage volume %s created"
 msgstr ""
 
-#: lxc/storage.go:841
+#: lxc/storage.go:867
 #, c-format
 msgid "Storage volume %s deleted"
 msgstr ""
@@ -1252,7 +1256,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:791
+#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:817
 msgid "TYPE"
 msgstr ""
 
@@ -1288,7 +1292,7 @@ msgstr ""
 msgid "The opposite of \"lxc pause\" is \"lxc start\"."
 msgstr ""
 
-#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:416 lxc/storage.go:536
+#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:438 lxc/storage.go:558
 msgid "The specified device doesn't exist"
 msgstr ""
 
@@ -1367,7 +1371,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:685 lxc/storage.go:794
+#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:707 lxc/storage.go:820
 msgid "USED BY"
 msgstr ""
 
@@ -2138,7 +2142,7 @@ msgid ""
 "    Create a snapshot of \"u1\" called \"snap0\"."
 msgstr ""
 
-#: lxc/storage.go:64
+#: lxc/storage.go:65
 msgid ""
 "Usage: lxc storage <subcommand> [options]\n"
 "\n"
@@ -2213,7 +2217,14 @@ msgid ""
 "\n"
 "lxc storage volume detach-profile [<remote:>]<pool> <volume> <profile> "
 "[device name]\n"
-"    Detach a storage volume from the specified profile.\n"
+"\tDetach a storage volume from the specified profile.\n"
+"\n"
+"lxc storage volume copy [<pool>/]<volume> [<pool>/]<volume> [--config|-c "
+"<key=value>...]\n"
+"    Copy an existing volume to a new volume at the specified pool.\n"
+"\n"
+"lxc storage volume move [<pool>/]<volume> [<pool>/]<volume>\n"
+"    Move an existing volume to the specified pool.\n"
 "\n"
 "Unless specified through a prefix, all volume operations affect \"custom"
 "\" (user created) volumes.\n"
diff --git a/po/sr.po b/po/sr.po
index 35da191cc..3d0b9718a 100644
--- a/po/sr.po
+++ b/po/sr.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: lxd\n"
 "Report-Msgid-Bugs-To: lxc-devel at lists.linuxcontainers.org\n"
-"POT-Creation-Date: 2018-01-11 17:16-0500\n"
+"POT-Creation-Date: 2018-01-16 11:17+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -16,7 +16,7 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: lxc/storage.go:33
+#: lxc/storage.go:34
 msgid ""
 "### This is a yaml representation of a storage pool.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -33,7 +33,7 @@ msgid ""
 "###   zfs.pool_name: default"
 msgstr ""
 
-#: lxc/storage.go:50
+#: lxc/storage.go:51
 msgid ""
 "### This is a yaml representation of a storage volume.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -288,7 +288,7 @@ msgstr ""
 msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
 
-#: lxc/profile.go:546 lxc/storage.go:653
+#: lxc/profile.go:546 lxc/storage.go:675
 msgid "Cannot provide container name to list"
 msgstr ""
 
@@ -313,8 +313,12 @@ msgstr ""
 msgid "Config key/value to apply to the new container"
 msgstr ""
 
+#: lxc/storage.go:158
+msgid "Config key/value to apply to the new storage volume"
+msgstr ""
+
 #: lxc/config.go:816 lxc/config.go:881 lxc/config.go:1331 lxc/image.go:1190
-#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:604 lxc/storage.go:979
+#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:626 lxc/storage.go:1058
 #, c-format
 msgid "Config parsing error: %s"
 msgstr ""
@@ -381,11 +385,11 @@ msgid "Creating the container"
 msgstr ""
 
 #: lxc/image.go:234 lxc/image.go:1137 lxc/list.go:465 lxc/network.go:525
-#: lxc/storage.go:682 lxc/storage.go:793
+#: lxc/storage.go:704 lxc/storage.go:819
 msgid "DESCRIPTION"
 msgstr ""
 
-#: lxc/storage.go:683
+#: lxc/storage.go:705
 msgid "DRIVER"
 msgstr ""
 
@@ -698,7 +702,7 @@ msgstr ""
 msgid "Missing summary."
 msgstr ""
 
-#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:402 lxc/storage.go:522
+#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:424 lxc/storage.go:544
 msgid "More than one device matches, specify the device name."
 msgstr ""
 
@@ -719,7 +723,7 @@ msgid "Must supply container name for: "
 msgstr ""
 
 #: lxc/list.go:467 lxc/network.go:522 lxc/profile.go:573 lxc/remote.go:409
-#: lxc/storage.go:681 lxc/storage.go:792
+#: lxc/storage.go:703 lxc/storage.go:818
 msgid "NAME"
 msgstr ""
 
@@ -767,7 +771,7 @@ msgstr ""
 msgid "No device found for this network"
 msgstr ""
 
-#: lxc/storage.go:411 lxc/storage.go:531
+#: lxc/storage.go:433 lxc/storage.go:553
 msgid "No device found for this storage volume."
 msgstr ""
 
@@ -775,7 +779,7 @@ msgstr ""
 msgid "No fingerprint specified."
 msgstr ""
 
-#: lxc/storage.go:355 lxc/storage.go:448
+#: lxc/storage.go:377 lxc/storage.go:470
 msgid "Only \"custom\" volumes can be attached to containers."
 msgstr ""
 
@@ -857,7 +861,7 @@ msgstr ""
 msgid "Pid: %d"
 msgstr ""
 
-#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:605 lxc/storage.go:980
+#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:627 lxc/storage.go:1059
 msgid "Press enter to open the editor again"
 msgstr ""
 
@@ -966,7 +970,7 @@ msgstr ""
 msgid "Remove %s (yes/no): "
 msgstr ""
 
-#: lxc/storage.go:1011
+#: lxc/storage.go:1090
 #, c-format
 msgid "Renamed storage volume from \"%s\" to \"%s\""
 msgstr ""
@@ -1004,7 +1008,7 @@ msgstr ""
 msgid "SNAPSHOTS"
 msgstr ""
 
-#: lxc/storage.go:684
+#: lxc/storage.go:706
 msgid "SOURCE"
 msgstr ""
 
@@ -1072,7 +1076,7 @@ msgstr ""
 msgid "Show the resources available to the server"
 msgstr ""
 
-#: lxc/storage.go:151
+#: lxc/storage.go:159
 msgid "Show the resources available to the storage pool"
 msgstr ""
 
@@ -1125,12 +1129,12 @@ msgstr ""
 msgid "Stopping the container failed: %s"
 msgstr ""
 
-#: lxc/storage.go:496
+#: lxc/storage.go:518
 #, c-format
 msgid "Storage pool %s created"
 msgstr ""
 
-#: lxc/storage.go:555
+#: lxc/storage.go:577
 #, c-format
 msgid "Storage pool %s deleted"
 msgstr ""
@@ -1139,12 +1143,12 @@ msgstr ""
 msgid "Storage pool name"
 msgstr ""
 
-#: lxc/storage.go:826
+#: lxc/storage.go:852
 #, c-format
 msgid "Storage volume %s created"
 msgstr ""
 
-#: lxc/storage.go:841
+#: lxc/storage.go:867
 #, c-format
 msgid "Storage volume %s deleted"
 msgstr ""
@@ -1161,7 +1165,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:791
+#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:817
 msgid "TYPE"
 msgstr ""
 
@@ -1197,7 +1201,7 @@ msgstr ""
 msgid "The opposite of \"lxc pause\" is \"lxc start\"."
 msgstr ""
 
-#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:416 lxc/storage.go:536
+#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:438 lxc/storage.go:558
 msgid "The specified device doesn't exist"
 msgstr ""
 
@@ -1276,7 +1280,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:685 lxc/storage.go:794
+#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:707 lxc/storage.go:820
 msgid "USED BY"
 msgstr ""
 
@@ -2035,7 +2039,7 @@ msgid ""
 "    Create a snapshot of \"u1\" called \"snap0\"."
 msgstr ""
 
-#: lxc/storage.go:64
+#: lxc/storage.go:65
 msgid ""
 "Usage: lxc storage <subcommand> [options]\n"
 "\n"
@@ -2110,7 +2114,14 @@ msgid ""
 "\n"
 "lxc storage volume detach-profile [<remote:>]<pool> <volume> <profile> "
 "[device name]\n"
-"    Detach a storage volume from the specified profile.\n"
+"\tDetach a storage volume from the specified profile.\n"
+"\n"
+"lxc storage volume copy [<pool>/]<volume> [<pool>/]<volume> [--config|-c "
+"<key=value>...]\n"
+"    Copy an existing volume to a new volume at the specified pool.\n"
+"\n"
+"lxc storage volume move [<pool>/]<volume> [<pool>/]<volume>\n"
+"    Move an existing volume to the specified pool.\n"
 "\n"
 "Unless specified through a prefix, all volume operations affect \"custom"
 "\" (user created) volumes.\n"
diff --git a/po/sv.po b/po/sv.po
index 669bfc3b1..1a7c3c449 100644
--- a/po/sv.po
+++ b/po/sv.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: lxd\n"
 "Report-Msgid-Bugs-To: lxc-devel at lists.linuxcontainers.org\n"
-"POT-Creation-Date: 2018-01-11 17:16-0500\n"
+"POT-Creation-Date: 2018-01-16 11:17+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -16,7 +16,7 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: lxc/storage.go:33
+#: lxc/storage.go:34
 msgid ""
 "### This is a yaml representation of a storage pool.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -33,7 +33,7 @@ msgid ""
 "###   zfs.pool_name: default"
 msgstr ""
 
-#: lxc/storage.go:50
+#: lxc/storage.go:51
 msgid ""
 "### This is a yaml representation of a storage volume.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -288,7 +288,7 @@ msgstr ""
 msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
 
-#: lxc/profile.go:546 lxc/storage.go:653
+#: lxc/profile.go:546 lxc/storage.go:675
 msgid "Cannot provide container name to list"
 msgstr ""
 
@@ -313,8 +313,12 @@ msgstr ""
 msgid "Config key/value to apply to the new container"
 msgstr ""
 
+#: lxc/storage.go:158
+msgid "Config key/value to apply to the new storage volume"
+msgstr ""
+
 #: lxc/config.go:816 lxc/config.go:881 lxc/config.go:1331 lxc/image.go:1190
-#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:604 lxc/storage.go:979
+#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:626 lxc/storage.go:1058
 #, c-format
 msgid "Config parsing error: %s"
 msgstr ""
@@ -381,11 +385,11 @@ msgid "Creating the container"
 msgstr ""
 
 #: lxc/image.go:234 lxc/image.go:1137 lxc/list.go:465 lxc/network.go:525
-#: lxc/storage.go:682 lxc/storage.go:793
+#: lxc/storage.go:704 lxc/storage.go:819
 msgid "DESCRIPTION"
 msgstr ""
 
-#: lxc/storage.go:683
+#: lxc/storage.go:705
 msgid "DRIVER"
 msgstr ""
 
@@ -698,7 +702,7 @@ msgstr ""
 msgid "Missing summary."
 msgstr ""
 
-#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:402 lxc/storage.go:522
+#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:424 lxc/storage.go:544
 msgid "More than one device matches, specify the device name."
 msgstr ""
 
@@ -719,7 +723,7 @@ msgid "Must supply container name for: "
 msgstr ""
 
 #: lxc/list.go:467 lxc/network.go:522 lxc/profile.go:573 lxc/remote.go:409
-#: lxc/storage.go:681 lxc/storage.go:792
+#: lxc/storage.go:703 lxc/storage.go:818
 msgid "NAME"
 msgstr ""
 
@@ -767,7 +771,7 @@ msgstr ""
 msgid "No device found for this network"
 msgstr ""
 
-#: lxc/storage.go:411 lxc/storage.go:531
+#: lxc/storage.go:433 lxc/storage.go:553
 msgid "No device found for this storage volume."
 msgstr ""
 
@@ -775,7 +779,7 @@ msgstr ""
 msgid "No fingerprint specified."
 msgstr ""
 
-#: lxc/storage.go:355 lxc/storage.go:448
+#: lxc/storage.go:377 lxc/storage.go:470
 msgid "Only \"custom\" volumes can be attached to containers."
 msgstr ""
 
@@ -857,7 +861,7 @@ msgstr ""
 msgid "Pid: %d"
 msgstr ""
 
-#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:605 lxc/storage.go:980
+#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:627 lxc/storage.go:1059
 msgid "Press enter to open the editor again"
 msgstr ""
 
@@ -966,7 +970,7 @@ msgstr ""
 msgid "Remove %s (yes/no): "
 msgstr ""
 
-#: lxc/storage.go:1011
+#: lxc/storage.go:1090
 #, c-format
 msgid "Renamed storage volume from \"%s\" to \"%s\""
 msgstr ""
@@ -1004,7 +1008,7 @@ msgstr ""
 msgid "SNAPSHOTS"
 msgstr ""
 
-#: lxc/storage.go:684
+#: lxc/storage.go:706
 msgid "SOURCE"
 msgstr ""
 
@@ -1072,7 +1076,7 @@ msgstr ""
 msgid "Show the resources available to the server"
 msgstr ""
 
-#: lxc/storage.go:151
+#: lxc/storage.go:159
 msgid "Show the resources available to the storage pool"
 msgstr ""
 
@@ -1125,12 +1129,12 @@ msgstr ""
 msgid "Stopping the container failed: %s"
 msgstr ""
 
-#: lxc/storage.go:496
+#: lxc/storage.go:518
 #, c-format
 msgid "Storage pool %s created"
 msgstr ""
 
-#: lxc/storage.go:555
+#: lxc/storage.go:577
 #, c-format
 msgid "Storage pool %s deleted"
 msgstr ""
@@ -1139,12 +1143,12 @@ msgstr ""
 msgid "Storage pool name"
 msgstr ""
 
-#: lxc/storage.go:826
+#: lxc/storage.go:852
 #, c-format
 msgid "Storage volume %s created"
 msgstr ""
 
-#: lxc/storage.go:841
+#: lxc/storage.go:867
 #, c-format
 msgid "Storage volume %s deleted"
 msgstr ""
@@ -1161,7 +1165,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:791
+#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:817
 msgid "TYPE"
 msgstr ""
 
@@ -1197,7 +1201,7 @@ msgstr ""
 msgid "The opposite of \"lxc pause\" is \"lxc start\"."
 msgstr ""
 
-#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:416 lxc/storage.go:536
+#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:438 lxc/storage.go:558
 msgid "The specified device doesn't exist"
 msgstr ""
 
@@ -1276,7 +1280,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:685 lxc/storage.go:794
+#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:707 lxc/storage.go:820
 msgid "USED BY"
 msgstr ""
 
@@ -2035,7 +2039,7 @@ msgid ""
 "    Create a snapshot of \"u1\" called \"snap0\"."
 msgstr ""
 
-#: lxc/storage.go:64
+#: lxc/storage.go:65
 msgid ""
 "Usage: lxc storage <subcommand> [options]\n"
 "\n"
@@ -2110,7 +2114,14 @@ msgid ""
 "\n"
 "lxc storage volume detach-profile [<remote:>]<pool> <volume> <profile> "
 "[device name]\n"
-"    Detach a storage volume from the specified profile.\n"
+"\tDetach a storage volume from the specified profile.\n"
+"\n"
+"lxc storage volume copy [<pool>/]<volume> [<pool>/]<volume> [--config|-c "
+"<key=value>...]\n"
+"    Copy an existing volume to a new volume at the specified pool.\n"
+"\n"
+"lxc storage volume move [<pool>/]<volume> [<pool>/]<volume>\n"
+"    Move an existing volume to the specified pool.\n"
 "\n"
 "Unless specified through a prefix, all volume operations affect \"custom"
 "\" (user created) volumes.\n"
diff --git a/po/tr.po b/po/tr.po
index d39f14de5..5dbdaefe9 100644
--- a/po/tr.po
+++ b/po/tr.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: lxd\n"
 "Report-Msgid-Bugs-To: lxc-devel at lists.linuxcontainers.org\n"
-"POT-Creation-Date: 2018-01-11 17:16-0500\n"
+"POT-Creation-Date: 2018-01-16 11:17+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -16,7 +16,7 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: lxc/storage.go:33
+#: lxc/storage.go:34
 msgid ""
 "### This is a yaml representation of a storage pool.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -33,7 +33,7 @@ msgid ""
 "###   zfs.pool_name: default"
 msgstr ""
 
-#: lxc/storage.go:50
+#: lxc/storage.go:51
 msgid ""
 "### This is a yaml representation of a storage volume.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -288,7 +288,7 @@ msgstr ""
 msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
 
-#: lxc/profile.go:546 lxc/storage.go:653
+#: lxc/profile.go:546 lxc/storage.go:675
 msgid "Cannot provide container name to list"
 msgstr ""
 
@@ -313,8 +313,12 @@ msgstr ""
 msgid "Config key/value to apply to the new container"
 msgstr ""
 
+#: lxc/storage.go:158
+msgid "Config key/value to apply to the new storage volume"
+msgstr ""
+
 #: lxc/config.go:816 lxc/config.go:881 lxc/config.go:1331 lxc/image.go:1190
-#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:604 lxc/storage.go:979
+#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:626 lxc/storage.go:1058
 #, c-format
 msgid "Config parsing error: %s"
 msgstr ""
@@ -381,11 +385,11 @@ msgid "Creating the container"
 msgstr ""
 
 #: lxc/image.go:234 lxc/image.go:1137 lxc/list.go:465 lxc/network.go:525
-#: lxc/storage.go:682 lxc/storage.go:793
+#: lxc/storage.go:704 lxc/storage.go:819
 msgid "DESCRIPTION"
 msgstr ""
 
-#: lxc/storage.go:683
+#: lxc/storage.go:705
 msgid "DRIVER"
 msgstr ""
 
@@ -698,7 +702,7 @@ msgstr ""
 msgid "Missing summary."
 msgstr ""
 
-#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:402 lxc/storage.go:522
+#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:424 lxc/storage.go:544
 msgid "More than one device matches, specify the device name."
 msgstr ""
 
@@ -719,7 +723,7 @@ msgid "Must supply container name for: "
 msgstr ""
 
 #: lxc/list.go:467 lxc/network.go:522 lxc/profile.go:573 lxc/remote.go:409
-#: lxc/storage.go:681 lxc/storage.go:792
+#: lxc/storage.go:703 lxc/storage.go:818
 msgid "NAME"
 msgstr ""
 
@@ -767,7 +771,7 @@ msgstr ""
 msgid "No device found for this network"
 msgstr ""
 
-#: lxc/storage.go:411 lxc/storage.go:531
+#: lxc/storage.go:433 lxc/storage.go:553
 msgid "No device found for this storage volume."
 msgstr ""
 
@@ -775,7 +779,7 @@ msgstr ""
 msgid "No fingerprint specified."
 msgstr ""
 
-#: lxc/storage.go:355 lxc/storage.go:448
+#: lxc/storage.go:377 lxc/storage.go:470
 msgid "Only \"custom\" volumes can be attached to containers."
 msgstr ""
 
@@ -857,7 +861,7 @@ msgstr ""
 msgid "Pid: %d"
 msgstr ""
 
-#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:605 lxc/storage.go:980
+#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:627 lxc/storage.go:1059
 msgid "Press enter to open the editor again"
 msgstr ""
 
@@ -966,7 +970,7 @@ msgstr ""
 msgid "Remove %s (yes/no): "
 msgstr ""
 
-#: lxc/storage.go:1011
+#: lxc/storage.go:1090
 #, c-format
 msgid "Renamed storage volume from \"%s\" to \"%s\""
 msgstr ""
@@ -1004,7 +1008,7 @@ msgstr ""
 msgid "SNAPSHOTS"
 msgstr ""
 
-#: lxc/storage.go:684
+#: lxc/storage.go:706
 msgid "SOURCE"
 msgstr ""
 
@@ -1072,7 +1076,7 @@ msgstr ""
 msgid "Show the resources available to the server"
 msgstr ""
 
-#: lxc/storage.go:151
+#: lxc/storage.go:159
 msgid "Show the resources available to the storage pool"
 msgstr ""
 
@@ -1125,12 +1129,12 @@ msgstr ""
 msgid "Stopping the container failed: %s"
 msgstr ""
 
-#: lxc/storage.go:496
+#: lxc/storage.go:518
 #, c-format
 msgid "Storage pool %s created"
 msgstr ""
 
-#: lxc/storage.go:555
+#: lxc/storage.go:577
 #, c-format
 msgid "Storage pool %s deleted"
 msgstr ""
@@ -1139,12 +1143,12 @@ msgstr ""
 msgid "Storage pool name"
 msgstr ""
 
-#: lxc/storage.go:826
+#: lxc/storage.go:852
 #, c-format
 msgid "Storage volume %s created"
 msgstr ""
 
-#: lxc/storage.go:841
+#: lxc/storage.go:867
 #, c-format
 msgid "Storage volume %s deleted"
 msgstr ""
@@ -1161,7 +1165,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:791
+#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:817
 msgid "TYPE"
 msgstr ""
 
@@ -1197,7 +1201,7 @@ msgstr ""
 msgid "The opposite of \"lxc pause\" is \"lxc start\"."
 msgstr ""
 
-#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:416 lxc/storage.go:536
+#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:438 lxc/storage.go:558
 msgid "The specified device doesn't exist"
 msgstr ""
 
@@ -1276,7 +1280,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:685 lxc/storage.go:794
+#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:707 lxc/storage.go:820
 msgid "USED BY"
 msgstr ""
 
@@ -2035,7 +2039,7 @@ msgid ""
 "    Create a snapshot of \"u1\" called \"snap0\"."
 msgstr ""
 
-#: lxc/storage.go:64
+#: lxc/storage.go:65
 msgid ""
 "Usage: lxc storage <subcommand> [options]\n"
 "\n"
@@ -2110,7 +2114,14 @@ msgid ""
 "\n"
 "lxc storage volume detach-profile [<remote:>]<pool> <volume> <profile> "
 "[device name]\n"
-"    Detach a storage volume from the specified profile.\n"
+"\tDetach a storage volume from the specified profile.\n"
+"\n"
+"lxc storage volume copy [<pool>/]<volume> [<pool>/]<volume> [--config|-c "
+"<key=value>...]\n"
+"    Copy an existing volume to a new volume at the specified pool.\n"
+"\n"
+"lxc storage volume move [<pool>/]<volume> [<pool>/]<volume>\n"
+"    Move an existing volume to the specified pool.\n"
 "\n"
 "Unless specified through a prefix, all volume operations affect \"custom"
 "\" (user created) volumes.\n"
diff --git a/po/zh.po b/po/zh.po
index 68969e136..2b1d8ee9b 100644
--- a/po/zh.po
+++ b/po/zh.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: lxd\n"
 "Report-Msgid-Bugs-To: lxc-devel at lists.linuxcontainers.org\n"
-"POT-Creation-Date: 2018-01-11 17:16-0500\n"
+"POT-Creation-Date: 2018-01-16 11:17+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -16,7 +16,7 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: lxc/storage.go:33
+#: lxc/storage.go:34
 msgid ""
 "### This is a yaml representation of a storage pool.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -33,7 +33,7 @@ msgid ""
 "###   zfs.pool_name: default"
 msgstr ""
 
-#: lxc/storage.go:50
+#: lxc/storage.go:51
 msgid ""
 "### This is a yaml representation of a storage volume.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -288,7 +288,7 @@ msgstr ""
 msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
 
-#: lxc/profile.go:546 lxc/storage.go:653
+#: lxc/profile.go:546 lxc/storage.go:675
 msgid "Cannot provide container name to list"
 msgstr ""
 
@@ -313,8 +313,12 @@ msgstr ""
 msgid "Config key/value to apply to the new container"
 msgstr ""
 
+#: lxc/storage.go:158
+msgid "Config key/value to apply to the new storage volume"
+msgstr ""
+
 #: lxc/config.go:816 lxc/config.go:881 lxc/config.go:1331 lxc/image.go:1190
-#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:604 lxc/storage.go:979
+#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:626 lxc/storage.go:1058
 #, c-format
 msgid "Config parsing error: %s"
 msgstr ""
@@ -381,11 +385,11 @@ msgid "Creating the container"
 msgstr ""
 
 #: lxc/image.go:234 lxc/image.go:1137 lxc/list.go:465 lxc/network.go:525
-#: lxc/storage.go:682 lxc/storage.go:793
+#: lxc/storage.go:704 lxc/storage.go:819
 msgid "DESCRIPTION"
 msgstr ""
 
-#: lxc/storage.go:683
+#: lxc/storage.go:705
 msgid "DRIVER"
 msgstr ""
 
@@ -698,7 +702,7 @@ msgstr ""
 msgid "Missing summary."
 msgstr ""
 
-#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:402 lxc/storage.go:522
+#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:424 lxc/storage.go:544
 msgid "More than one device matches, specify the device name."
 msgstr ""
 
@@ -719,7 +723,7 @@ msgid "Must supply container name for: "
 msgstr ""
 
 #: lxc/list.go:467 lxc/network.go:522 lxc/profile.go:573 lxc/remote.go:409
-#: lxc/storage.go:681 lxc/storage.go:792
+#: lxc/storage.go:703 lxc/storage.go:818
 msgid "NAME"
 msgstr ""
 
@@ -767,7 +771,7 @@ msgstr ""
 msgid "No device found for this network"
 msgstr ""
 
-#: lxc/storage.go:411 lxc/storage.go:531
+#: lxc/storage.go:433 lxc/storage.go:553
 msgid "No device found for this storage volume."
 msgstr ""
 
@@ -775,7 +779,7 @@ msgstr ""
 msgid "No fingerprint specified."
 msgstr ""
 
-#: lxc/storage.go:355 lxc/storage.go:448
+#: lxc/storage.go:377 lxc/storage.go:470
 msgid "Only \"custom\" volumes can be attached to containers."
 msgstr ""
 
@@ -857,7 +861,7 @@ msgstr ""
 msgid "Pid: %d"
 msgstr ""
 
-#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:605 lxc/storage.go:980
+#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:627 lxc/storage.go:1059
 msgid "Press enter to open the editor again"
 msgstr ""
 
@@ -966,7 +970,7 @@ msgstr ""
 msgid "Remove %s (yes/no): "
 msgstr ""
 
-#: lxc/storage.go:1011
+#: lxc/storage.go:1090
 #, c-format
 msgid "Renamed storage volume from \"%s\" to \"%s\""
 msgstr ""
@@ -1004,7 +1008,7 @@ msgstr ""
 msgid "SNAPSHOTS"
 msgstr ""
 
-#: lxc/storage.go:684
+#: lxc/storage.go:706
 msgid "SOURCE"
 msgstr ""
 
@@ -1072,7 +1076,7 @@ msgstr ""
 msgid "Show the resources available to the server"
 msgstr ""
 
-#: lxc/storage.go:151
+#: lxc/storage.go:159
 msgid "Show the resources available to the storage pool"
 msgstr ""
 
@@ -1125,12 +1129,12 @@ msgstr ""
 msgid "Stopping the container failed: %s"
 msgstr ""
 
-#: lxc/storage.go:496
+#: lxc/storage.go:518
 #, c-format
 msgid "Storage pool %s created"
 msgstr ""
 
-#: lxc/storage.go:555
+#: lxc/storage.go:577
 #, c-format
 msgid "Storage pool %s deleted"
 msgstr ""
@@ -1139,12 +1143,12 @@ msgstr ""
 msgid "Storage pool name"
 msgstr ""
 
-#: lxc/storage.go:826
+#: lxc/storage.go:852
 #, c-format
 msgid "Storage volume %s created"
 msgstr ""
 
-#: lxc/storage.go:841
+#: lxc/storage.go:867
 #, c-format
 msgid "Storage volume %s deleted"
 msgstr ""
@@ -1161,7 +1165,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:791
+#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:817
 msgid "TYPE"
 msgstr ""
 
@@ -1197,7 +1201,7 @@ msgstr ""
 msgid "The opposite of \"lxc pause\" is \"lxc start\"."
 msgstr ""
 
-#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:416 lxc/storage.go:536
+#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:438 lxc/storage.go:558
 msgid "The specified device doesn't exist"
 msgstr ""
 
@@ -1276,7 +1280,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:685 lxc/storage.go:794
+#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:707 lxc/storage.go:820
 msgid "USED BY"
 msgstr ""
 
@@ -2035,7 +2039,7 @@ msgid ""
 "    Create a snapshot of \"u1\" called \"snap0\"."
 msgstr ""
 
-#: lxc/storage.go:64
+#: lxc/storage.go:65
 msgid ""
 "Usage: lxc storage <subcommand> [options]\n"
 "\n"
@@ -2110,7 +2114,14 @@ msgid ""
 "\n"
 "lxc storage volume detach-profile [<remote:>]<pool> <volume> <profile> "
 "[device name]\n"
-"    Detach a storage volume from the specified profile.\n"
+"\tDetach a storage volume from the specified profile.\n"
+"\n"
+"lxc storage volume copy [<pool>/]<volume> [<pool>/]<volume> [--config|-c "
+"<key=value>...]\n"
+"    Copy an existing volume to a new volume at the specified pool.\n"
+"\n"
+"lxc storage volume move [<pool>/]<volume> [<pool>/]<volume>\n"
+"    Move an existing volume to the specified pool.\n"
 "\n"
 "Unless specified through a prefix, all volume operations affect \"custom"
 "\" (user created) volumes.\n"
diff --git a/po/zh_Hans.po b/po/zh_Hans.po
index 44a51efcf..6970e1015 100644
--- a/po/zh_Hans.po
+++ b/po/zh_Hans.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: lxd\n"
 "Report-Msgid-Bugs-To: lxc-devel at lists.linuxcontainers.org\n"
-"POT-Creation-Date: 2018-01-11 17:16-0500\n"
+"POT-Creation-Date: 2018-01-16 11:17+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -16,7 +16,7 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: lxc/storage.go:33
+#: lxc/storage.go:34
 msgid ""
 "### This is a yaml representation of a storage pool.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -33,7 +33,7 @@ msgid ""
 "###   zfs.pool_name: default"
 msgstr ""
 
-#: lxc/storage.go:50
+#: lxc/storage.go:51
 msgid ""
 "### This is a yaml representation of a storage volume.\n"
 "### Any line starting with a '# will be ignored.\n"
@@ -288,7 +288,7 @@ msgstr ""
 msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
 
-#: lxc/profile.go:546 lxc/storage.go:653
+#: lxc/profile.go:546 lxc/storage.go:675
 msgid "Cannot provide container name to list"
 msgstr ""
 
@@ -313,8 +313,12 @@ msgstr ""
 msgid "Config key/value to apply to the new container"
 msgstr ""
 
+#: lxc/storage.go:158
+msgid "Config key/value to apply to the new storage volume"
+msgstr ""
+
 #: lxc/config.go:816 lxc/config.go:881 lxc/config.go:1331 lxc/image.go:1190
-#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:604 lxc/storage.go:979
+#: lxc/network.go:426 lxc/profile.go:275 lxc/storage.go:626 lxc/storage.go:1058
 #, c-format
 msgid "Config parsing error: %s"
 msgstr ""
@@ -381,11 +385,11 @@ msgid "Creating the container"
 msgstr ""
 
 #: lxc/image.go:234 lxc/image.go:1137 lxc/list.go:465 lxc/network.go:525
-#: lxc/storage.go:682 lxc/storage.go:793
+#: lxc/storage.go:704 lxc/storage.go:819
 msgid "DESCRIPTION"
 msgstr ""
 
-#: lxc/storage.go:683
+#: lxc/storage.go:705
 msgid "DRIVER"
 msgstr ""
 
@@ -698,7 +702,7 @@ msgstr ""
 msgid "Missing summary."
 msgstr ""
 
-#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:402 lxc/storage.go:522
+#: lxc/network.go:284 lxc/network.go:337 lxc/storage.go:424 lxc/storage.go:544
 msgid "More than one device matches, specify the device name."
 msgstr ""
 
@@ -719,7 +723,7 @@ msgid "Must supply container name for: "
 msgstr ""
 
 #: lxc/list.go:467 lxc/network.go:522 lxc/profile.go:573 lxc/remote.go:409
-#: lxc/storage.go:681 lxc/storage.go:792
+#: lxc/storage.go:703 lxc/storage.go:818
 msgid "NAME"
 msgstr ""
 
@@ -767,7 +771,7 @@ msgstr ""
 msgid "No device found for this network"
 msgstr ""
 
-#: lxc/storage.go:411 lxc/storage.go:531
+#: lxc/storage.go:433 lxc/storage.go:553
 msgid "No device found for this storage volume."
 msgstr ""
 
@@ -775,7 +779,7 @@ msgstr ""
 msgid "No fingerprint specified."
 msgstr ""
 
-#: lxc/storage.go:355 lxc/storage.go:448
+#: lxc/storage.go:377 lxc/storage.go:470
 msgid "Only \"custom\" volumes can be attached to containers."
 msgstr ""
 
@@ -857,7 +861,7 @@ msgstr ""
 msgid "Pid: %d"
 msgstr ""
 
-#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:605 lxc/storage.go:980
+#: lxc/network.go:427 lxc/profile.go:276 lxc/storage.go:627 lxc/storage.go:1059
 msgid "Press enter to open the editor again"
 msgstr ""
 
@@ -966,7 +970,7 @@ msgstr ""
 msgid "Remove %s (yes/no): "
 msgstr ""
 
-#: lxc/storage.go:1011
+#: lxc/storage.go:1090
 #, c-format
 msgid "Renamed storage volume from \"%s\" to \"%s\""
 msgstr ""
@@ -1004,7 +1008,7 @@ msgstr ""
 msgid "SNAPSHOTS"
 msgstr ""
 
-#: lxc/storage.go:684
+#: lxc/storage.go:706
 msgid "SOURCE"
 msgstr ""
 
@@ -1072,7 +1076,7 @@ msgstr ""
 msgid "Show the resources available to the server"
 msgstr ""
 
-#: lxc/storage.go:151
+#: lxc/storage.go:159
 msgid "Show the resources available to the storage pool"
 msgstr ""
 
@@ -1125,12 +1129,12 @@ msgstr ""
 msgid "Stopping the container failed: %s"
 msgstr ""
 
-#: lxc/storage.go:496
+#: lxc/storage.go:518
 #, c-format
 msgid "Storage pool %s created"
 msgstr ""
 
-#: lxc/storage.go:555
+#: lxc/storage.go:577
 #, c-format
 msgid "Storage pool %s deleted"
 msgstr ""
@@ -1139,12 +1143,12 @@ msgstr ""
 msgid "Storage pool name"
 msgstr ""
 
-#: lxc/storage.go:826
+#: lxc/storage.go:852
 #, c-format
 msgid "Storage volume %s created"
 msgstr ""
 
-#: lxc/storage.go:841
+#: lxc/storage.go:867
 #, c-format
 msgid "Storage volume %s deleted"
 msgstr ""
@@ -1161,7 +1165,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:791
+#: lxc/list.go:473 lxc/network.go:523 lxc/operation.go:153 lxc/storage.go:817
 msgid "TYPE"
 msgstr ""
 
@@ -1197,7 +1201,7 @@ msgstr ""
 msgid "The opposite of \"lxc pause\" is \"lxc start\"."
 msgstr ""
 
-#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:416 lxc/storage.go:536
+#: lxc/network.go:298 lxc/network.go:351 lxc/storage.go:438 lxc/storage.go:558
 msgid "The specified device doesn't exist"
 msgstr ""
 
@@ -1276,7 +1280,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:685 lxc/storage.go:794
+#: lxc/network.go:526 lxc/profile.go:574 lxc/storage.go:707 lxc/storage.go:820
 msgid "USED BY"
 msgstr ""
 
@@ -2035,7 +2039,7 @@ msgid ""
 "    Create a snapshot of \"u1\" called \"snap0\"."
 msgstr ""
 
-#: lxc/storage.go:64
+#: lxc/storage.go:65
 msgid ""
 "Usage: lxc storage <subcommand> [options]\n"
 "\n"
@@ -2110,7 +2114,14 @@ msgid ""
 "\n"
 "lxc storage volume detach-profile [<remote:>]<pool> <volume> <profile> "
 "[device name]\n"
-"    Detach a storage volume from the specified profile.\n"
+"\tDetach a storage volume from the specified profile.\n"
+"\n"
+"lxc storage volume copy [<pool>/]<volume> [<pool>/]<volume> [--config|-c "
+"<key=value>...]\n"
+"    Copy an existing volume to a new volume at the specified pool.\n"
+"\n"
+"lxc storage volume move [<pool>/]<volume> [<pool>/]<volume>\n"
+"    Move an existing volume to the specified pool.\n"
 "\n"
 "Unless specified through a prefix, all volume operations affect \"custom"
 "\" (user created) volumes.\n"

From 11d7a8d22c8371187efd373af0b1dad967415aab Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Tue, 16 Jan 2018 11:16:46 +0100
Subject: [PATCH 09/10] doc: add "storage_api_local_volume_handling"

Closes #3984.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 doc/api-extensions.md | 4 ++++
 shared/version/api.go | 1 +
 2 files changed, 5 insertions(+)

diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index 1ba3db34d..614afbf88 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -395,3 +395,7 @@ getting a stream of events over websocket.
 ## proxy
 This adds a new `proxy` device type to containers, allowing forwarding
 of connections between the host and container.
+
+## storage\_api\_local\_volume\_handling
+This add the ability to copy and move custom storage volumes locally in the
+same and between storage pools.
diff --git a/shared/version/api.go b/shared/version/api.go
index feb31aab8..f292ff7e7 100644
--- a/shared/version/api.go
+++ b/shared/version/api.go
@@ -87,4 +87,5 @@ var APIExtensions = []string{
 	"maas_network",
 	"devlxd_events",
 	"proxy",
+	"storage_api_local_volume_handling",
 }

From adec77b53e1d7c1b41a419659be703becbc99305 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Tue, 16 Jan 2018 13:50:17 +0100
Subject: [PATCH 10/10] test: add local storage volume handling tests

Closes #3984.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 test/main.sh                                 |  1 +
 test/suites/storage_local_volume_handling.sh | 97 ++++++++++++++++++++++++++++
 2 files changed, 98 insertions(+)
 create mode 100644 test/suites/storage_local_volume_handling.sh

diff --git a/test/main.sh b/test/main.sh
index 0890f9d77..89f7a95ef 100755
--- a/test/main.sh
+++ b/test/main.sh
@@ -191,6 +191,7 @@ run_test test_kernel_limits "kernel limits"
 run_test test_macaroon_auth "macaroon authentication"
 run_test test_console "console"
 run_test test_proxy_device "proxy device"
+run_test test_storage_local_volume_handling "storage local volume handling"
 
 # shellcheck disable=SC2034
 TEST_RESULT=success
diff --git a/test/suites/storage_local_volume_handling.sh b/test/suites/storage_local_volume_handling.sh
new file mode 100644
index 000000000..35ed25d63
--- /dev/null
+++ b/test/suites/storage_local_volume_handling.sh
@@ -0,0 +1,97 @@
+test_storage_local_volume_handling() {
+  ensure_import_testimage
+
+  # shellcheck disable=2039
+  local LXD_STORAGE_DIR lxd_backend  
+
+  lxd_backend=$(storage_backend "$LXD_DIR")
+  LXD_STORAGE_DIR=$(mktemp -d -p "${TEST_DIR}" XXXXXXXXX)
+  chmod +x "${LXD_STORAGE_DIR}"
+  spawn_lxd "${LXD_STORAGE_DIR}" false
+
+  ensure_import_testimage
+
+  (
+    set -e
+    # shellcheck disable=2030
+    LXD_DIR="${LXD_STORAGE_DIR}"
+
+    if storage_backend_available "btrfs"; then
+      # Create loop file btrfs pool.
+      lxc storage create "lxdtest-$(basename "${LXD_DIR}")-btrfs" btrfs
+      # btrfs -> btrfs
+      lxc storage create "lxdtest-$(basename "${LXD_DIR}")-btrfs1" btrfs
+      lxc storage volume create "lxdtest-$(basename "${LXD_DIR}")-btrfs" vol1
+      lxc storage volume copy "lxdtest-$(basename "${LXD_DIR}")-btrfs/vol1" "lxdtest-$(basename "${LXD_DIR}")-btrfs1/vol1"
+      lxc storage volume delete "lxdtest-$(basename "${LXD_DIR}")-btrfs1 vol1"
+      lxc storage volume move "lxdtest-$(basename "${LXD_DIR}")-btrfs/vol1" "lxdtest-$(basename "${LXD_DIR}")-btrfs1/vol1"
+      ! lxc storage volume show "lxdtest-$(basename "${LXD_DIR}")-btrfs vol1"
+      lxc storage volume show "lxdtest-$(basename "${LXD_DIR}")-btrfs1 vol1"
+      lxc storage volume delete "lxdtest-$(basename "${LXD_DIR}")-btrfs1 vol1"
+      lxc storage delete "lxdtest-$(basename "${LXD_DIR}")-btrfs1"
+    fi
+
+    if storage_backend_available "ceph"; then
+      # Create dir pool.
+      lxc storage create "lxdtest-$(basename "${LXD_DIR}")-ceph" ceph
+      # ceph -> ceph
+      lxc storage create "lxdtest-$(basename "${LXD_DIR}")-ceph1" ceph
+      lxc storage volume create "lxdtest-$(basename "${LXD_DIR}")-ceph" vol1
+      lxc storage volume copy "lxdtest-$(basename "${LXD_DIR}")-ceph/vol1" "lxdtest-$(basename "${LXD_DIR}")-ceph1/vol1"
+      lxc storage volume delete "lxdtest-$(basename "${LXD_DIR}")-ceph1 vol1"
+      lxc storage volume move "lxdtest-$(basename "${LXD_DIR}")-ceph/vol1" "lxdtest-$(basename "${LXD_DIR}")-ceph1/vol1"
+      ! lxc storage volume show "lxdtest-$(basename "${LXD_DIR}")-ceph vol1"
+      lxc storage volume show "lxdtest-$(basename "${LXD_DIR}")-ceph1 vol1"
+      lxc storage volume delete "lxdtest-$(basename "${LXD_DIR}")-ceph1 vol1"
+      lxc storage delete "lxdtest-$(basename "${LXD_DIR}")-ceph1"
+    fi
+
+    # Create dir pool.
+    lxc storage create "lxdtest-$(basename "${LXD_DIR}")-dir" dir
+    # dir -> dir
+    lxc storage create "lxdtest-$(basename "${LXD_DIR}")-dir1" dir
+    lxc storage volume create "lxdtest-$(basename "${LXD_DIR}")-dir" vol1
+    lxc storage volume copy "lxdtest-$(basename "${LXD_DIR}")-dir/vol1" "lxdtest-$(basename "${LXD_DIR}")-dir1/vol1"
+    lxc storage volume delete "lxdtest-$(basename "${LXD_DIR}")-dir1 vol1"
+    lxc storage volume move "lxdtest-$(basename "${LXD_DIR}")-dir/vol1" "lxdtest-$(basename "${LXD_DIR}")-dir1/vol1"
+    ! lxc storage volume show "lxdtest-$(basename "${LXD_DIR}")-dir vol1"
+    lxc storage volume show "lxdtest-$(basename "${LXD_DIR}")-dir1 vol1"
+    lxc storage volume delete "lxdtest-$(basename "${LXD_DIR}")-dir1 vol1"
+    lxc storage delete "lxdtest-$(basename "${LXD_DIR}")-dir1"
+
+    if storage_backend_available "lvm"; then
+      # shellcheck disable=SC2154
+      lxc storage create "lxdtest-$(basename "${LXD_DIR}")-lvm" lvm volume.size=25MB
+      # lvm -> lvm
+      lxc storage create "lxdtest-$(basename "${LXD_DIR}")-lvm1" lvm
+      lxc storage volume create "lxdtest-$(basename "${LXD_DIR}")-lvm" vol1
+      lxc storage volume copy "lxdtest-$(basename "${LXD_DIR}")-lvm/vol1" "lxdtest-$(basename "${LXD_DIR}")-lvm1/vol1"
+      lxc storage volume delete "lxdtest-$(basename "${LXD_DIR}")-lvm1 vol1"
+      lxc storage volume move "lxdtest-$(basename "${LXD_DIR}")-lvm/vol1" "lxdtest-$(basename "${LXD_DIR}")-lvm1/vol1"
+      ! lxc storage volume show "lxdtest-$(basename "${LXD_DIR}")-lvm vol1"
+      lxc storage volume show "lxdtest-$(basename "${LXD_DIR}")-lvm1 vol1"
+      lxc storage volume delete "lxdtest-$(basename "${LXD_DIR}")-lvm1 vol1"
+      lxc storage delete "lxdtest-$(basename "${LXD_DIR}")-lvm1"
+    fi
+
+    # shellcheck disable=SC1009
+    if storage_backend_available "zfs"; then
+      # Create loop file zfs pool.
+      lxc storage create "lxdtest-$(basename "${LXD_DIR}")-zfs" zfs
+      # zfs -> zfs
+      lxc storage create "lxdtest-$(basename "${LXD_DIR}")-zfs1" zfs
+      lxc storage volume create "lxdtest-$(basename "${LXD_DIR}")-zfs" vol1
+      lxc storage volume copy "lxdtest-$(basename "${LXD_DIR}")-zfs/vol1" "lxdtest-$(basename "${LXD_DIR}")-zfs1/vol1"
+      lxc storage volume delete "lxdtest-$(basename "${LXD_DIR}")-zfs1 vol1"
+      lxc storage volume move "lxdtest-$(basename "${LXD_DIR}")-zfs/vol1" "lxdtest-$(basename "${LXD_DIR}")-zfs1/vol1"
+      ! lxc storage volume show "lxdtest-$(basename "${LXD_DIR}")-zfs vol1"
+      lxc storage volume show "lxdtest-$(basename "${LXD_DIR}")-zfs1 vol1"
+      lxc storage volume delete "lxdtest-$(basename "${LXD_DIR}")-zfs1 vol1"
+      lxc storage delete "lxdtest-$(basename "${LXD_DIR}")-zfs1"
+    fi
+  )
+
+  # shellcheck disable=SC2031
+  LXD_DIR="${LXD_DIR}"
+  kill_lxd "${LXD_STORAGE_DIR}"
+}


More information about the lxc-devel mailing list