[lxc-devel] [lxd/master] Storage: Custom volumes in Projects

tomponline on Github lxc-bot at linuxcontainers.org
Thu Mar 5 10:28:22 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 304 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200305/0f496480/attachment-0001.bin>
-------------- next part --------------
From 8ccf24fae9328e2d99cb45d0b759e2bf5f4111e2 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 09:21:26 +0000
Subject: [PATCH 01/40] lxd/project/project: Definition optimisation and
 comment tweak to Instance()

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/project/project.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lxd/project/project.go b/lxd/project/project.go
index 89882a526c..2b5d208c64 100644
--- a/lxd/project/project.go
+++ b/lxd/project/project.go
@@ -11,8 +11,8 @@ const Default = "default"
 // separator is used to delimit the project name from the suffix.
 const separator = "_"
 
-// Instance Adds the "<project>_" prefix to instance name when the given project name is not "default".
-func Instance(projectName string, instanceName string) string {
+// Instance adds the "<project>_" prefix to instance name when the given project name is not "default".
+func Instance(projectName, instanceName string) string {
 	if projectName != Default {
 		return fmt.Sprintf("%s%s%s", projectName, separator, instanceName)
 	}

From 3bad7b04022c5487236b8ac3a41eed8057121f57 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 09:21:59 +0000
Subject: [PATCH 02/40] lxd/project/project: Adds StorageVolume()

This function always prefixes the project name, even if it is default.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/project/project.go | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lxd/project/project.go b/lxd/project/project.go
index 2b5d208c64..bb6823d4fc 100644
--- a/lxd/project/project.go
+++ b/lxd/project/project.go
@@ -36,3 +36,8 @@ func InstanceParts(projectInstanceName string) (string, string) {
 	// Instance names are not allowed to container the separator value.
 	return projectInstanceName[0:i], projectInstanceName[i+1:]
 }
+
+// StorageVolume adds the "<project>_prefix" to the storage volume name. Even if the project name is "default".
+func StorageVolume(projectName, storageVolumeName string) string {
+	return fmt.Sprintf("%s%s%s", projectName, separator, storageVolumeName)
+}

From c01e6e69f6746d5ea733b6b635e2916229690934 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 09:22:54 +0000
Subject: [PATCH 03/40] lxd/project/project/test: Adds StorageVolume() test

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/project/project_test.go | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/lxd/project/project_test.go b/lxd/project/project_test.go
index f5f7709072..43532a9f3b 100644
--- a/lxd/project/project_test.go
+++ b/lxd/project/project_test.go
@@ -34,3 +34,13 @@ func ExampleInstanceParts() {
 	// project_name test
 	// proj test1
 }
+
+func ExampleStorageVolume() {
+	prefixed := project.StorageVolume(project.Default, "test")
+	fmt.Println(prefixed)
+
+	prefixed = project.StorageVolume("project_name", "test1")
+	fmt.Println(prefixed)
+	// Output: default_test
+	// project_name_test1
+}

From cc2c722b7e2b6fe1bb102309e8e28843ee2f0392 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 09:34:05 +0000
Subject: [PATCH 04/40] lxd/project: Adds STORAGE VOLUMES col to projects list

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxc/project.go | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/lxc/project.go b/lxc/project.go
index ab88b31839..3a9b89cd27 100644
--- a/lxc/project.go
+++ b/lxc/project.go
@@ -435,13 +435,18 @@ func (c *cmdProjectList) Run(cmd *cobra.Command, args []string) error {
 			profiles = i18n.G("YES")
 		}
 
+		storageVolumes := i18n.G("NO")
+		if project.Config["features.storage.volumes"] == "true" {
+			storageVolumes = i18n.G("YES")
+		}
+
 		name := project.Name
 		if name == currentProject {
 			name = fmt.Sprintf("%s (%s)", name, i18n.G("current"))
 		}
 
 		strUsedBy := fmt.Sprintf("%d", len(project.UsedBy))
-		data = append(data, []string{name, images, profiles, strUsedBy})
+		data = append(data, []string{name, images, profiles, storageVolumes, strUsedBy})
 	}
 	sort.Sort(byName(data))
 
@@ -449,6 +454,7 @@ func (c *cmdProjectList) Run(cmd *cobra.Command, args []string) error {
 		i18n.G("NAME"),
 		i18n.G("IMAGES"),
 		i18n.G("PROFILES"),
+		i18n.G("STORAGE VOLUMES"),
 		i18n.G("USED BY"),
 	}
 

From fa45cff8ffd1b7218fa06fac0435184a51a8a632 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 09:36:08 +0000
Subject: [PATCH 05/40] doc/projects: Documents features.storage.volumes flag

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 doc/projects.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/doc/projects.md b/doc/projects.md
index 0be2809205..81dcefbed0 100644
--- a/doc/projects.md
+++ b/doc/projects.md
@@ -19,6 +19,7 @@ Key                             | Type      | Condition             | Default
 :--                             | :--       | :--                   | :--                       | :--
 features.images                 | boolean   | -                     | true                      | Separate set of images and image aliases for the project
 features.profiles               | boolean   | -                     | true                      | Separate set of profiles for the project
+features.storage.volumes        | boolean   | -                     | true                      | Separate set of storage volumes for the project
 limits.containers               | integer   | -                     | -                         | Maximum number of containers that can be created in the project
 limits.virtual-machines         | integer   | -                     | -                         | Maximum number of VMs that can be created in the project
 limits.cpu                      | integer   | -                     | -                         | Maximum value for the sum of individual "limits.cpu" configs set on the instances of the project

From f3994549e1895b33800e1b175d1e46c92ec9e7f1 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 10:17:51 +0000
Subject: [PATCH 06/40] lxd/api/project: Adds features.storage.volumes to API

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/api_project.go | 40 +++++++++++++++++++++++-----------------
 1 file changed, 23 insertions(+), 17 deletions(-)

diff --git a/lxd/api_project.go b/lxd/api_project.go
index 32c0ce17b7..66899b6072 100644
--- a/lxd/api_project.go
+++ b/lxd/api_project.go
@@ -21,6 +21,8 @@ import (
 	"github.com/lxc/lxd/shared/version"
 )
 
+var projectFeatures = []string{"features.images", "features.profiles", "features.storage.volumes"}
+
 var projectsCmd = APIEndpoint{
 	Path: "projects",
 
@@ -97,7 +99,7 @@ func projectsPost(d *Daemon, r *http.Request) response.Response {
 	if project.Config == nil {
 		project.Config = map[string]string{}
 	}
-	for _, feature := range []string{"features.images", "features.profiles"} {
+	for _, feature := range projectFeatures {
 		_, ok := project.Config[feature]
 		if !ok {
 			project.Config[feature] = "true"
@@ -336,12 +338,16 @@ func projectChange(d *Daemon, project *api.Project, req api.ProjectPut) response
 		}
 	}
 
-	keyHasChanged := func(key string) bool { return shared.StringInSlice(key, configChanged) }
-
 	// Flag indicating if any feature has changed.
-	featuresChanged := keyHasChanged("features.images") || keyHasChanged("features.profiles")
+	featuresChanged := false
+	for _, featureKey := range projectFeatures {
+		if shared.StringInSlice(featureKey, configChanged) {
+			featuresChanged = true
+			break
+		}
+	}
 
-	// Sanity checks
+	// Sanity checks.
 	if project.Name == "default" && featuresChanged {
 		return response.BadRequest(fmt.Errorf("You can't change the features of the default project"))
 	}
@@ -350,13 +356,13 @@ func projectChange(d *Daemon, project *api.Project, req api.ProjectPut) response
 		return response.BadRequest(fmt.Errorf("Features can only be changed on empty projects"))
 	}
 
-	// Validate the configuration
+	// Validate the configuration.
 	err := projectValidateConfig(req.Config)
 	if err != nil {
 		return response.BadRequest(err)
 	}
 
-	// Update the database entry
+	// Update the database entry.
 	err = d.cluster.Transaction(func(tx *db.ClusterTx) error {
 		err := projecthelpers.ValidateLimitsUponProjectUpdate(tx, project.Name, req.Config, configChanged)
 		if err != nil {
@@ -368,7 +374,7 @@ func projectChange(d *Daemon, project *api.Project, req api.ProjectPut) response
 			return errors.Wrap(err, "Persist profile changes")
 		}
 
-		if keyHasChanged("features.profiles") {
+		if shared.StringInSlice("features.profiles", configChanged) {
 			if req.Config["features.profiles"] == "true" {
 				err = projectCreateDefaultProfile(tx, project.Name)
 				if err != nil {
@@ -384,7 +390,6 @@ func projectChange(d *Daemon, project *api.Project, req api.ProjectPut) response
 		}
 
 		return nil
-
 	})
 
 	if err != nil {
@@ -513,15 +518,16 @@ func projectIsEmpty(project *api.Project) bool {
 	return true
 }
 
-// Validate the project configuration
+// Validate the project configuration.
 var projectConfigKeys = map[string]func(value string) error{
-	"features.profiles":       shared.IsBool,
-	"features.images":         shared.IsBool,
-	"limits.containers":       shared.IsUint32,
-	"limits.virtual-machines": shared.IsUint32,
-	"limits.memory":           shared.IsSize,
-	"limits.processes":        shared.IsUint32,
-	"limits.cpu":              shared.IsUint32,
+	"features.profiles":        shared.IsBool,
+	"features.images":          shared.IsBool,
+	"features.storage.volumes": shared.IsBool,
+	"limits.containers":        shared.IsUint32,
+	"limits.virtual-machines":  shared.IsUint32,
+	"limits.memory":            shared.IsSize,
+	"limits.processes":         shared.IsUint32,
+	"limits.cpu":               shared.IsUint32,
 }
 
 func projectValidateConfig(config map[string]string) error {

From 1346d09611bf9c0d711af44a56e9cedc422f10d7 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 10:21:16 +0000
Subject: [PATCH 07/40] lxd/db/migration: Adds features.storage.volumes true to
 default project on importPreClusteringData

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/db/migration.go | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lxd/db/migration.go b/lxd/db/migration.go
index 12d4624da0..83d77a633a 100644
--- a/lxd/db/migration.go
+++ b/lxd/db/migration.go
@@ -125,6 +125,7 @@ INSERT INTO nodes(id, name, address, schema, api_extensions) VALUES(1, 'none', '
 INSERT INTO projects (name, description) VALUES ('default', 'Default LXD project');
 INSERT INTO projects_config (project_id, key, value) VALUES (1, 'features.images', 'true');
 INSERT INTO projects_config (project_id, key, value) VALUES (1, 'features.profiles', 'true');
+INSERT INTO projects_config (project_id, key, value) VALUES (1, 'features.storage.volumes', 'true');
 `
 	_, err = tx.Exec(stmt)
 	if err != nil {

From 30799aa682aa7bab69914578e2061d1194238d57 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 10:22:05 +0000
Subject: [PATCH 08/40] lxd/db/cluster/open: Adds features.storage.volumes true
 to default project in EnsureSchema

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/db/cluster/open.go | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lxd/db/cluster/open.go b/lxd/db/cluster/open.go
index 0ce55f6a0b..23b4f9b662 100644
--- a/lxd/db/cluster/open.go
+++ b/lxd/db/cluster/open.go
@@ -184,6 +184,7 @@ INSERT INTO nodes(id, name, address, schema, api_extensions, arch) VALUES(1, 'no
 INSERT INTO projects (name, description) VALUES ('default', 'Default LXD project');
 INSERT INTO projects_config (project_id, key, value) VALUES (1, 'features.images', 'true');
 INSERT INTO projects_config (project_id, key, value) VALUES (1, 'features.profiles', 'true');
+INSERT INTO projects_config (project_id, key, value) VALUES (1, 'features.storage.volumes', 'true');
 `
 			_, err = tx.Exec(stmt)
 			if err != nil {

From 768f4baa21fde8da4054a51e832c55c3a5970a4b Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 10:23:52 +0000
Subject: [PATCH 09/40] scripts/bash/lxd-client: Adds features.storage.volumes
 to bash autocomplete

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 scripts/bash/lxd-client | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/bash/lxd-client b/scripts/bash/lxd-client
index a60d27900e..4566aba538 100644
--- a/scripts/bash/lxd-client
+++ b/scripts/bash/lxd-client
@@ -130,7 +130,7 @@ _have lxc && {
       ipv6.dhcp.stateful ipv6.firewall ipv6.nat ipv6.nat.address ipv6.nat.order \
       ipv6.routes ipv6.routing raw.dnsmasq"
 
-    project_keys="features.images features.profiles"
+    project_keys="features.images features.profiles features.storage.volumes"
 
     storage_pool_keys="source size btrfs.mount_options ceph.cluster_name \
       ceph.osd.force_reuse ceph.osd.pg_num ceph.osd.pool_name ceph.osd.data_pool_name \

From e1cdd2c76ae91acd72681e917a235332d090275f Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 10:28:28 +0000
Subject: [PATCH 10/40] i18n: Update translation templates

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 po/bg.po      | 52 +++++++++++++++++++++++++++-----------------------
 po/de.po      | 52 +++++++++++++++++++++++++++-----------------------
 po/el.po      | 52 +++++++++++++++++++++++++++-----------------------
 po/es.po      | 52 +++++++++++++++++++++++++++-----------------------
 po/fa.po      | 52 +++++++++++++++++++++++++++-----------------------
 po/fi.po      | 52 +++++++++++++++++++++++++++-----------------------
 po/fr.po      | 53 ++++++++++++++++++++++++++++-----------------------
 po/hi.po      | 52 +++++++++++++++++++++++++++-----------------------
 po/id.po      | 52 +++++++++++++++++++++++++++-----------------------
 po/it.po      | 52 +++++++++++++++++++++++++++-----------------------
 po/ja.po      | 52 +++++++++++++++++++++++++++-----------------------
 po/ko.po      | 52 +++++++++++++++++++++++++++-----------------------
 po/lxd.pot    | 50 ++++++++++++++++++++++++++----------------------
 po/nb_NO.po   | 52 +++++++++++++++++++++++++++-----------------------
 po/nl.po      | 52 +++++++++++++++++++++++++++-----------------------
 po/pa.po      | 52 +++++++++++++++++++++++++++-----------------------
 po/pl.po      | 52 +++++++++++++++++++++++++++-----------------------
 po/pt_BR.po   | 52 +++++++++++++++++++++++++++-----------------------
 po/ru.po      | 52 +++++++++++++++++++++++++++-----------------------
 po/sl.po      | 52 +++++++++++++++++++++++++++-----------------------
 po/sr.po      | 52 +++++++++++++++++++++++++++-----------------------
 po/sv.po      | 52 +++++++++++++++++++++++++++-----------------------
 po/te.po      | 52 +++++++++++++++++++++++++++-----------------------
 po/tr.po      | 52 +++++++++++++++++++++++++++-----------------------
 po/uk.po      | 52 +++++++++++++++++++++++++++-----------------------
 po/zh_Hans.po | 52 +++++++++++++++++++++++++++-----------------------
 26 files changed, 728 insertions(+), 623 deletions(-)

diff --git a/po/bg.po b/po/bg.po
index 25ca7c6bba..614766228a 100644
--- a/po/bg.po
+++ b/po/bg.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: 2020-02-26 08:16-0500\n"
+"POT-Creation-Date: 2020-03-04 10:28+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -860,8 +860,8 @@ msgstr ""
 #: lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712
 #: lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29
 #: lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334
-#: lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584
-#: lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31
+#: lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590
+#: lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31
 #: lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455
 #: lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685
 #: lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33
@@ -1308,7 +1308,7 @@ msgstr ""
 msgid "ID: %s"
 msgstr ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid "IMAGES"
 msgstr ""
 
@@ -1921,7 +1921,7 @@ msgid "Missing profile name"
 msgstr ""
 
 #: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358
-#: lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 msgid "Missing project name"
 msgstr ""
 
@@ -1997,7 +1997,7 @@ msgid "Must supply instance name for: "
 msgstr ""
 
 #: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620
-#: lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558
+#: lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558
 #: lxc/storage_volume.go:1118
 msgid "NAME"
 msgstr ""
@@ -2011,7 +2011,7 @@ msgid "NICs:"
 msgstr ""
 
 #: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428
-#: lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid "NO"
 msgstr ""
 
@@ -2155,7 +2155,7 @@ msgstr ""
 msgid "PROCESSES"
 msgstr ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid "PROFILES"
 msgstr ""
 
@@ -2313,7 +2313,7 @@ msgstr ""
 msgid "Project %s deleted"
 msgstr ""
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, c-format
 msgid "Project %s renamed to %s"
 msgstr ""
@@ -2390,7 +2390,7 @@ msgstr ""
 msgid "Remote %s already exists"
 msgstr ""
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
 #: lxc/remote.go:705
 #, c-format
 msgid "Remote %s doesn't exist"
@@ -2474,7 +2474,7 @@ msgstr ""
 msgid "Rename profiles"
 msgstr ""
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 msgid "Rename projects"
 msgstr ""
 
@@ -2579,6 +2579,10 @@ msgstr ""
 msgid "STORAGE POOL"
 msgstr ""
 
+#: lxc/project.go:457
+msgid "STORAGE VOLUMES"
+msgstr ""
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid "Send a raw query to LXD"
 msgstr ""
@@ -2665,11 +2669,11 @@ msgid ""
 "    lxc profile set [<remote>:]<profile> <key> <value>"
 msgstr ""
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 msgid "Set project configuration keys"
 msgstr ""
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid ""
 "Set project configuration keys\n"
 "\n"
@@ -2776,7 +2780,7 @@ msgstr ""
 msgid "Show profile configurations"
 msgstr ""
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 msgid "Show project options"
 msgstr ""
 
@@ -2951,7 +2955,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 msgid "Switch the current project"
 msgstr ""
 
@@ -3134,7 +3138,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567
 #: lxc/storage_volume.go:1120
 msgid "USED BY"
 msgstr ""
@@ -3179,7 +3183,7 @@ msgstr ""
 msgid "Unset profile configuration keys"
 msgstr ""
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 msgid "Unset project configuration keys"
 msgstr ""
 
@@ -3274,7 +3278,7 @@ msgid "Whether or not to snapshot the instance's running state"
 msgstr ""
 
 #: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430
-#: lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid "YES"
 msgstr ""
 
@@ -3398,7 +3402,7 @@ msgstr ""
 msgid "create [<remote>:]<project>"
 msgstr ""
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 msgid "current"
 msgstr ""
 
@@ -4037,7 +4041,7 @@ msgstr ""
 msgid "rename [<remote>:]<profile> <new-name>"
 msgstr ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid "rename [<remote>:]<project> <new-name>"
 msgstr ""
 
@@ -4073,7 +4077,7 @@ msgstr ""
 msgid "set [<remote>:]<profile> <key><value>..."
 msgstr ""
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 msgid "set [<remote>:]<project> <key>=<value>..."
 msgstr ""
 
@@ -4125,7 +4129,7 @@ msgstr ""
 msgid "show [<remote>:]<profile>"
 msgstr ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid "show [<remote>:]<project>"
 msgstr ""
 
@@ -4169,7 +4173,7 @@ msgstr ""
 msgid "switch <remote>"
 msgstr ""
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 msgid "switch [<remote>:]<project>"
 msgstr ""
 
@@ -4214,7 +4218,7 @@ msgstr ""
 msgid "unset [<remote>:]<profile> <key>"
 msgstr ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 msgid "unset [<remote>:]<project> <key>"
 msgstr ""
 
diff --git a/po/de.po b/po/de.po
index a1c3f804d5..40a50c4309 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: 2020-02-26 08:16-0500\n"
+"POT-Creation-Date: 2020-03-04 10:28+0000\n"
 "PO-Revision-Date: 2019-12-12 14:53+0000\n"
 "Last-Translator: Stéphane Graber <stgraber at stgraber.org>\n"
 "Language-Team: German <https://hosted.weblate.org/projects/linux-containers/"
@@ -1044,8 +1044,8 @@ msgstr "Kein Zertifikat für diese Verbindung"
 #: lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712
 #: lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29
 #: lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334
-#: lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584
-#: lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31
+#: lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590
+#: lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31
 #: lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455
 #: lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685
 #: lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33
@@ -1524,7 +1524,7 @@ msgstr ""
 msgid "ID: %s"
 msgstr ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid "IMAGES"
 msgstr ""
 
@@ -2185,7 +2185,7 @@ msgid "Missing profile name"
 msgstr ""
 
 #: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358
-#: lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 #, fuzzy
 msgid "Missing project name"
 msgstr "Profilname kann nicht geändert werden"
@@ -2269,7 +2269,7 @@ msgid "Must supply instance name for: "
 msgstr "der Name des Ursprung Containers muss angegeben werden"
 
 #: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620
-#: lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558
+#: lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558
 #: lxc/storage_volume.go:1118
 msgid "NAME"
 msgstr ""
@@ -2283,7 +2283,7 @@ msgid "NICs:"
 msgstr ""
 
 #: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428
-#: lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid "NO"
 msgstr ""
 
@@ -2431,7 +2431,7 @@ msgstr ""
 msgid "PROCESSES"
 msgstr ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid "PROFILES"
 msgstr ""
 
@@ -2594,7 +2594,7 @@ msgstr "Profil %s erstellt\n"
 msgid "Project %s deleted"
 msgstr "Profil %s gelöscht\n"
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, fuzzy, c-format
 msgid "Project %s renamed to %s"
 msgstr "Profil %s wurde auf %s angewandt\n"
@@ -2675,7 +2675,7 @@ msgstr ""
 msgid "Remote %s already exists"
 msgstr "entfernte Instanz %s existiert bereits"
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
 #: lxc/remote.go:705
 #, fuzzy, c-format
 msgid "Remote %s doesn't exist"
@@ -2765,7 +2765,7 @@ msgstr ""
 msgid "Rename profiles"
 msgstr "Fehlerhafte Profil URL %s"
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 #, fuzzy
 msgid "Rename projects"
 msgstr "Fehlerhafte Profil URL %s"
@@ -2877,6 +2877,10 @@ msgstr ""
 msgid "STORAGE POOL"
 msgstr ""
 
+#: lxc/project.go:457
+msgid "STORAGE VOLUMES"
+msgstr ""
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid "Send a raw query to LXD"
 msgstr ""
@@ -2967,12 +2971,12 @@ msgid ""
 "    lxc profile set [<remote>:]<profile> <key> <value>"
 msgstr ""
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 #, fuzzy
 msgid "Set project configuration keys"
 msgstr "Profil %s erstellt\n"
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid ""
 "Set project configuration keys\n"
 "\n"
@@ -3086,7 +3090,7 @@ msgstr ""
 msgid "Show profile configurations"
 msgstr ""
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 msgid "Show project options"
 msgstr ""
 
@@ -3272,7 +3276,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 msgid "Switch the current project"
 msgstr ""
 
@@ -3462,7 +3466,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567
 #: lxc/storage_volume.go:1120
 msgid "USED BY"
 msgstr ""
@@ -3510,7 +3514,7 @@ msgstr ""
 msgid "Unset profile configuration keys"
 msgstr ""
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 #, fuzzy
 msgid "Unset project configuration keys"
 msgstr "Profil %s erstellt\n"
@@ -3617,7 +3621,7 @@ msgid "Whether or not to snapshot the instance's running state"
 msgstr "Zustand des laufenden Containers sichern oder nicht"
 
 #: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430
-#: lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid "YES"
 msgstr ""
 
@@ -3766,7 +3770,7 @@ msgstr ""
 msgid "create [<remote>:]<project>"
 msgstr ""
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 msgid "current"
 msgstr ""
 
@@ -4561,7 +4565,7 @@ msgstr ""
 msgid "rename [<remote>:]<profile> <new-name>"
 msgstr ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid "rename [<remote>:]<project> <new-name>"
 msgstr ""
 
@@ -4627,7 +4631,7 @@ msgstr ""
 "\n"
 "lxd %s <Name>\n"
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 #, fuzzy
 msgid "set [<remote>:]<project> <key>=<value>..."
 msgstr ""
@@ -4707,7 +4711,7 @@ msgstr ""
 msgid "show [<remote>:]<profile>"
 msgstr ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid "show [<remote>:]<project>"
 msgstr ""
 
@@ -4774,7 +4778,7 @@ msgstr ""
 msgid "switch <remote>"
 msgstr ""
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 #, fuzzy
 msgid "switch [<remote>:]<project>"
 msgstr ""
@@ -4827,7 +4831,7 @@ msgstr ""
 msgid "unset [<remote>:]<profile> <key>"
 msgstr ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 #, fuzzy
 msgid "unset [<remote>:]<project> <key>"
 msgstr ""
diff --git a/po/el.po b/po/el.po
index 4997d4dbb9..d04e685b71 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: 2020-02-26 08:16-0500\n"
+"POT-Creation-Date: 2020-03-04 10:28+0000\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/"
@@ -864,8 +864,8 @@ msgstr ""
 #: lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712
 #: lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29
 #: lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334
-#: lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584
-#: lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31
+#: lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590
+#: lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31
 #: lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455
 #: lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685
 #: lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33
@@ -1315,7 +1315,7 @@ msgstr ""
 msgid "ID: %s"
 msgstr ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid "IMAGES"
 msgstr ""
 
@@ -1930,7 +1930,7 @@ msgid "Missing profile name"
 msgstr ""
 
 #: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358
-#: lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 msgid "Missing project name"
 msgstr ""
 
@@ -2006,7 +2006,7 @@ msgid "Must supply instance name for: "
 msgstr ""
 
 #: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620
-#: lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558
+#: lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558
 #: lxc/storage_volume.go:1118
 msgid "NAME"
 msgstr ""
@@ -2020,7 +2020,7 @@ msgid "NICs:"
 msgstr ""
 
 #: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428
-#: lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid "NO"
 msgstr ""
 
@@ -2165,7 +2165,7 @@ msgstr ""
 msgid "PROCESSES"
 msgstr ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid "PROFILES"
 msgstr ""
 
@@ -2323,7 +2323,7 @@ msgstr ""
 msgid "Project %s deleted"
 msgstr ""
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, c-format
 msgid "Project %s renamed to %s"
 msgstr ""
@@ -2400,7 +2400,7 @@ msgstr ""
 msgid "Remote %s already exists"
 msgstr ""
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
 #: lxc/remote.go:705
 #, c-format
 msgid "Remote %s doesn't exist"
@@ -2484,7 +2484,7 @@ msgstr ""
 msgid "Rename profiles"
 msgstr ""
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 msgid "Rename projects"
 msgstr ""
 
@@ -2589,6 +2589,10 @@ msgstr ""
 msgid "STORAGE POOL"
 msgstr ""
 
+#: lxc/project.go:457
+msgid "STORAGE VOLUMES"
+msgstr ""
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid "Send a raw query to LXD"
 msgstr ""
@@ -2675,11 +2679,11 @@ msgid ""
 "    lxc profile set [<remote>:]<profile> <key> <value>"
 msgstr ""
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 msgid "Set project configuration keys"
 msgstr ""
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid ""
 "Set project configuration keys\n"
 "\n"
@@ -2786,7 +2790,7 @@ msgstr ""
 msgid "Show profile configurations"
 msgstr ""
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 msgid "Show project options"
 msgstr ""
 
@@ -2961,7 +2965,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 msgid "Switch the current project"
 msgstr ""
 
@@ -3144,7 +3148,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567
 #: lxc/storage_volume.go:1120
 msgid "USED BY"
 msgstr ""
@@ -3189,7 +3193,7 @@ msgstr ""
 msgid "Unset profile configuration keys"
 msgstr ""
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 msgid "Unset project configuration keys"
 msgstr ""
 
@@ -3284,7 +3288,7 @@ msgid "Whether or not to snapshot the instance's running state"
 msgstr ""
 
 #: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430
-#: lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid "YES"
 msgstr ""
 
@@ -3408,7 +3412,7 @@ msgstr ""
 msgid "create [<remote>:]<project>"
 msgstr ""
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 msgid "current"
 msgstr ""
 
@@ -4047,7 +4051,7 @@ msgstr ""
 msgid "rename [<remote>:]<profile> <new-name>"
 msgstr ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid "rename [<remote>:]<project> <new-name>"
 msgstr ""
 
@@ -4083,7 +4087,7 @@ msgstr ""
 msgid "set [<remote>:]<profile> <key><value>..."
 msgstr ""
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 msgid "set [<remote>:]<project> <key>=<value>..."
 msgstr ""
 
@@ -4135,7 +4139,7 @@ msgstr ""
 msgid "show [<remote>:]<profile>"
 msgstr ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid "show [<remote>:]<project>"
 msgstr ""
 
@@ -4179,7 +4183,7 @@ msgstr ""
 msgid "switch <remote>"
 msgstr ""
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 msgid "switch [<remote>:]<project>"
 msgstr ""
 
@@ -4224,7 +4228,7 @@ msgstr ""
 msgid "unset [<remote>:]<profile> <key>"
 msgstr ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 msgid "unset [<remote>:]<project> <key>"
 msgstr ""
 
diff --git a/po/es.po b/po/es.po
index 26d99e7a02..ea0577539d 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: 2020-02-26 08:16-0500\n"
+"POT-Creation-Date: 2020-03-04 10:28+0000\n"
 "PO-Revision-Date: 2019-09-06 07:09+0000\n"
 "Last-Translator: Stéphane Graber <stgraber at stgraber.org>\n"
 "Language-Team: Spanish <https://hosted.weblate.org/projects/linux-containers/"
@@ -999,8 +999,8 @@ msgstr ""
 #: lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712
 #: lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29
 #: lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334
-#: lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584
-#: lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31
+#: lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590
+#: lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31
 #: lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455
 #: lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685
 #: lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33
@@ -1452,7 +1452,7 @@ msgstr ""
 msgid "ID: %s"
 msgstr ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid "IMAGES"
 msgstr ""
 
@@ -2070,7 +2070,7 @@ msgid "Missing profile name"
 msgstr ""
 
 #: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358
-#: lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 #, fuzzy
 msgid "Missing project name"
 msgstr "Nombre del contenedor es: %s"
@@ -2148,7 +2148,7 @@ msgid "Must supply instance name for: "
 msgstr ""
 
 #: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620
-#: lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558
+#: lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558
 #: lxc/storage_volume.go:1118
 msgid "NAME"
 msgstr ""
@@ -2162,7 +2162,7 @@ msgid "NICs:"
 msgstr ""
 
 #: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428
-#: lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid "NO"
 msgstr ""
 
@@ -2306,7 +2306,7 @@ msgstr ""
 msgid "PROCESSES"
 msgstr ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid "PROFILES"
 msgstr ""
 
@@ -2467,7 +2467,7 @@ msgstr ""
 msgid "Project %s deleted"
 msgstr ""
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, c-format
 msgid "Project %s renamed to %s"
 msgstr ""
@@ -2544,7 +2544,7 @@ msgstr "Refrescando la imagen: %s"
 msgid "Remote %s already exists"
 msgstr ""
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
 #: lxc/remote.go:705
 #, c-format
 msgid "Remote %s doesn't exist"
@@ -2629,7 +2629,7 @@ msgstr ""
 msgid "Rename profiles"
 msgstr ""
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 msgid "Rename projects"
 msgstr ""
 
@@ -2735,6 +2735,10 @@ msgstr ""
 msgid "STORAGE POOL"
 msgstr ""
 
+#: lxc/project.go:457
+msgid "STORAGE VOLUMES"
+msgstr ""
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid "Send a raw query to LXD"
 msgstr ""
@@ -2821,11 +2825,11 @@ msgid ""
 "    lxc profile set [<remote>:]<profile> <key> <value>"
 msgstr ""
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 msgid "Set project configuration keys"
 msgstr ""
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid ""
 "Set project configuration keys\n"
 "\n"
@@ -2932,7 +2936,7 @@ msgstr ""
 msgid "Show profile configurations"
 msgstr ""
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 msgid "Show project options"
 msgstr ""
 
@@ -3107,7 +3111,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 msgid "Switch the current project"
 msgstr ""
 
@@ -3290,7 +3294,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567
 #: lxc/storage_volume.go:1120
 msgid "USED BY"
 msgstr ""
@@ -3335,7 +3339,7 @@ msgstr ""
 msgid "Unset profile configuration keys"
 msgstr ""
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 msgid "Unset project configuration keys"
 msgstr ""
 
@@ -3430,7 +3434,7 @@ msgid "Whether or not to snapshot the instance's running state"
 msgstr ""
 
 #: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430
-#: lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid "YES"
 msgstr ""
 
@@ -3558,7 +3562,7 @@ msgstr ""
 msgid "create [<remote>:]<project>"
 msgstr ""
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 msgid "current"
 msgstr ""
 
@@ -4214,7 +4218,7 @@ msgstr ""
 msgid "rename [<remote>:]<profile> <new-name>"
 msgstr ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid "rename [<remote>:]<project> <new-name>"
 msgstr ""
 
@@ -4253,7 +4257,7 @@ msgstr ""
 msgid "set [<remote>:]<profile> <key><value>..."
 msgstr ""
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 msgid "set [<remote>:]<project> <key>=<value>..."
 msgstr ""
 
@@ -4309,7 +4313,7 @@ msgstr ""
 msgid "show [<remote>:]<profile>"
 msgstr ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid "show [<remote>:]<project>"
 msgstr ""
 
@@ -4357,7 +4361,7 @@ msgstr ""
 msgid "switch <remote>"
 msgstr ""
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 #, fuzzy
 msgid "switch [<remote>:]<project>"
 msgstr "No se puede proveer el nombre del container a la lista"
@@ -4404,7 +4408,7 @@ msgstr ""
 msgid "unset [<remote>:]<profile> <key>"
 msgstr ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 msgid "unset [<remote>:]<project> <key>"
 msgstr ""
 
diff --git a/po/fa.po b/po/fa.po
index 0a069ffcb7..47a32edd7a 100644
--- a/po/fa.po
+++ b/po/fa.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: 2020-02-26 08:16-0500\n"
+"POT-Creation-Date: 2020-03-04 10:28+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -860,8 +860,8 @@ msgstr ""
 #: lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712
 #: lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29
 #: lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334
-#: lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584
-#: lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31
+#: lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590
+#: lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31
 #: lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455
 #: lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685
 #: lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33
@@ -1308,7 +1308,7 @@ msgstr ""
 msgid "ID: %s"
 msgstr ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid "IMAGES"
 msgstr ""
 
@@ -1921,7 +1921,7 @@ msgid "Missing profile name"
 msgstr ""
 
 #: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358
-#: lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 msgid "Missing project name"
 msgstr ""
 
@@ -1997,7 +1997,7 @@ msgid "Must supply instance name for: "
 msgstr ""
 
 #: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620
-#: lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558
+#: lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558
 #: lxc/storage_volume.go:1118
 msgid "NAME"
 msgstr ""
@@ -2011,7 +2011,7 @@ msgid "NICs:"
 msgstr ""
 
 #: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428
-#: lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid "NO"
 msgstr ""
 
@@ -2155,7 +2155,7 @@ msgstr ""
 msgid "PROCESSES"
 msgstr ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid "PROFILES"
 msgstr ""
 
@@ -2313,7 +2313,7 @@ msgstr ""
 msgid "Project %s deleted"
 msgstr ""
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, c-format
 msgid "Project %s renamed to %s"
 msgstr ""
@@ -2390,7 +2390,7 @@ msgstr ""
 msgid "Remote %s already exists"
 msgstr ""
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
 #: lxc/remote.go:705
 #, c-format
 msgid "Remote %s doesn't exist"
@@ -2474,7 +2474,7 @@ msgstr ""
 msgid "Rename profiles"
 msgstr ""
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 msgid "Rename projects"
 msgstr ""
 
@@ -2579,6 +2579,10 @@ msgstr ""
 msgid "STORAGE POOL"
 msgstr ""
 
+#: lxc/project.go:457
+msgid "STORAGE VOLUMES"
+msgstr ""
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid "Send a raw query to LXD"
 msgstr ""
@@ -2665,11 +2669,11 @@ msgid ""
 "    lxc profile set [<remote>:]<profile> <key> <value>"
 msgstr ""
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 msgid "Set project configuration keys"
 msgstr ""
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid ""
 "Set project configuration keys\n"
 "\n"
@@ -2776,7 +2780,7 @@ msgstr ""
 msgid "Show profile configurations"
 msgstr ""
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 msgid "Show project options"
 msgstr ""
 
@@ -2951,7 +2955,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 msgid "Switch the current project"
 msgstr ""
 
@@ -3134,7 +3138,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567
 #: lxc/storage_volume.go:1120
 msgid "USED BY"
 msgstr ""
@@ -3179,7 +3183,7 @@ msgstr ""
 msgid "Unset profile configuration keys"
 msgstr ""
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 msgid "Unset project configuration keys"
 msgstr ""
 
@@ -3274,7 +3278,7 @@ msgid "Whether or not to snapshot the instance's running state"
 msgstr ""
 
 #: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430
-#: lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid "YES"
 msgstr ""
 
@@ -3398,7 +3402,7 @@ msgstr ""
 msgid "create [<remote>:]<project>"
 msgstr ""
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 msgid "current"
 msgstr ""
 
@@ -4037,7 +4041,7 @@ msgstr ""
 msgid "rename [<remote>:]<profile> <new-name>"
 msgstr ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid "rename [<remote>:]<project> <new-name>"
 msgstr ""
 
@@ -4073,7 +4077,7 @@ msgstr ""
 msgid "set [<remote>:]<profile> <key><value>..."
 msgstr ""
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 msgid "set [<remote>:]<project> <key>=<value>..."
 msgstr ""
 
@@ -4125,7 +4129,7 @@ msgstr ""
 msgid "show [<remote>:]<profile>"
 msgstr ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid "show [<remote>:]<project>"
 msgstr ""
 
@@ -4169,7 +4173,7 @@ msgstr ""
 msgid "switch <remote>"
 msgstr ""
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 msgid "switch [<remote>:]<project>"
 msgstr ""
 
@@ -4214,7 +4218,7 @@ msgstr ""
 msgid "unset [<remote>:]<profile> <key>"
 msgstr ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 msgid "unset [<remote>:]<project> <key>"
 msgstr ""
 
diff --git a/po/fi.po b/po/fi.po
index 3c19179d43..11ddb4c432 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: 2020-02-26 08:16-0500\n"
+"POT-Creation-Date: 2020-03-04 10:28+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -860,8 +860,8 @@ msgstr ""
 #: lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712
 #: lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29
 #: lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334
-#: lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584
-#: lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31
+#: lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590
+#: lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31
 #: lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455
 #: lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685
 #: lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33
@@ -1308,7 +1308,7 @@ msgstr ""
 msgid "ID: %s"
 msgstr ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid "IMAGES"
 msgstr ""
 
@@ -1921,7 +1921,7 @@ msgid "Missing profile name"
 msgstr ""
 
 #: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358
-#: lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 msgid "Missing project name"
 msgstr ""
 
@@ -1997,7 +1997,7 @@ msgid "Must supply instance name for: "
 msgstr ""
 
 #: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620
-#: lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558
+#: lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558
 #: lxc/storage_volume.go:1118
 msgid "NAME"
 msgstr ""
@@ -2011,7 +2011,7 @@ msgid "NICs:"
 msgstr ""
 
 #: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428
-#: lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid "NO"
 msgstr ""
 
@@ -2155,7 +2155,7 @@ msgstr ""
 msgid "PROCESSES"
 msgstr ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid "PROFILES"
 msgstr ""
 
@@ -2313,7 +2313,7 @@ msgstr ""
 msgid "Project %s deleted"
 msgstr ""
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, c-format
 msgid "Project %s renamed to %s"
 msgstr ""
@@ -2390,7 +2390,7 @@ msgstr ""
 msgid "Remote %s already exists"
 msgstr ""
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
 #: lxc/remote.go:705
 #, c-format
 msgid "Remote %s doesn't exist"
@@ -2474,7 +2474,7 @@ msgstr ""
 msgid "Rename profiles"
 msgstr ""
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 msgid "Rename projects"
 msgstr ""
 
@@ -2579,6 +2579,10 @@ msgstr ""
 msgid "STORAGE POOL"
 msgstr ""
 
+#: lxc/project.go:457
+msgid "STORAGE VOLUMES"
+msgstr ""
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid "Send a raw query to LXD"
 msgstr ""
@@ -2665,11 +2669,11 @@ msgid ""
 "    lxc profile set [<remote>:]<profile> <key> <value>"
 msgstr ""
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 msgid "Set project configuration keys"
 msgstr ""
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid ""
 "Set project configuration keys\n"
 "\n"
@@ -2776,7 +2780,7 @@ msgstr ""
 msgid "Show profile configurations"
 msgstr ""
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 msgid "Show project options"
 msgstr ""
 
@@ -2951,7 +2955,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 msgid "Switch the current project"
 msgstr ""
 
@@ -3134,7 +3138,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567
 #: lxc/storage_volume.go:1120
 msgid "USED BY"
 msgstr ""
@@ -3179,7 +3183,7 @@ msgstr ""
 msgid "Unset profile configuration keys"
 msgstr ""
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 msgid "Unset project configuration keys"
 msgstr ""
 
@@ -3274,7 +3278,7 @@ msgid "Whether or not to snapshot the instance's running state"
 msgstr ""
 
 #: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430
-#: lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid "YES"
 msgstr ""
 
@@ -3398,7 +3402,7 @@ msgstr ""
 msgid "create [<remote>:]<project>"
 msgstr ""
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 msgid "current"
 msgstr ""
 
@@ -4037,7 +4041,7 @@ msgstr ""
 msgid "rename [<remote>:]<profile> <new-name>"
 msgstr ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid "rename [<remote>:]<project> <new-name>"
 msgstr ""
 
@@ -4073,7 +4077,7 @@ msgstr ""
 msgid "set [<remote>:]<profile> <key><value>..."
 msgstr ""
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 msgid "set [<remote>:]<project> <key>=<value>..."
 msgstr ""
 
@@ -4125,7 +4129,7 @@ msgstr ""
 msgid "show [<remote>:]<profile>"
 msgstr ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid "show [<remote>:]<project>"
 msgstr ""
 
@@ -4169,7 +4173,7 @@ msgstr ""
 msgid "switch <remote>"
 msgstr ""
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 msgid "switch [<remote>:]<project>"
 msgstr ""
 
@@ -4214,7 +4218,7 @@ msgstr ""
 msgid "unset [<remote>:]<profile> <key>"
 msgstr ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 msgid "unset [<remote>:]<project> <key>"
 msgstr ""
 
diff --git a/po/fr.po b/po/fr.po
index ee96dfa609..315a019141 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: 2020-02-26 08:16-0500\n"
+"POT-Creation-Date: 2020-03-04 10:28+0000\n"
 "PO-Revision-Date: 2019-01-04 18:07+0000\n"
 "Last-Translator: Deleted User <noreply+12102 at weblate.org>\n"
 "Language-Team: French <https://hosted.weblate.org/projects/linux-containers/"
@@ -1051,8 +1051,8 @@ msgstr "Copie de l'image : %s"
 #: lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712
 #: lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29
 #: lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334
-#: lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584
-#: lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31
+#: lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590
+#: lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31
 #: lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455
 #: lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685
 #: lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33
@@ -1536,7 +1536,7 @@ msgstr "Pid : %d"
 msgid "ID: %s"
 msgstr ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid "IMAGES"
 msgstr ""
 
@@ -2241,7 +2241,7 @@ msgid "Missing profile name"
 msgstr ""
 
 #: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358
-#: lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 #, fuzzy
 msgid "Missing project name"
 msgstr "Nom de l'ensemble de stockage"
@@ -2327,7 +2327,7 @@ msgid "Must supply instance name for: "
 msgstr "Vous devez fournir le nom d'un conteneur pour : "
 
 #: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620
-#: lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558
+#: lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558
 #: lxc/storage_volume.go:1118
 msgid "NAME"
 msgstr "NOM"
@@ -2341,7 +2341,7 @@ msgid "NICs:"
 msgstr ""
 
 #: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428
-#: lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid "NO"
 msgstr "NON"
 
@@ -2496,7 +2496,7 @@ msgstr "PID"
 msgid "PROCESSES"
 msgstr ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid "PROFILES"
 msgstr "PROFILS"
 
@@ -2660,7 +2660,7 @@ msgstr "Profil %s créé"
 msgid "Project %s deleted"
 msgstr "Profil %s supprimé"
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, fuzzy, c-format
 msgid "Project %s renamed to %s"
 msgstr "Profil %s ajouté à %s"
@@ -2742,7 +2742,7 @@ msgstr "Récupération de l'image : %s"
 msgid "Remote %s already exists"
 msgstr "le serveur distant %s existe déjà"
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
 #: lxc/remote.go:705
 #, fuzzy, c-format
 msgid "Remote %s doesn't exist"
@@ -2831,7 +2831,7 @@ msgstr ""
 msgid "Rename profiles"
 msgstr ""
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 #, fuzzy
 msgid "Rename projects"
 msgstr "Créé : %s"
@@ -2945,6 +2945,11 @@ msgstr "ÉTAT"
 msgid "STORAGE POOL"
 msgstr "ENSEMBLE DE STOCKAGE"
 
+#: lxc/project.go:457
+#, fuzzy
+msgid "STORAGE VOLUMES"
+msgstr "ENSEMBLE DE STOCKAGE"
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid "Send a raw query to LXD"
 msgstr ""
@@ -3037,12 +3042,12 @@ msgid ""
 "    lxc profile set [<remote>:]<profile> <key> <value>"
 msgstr ""
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 #, fuzzy
 msgid "Set project configuration keys"
 msgstr "Clé de configuration invalide"
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid ""
 "Set project configuration keys\n"
 "\n"
@@ -3159,7 +3164,7 @@ msgstr "Afficher la configuration étendue"
 msgid "Show profile configurations"
 msgstr "Afficher la configuration étendue"
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 #, fuzzy
 msgid "Show project options"
 msgstr "Afficher la configuration étendue"
@@ -3347,7 +3352,7 @@ msgstr "Swap (courant)"
 msgid "Swap (peak)"
 msgstr "Swap (pointe)"
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 #, fuzzy
 msgid "Switch the current project"
 msgstr "impossible de supprimer le serveur distant par défaut"
@@ -3545,7 +3550,7 @@ msgstr "DATE DE PUBLICATION"
 msgid "URL"
 msgstr "URL"
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567
 #: lxc/storage_volume.go:1120
 msgid "USED BY"
 msgstr "UTILISÉ PAR"
@@ -3595,7 +3600,7 @@ msgstr "Clé de configuration invalide"
 msgid "Unset profile configuration keys"
 msgstr "Clé de configuration invalide"
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 #, fuzzy
 msgid "Unset project configuration keys"
 msgstr "Clé de configuration invalide"
@@ -3700,7 +3705,7 @@ msgid "Whether or not to snapshot the instance's running state"
 msgstr "Réaliser ou pas l'instantané de l'état de fonctionnement du conteneur"
 
 #: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430
-#: lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid "YES"
 msgstr "OUI"
 
@@ -3853,7 +3858,7 @@ msgstr ""
 msgid "create [<remote>:]<project>"
 msgstr ""
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 #, fuzzy
 msgid "current"
 msgstr "Swap (courant)"
@@ -4705,7 +4710,7 @@ msgstr ""
 msgid "rename [<remote>:]<profile> <new-name>"
 msgstr ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid "rename [<remote>:]<project> <new-name>"
 msgstr ""
 
@@ -4777,7 +4782,7 @@ msgstr ""
 "\n"
 "lxc %s [<remote>:]<container> [[<remote>:]<container>...]%s"
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 #, fuzzy
 msgid "set [<remote>:]<project> <key>=<value>..."
 msgstr ""
@@ -4869,7 +4874,7 @@ msgstr ""
 msgid "show [<remote>:]<profile>"
 msgstr ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid "show [<remote>:]<project>"
 msgstr ""
 
@@ -4946,7 +4951,7 @@ msgstr ""
 msgid "switch <remote>"
 msgstr "impossible de supprimer le serveur distant par défaut"
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 #, fuzzy
 msgid "switch [<remote>:]<project>"
 msgstr "impossible de supprimer le serveur distant par défaut"
@@ -4996,7 +5001,7 @@ msgstr ""
 msgid "unset [<remote>:]<profile> <key>"
 msgstr ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 #, fuzzy
 msgid "unset [<remote>:]<project> <key>"
 msgstr ""
diff --git a/po/hi.po b/po/hi.po
index 8a7595da20..711c9172c7 100644
--- a/po/hi.po
+++ b/po/hi.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: 2020-02-26 08:16-0500\n"
+"POT-Creation-Date: 2020-03-04 10:28+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -860,8 +860,8 @@ msgstr ""
 #: lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712
 #: lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29
 #: lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334
-#: lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584
-#: lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31
+#: lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590
+#: lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31
 #: lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455
 #: lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685
 #: lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33
@@ -1308,7 +1308,7 @@ msgstr ""
 msgid "ID: %s"
 msgstr ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid "IMAGES"
 msgstr ""
 
@@ -1921,7 +1921,7 @@ msgid "Missing profile name"
 msgstr ""
 
 #: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358
-#: lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 msgid "Missing project name"
 msgstr ""
 
@@ -1997,7 +1997,7 @@ msgid "Must supply instance name for: "
 msgstr ""
 
 #: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620
-#: lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558
+#: lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558
 #: lxc/storage_volume.go:1118
 msgid "NAME"
 msgstr ""
@@ -2011,7 +2011,7 @@ msgid "NICs:"
 msgstr ""
 
 #: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428
-#: lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid "NO"
 msgstr ""
 
@@ -2155,7 +2155,7 @@ msgstr ""
 msgid "PROCESSES"
 msgstr ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid "PROFILES"
 msgstr ""
 
@@ -2313,7 +2313,7 @@ msgstr ""
 msgid "Project %s deleted"
 msgstr ""
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, c-format
 msgid "Project %s renamed to %s"
 msgstr ""
@@ -2390,7 +2390,7 @@ msgstr ""
 msgid "Remote %s already exists"
 msgstr ""
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
 #: lxc/remote.go:705
 #, c-format
 msgid "Remote %s doesn't exist"
@@ -2474,7 +2474,7 @@ msgstr ""
 msgid "Rename profiles"
 msgstr ""
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 msgid "Rename projects"
 msgstr ""
 
@@ -2579,6 +2579,10 @@ msgstr ""
 msgid "STORAGE POOL"
 msgstr ""
 
+#: lxc/project.go:457
+msgid "STORAGE VOLUMES"
+msgstr ""
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid "Send a raw query to LXD"
 msgstr ""
@@ -2665,11 +2669,11 @@ msgid ""
 "    lxc profile set [<remote>:]<profile> <key> <value>"
 msgstr ""
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 msgid "Set project configuration keys"
 msgstr ""
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid ""
 "Set project configuration keys\n"
 "\n"
@@ -2776,7 +2780,7 @@ msgstr ""
 msgid "Show profile configurations"
 msgstr ""
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 msgid "Show project options"
 msgstr ""
 
@@ -2951,7 +2955,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 msgid "Switch the current project"
 msgstr ""
 
@@ -3134,7 +3138,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567
 #: lxc/storage_volume.go:1120
 msgid "USED BY"
 msgstr ""
@@ -3179,7 +3183,7 @@ msgstr ""
 msgid "Unset profile configuration keys"
 msgstr ""
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 msgid "Unset project configuration keys"
 msgstr ""
 
@@ -3274,7 +3278,7 @@ msgid "Whether or not to snapshot the instance's running state"
 msgstr ""
 
 #: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430
-#: lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid "YES"
 msgstr ""
 
@@ -3398,7 +3402,7 @@ msgstr ""
 msgid "create [<remote>:]<project>"
 msgstr ""
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 msgid "current"
 msgstr ""
 
@@ -4037,7 +4041,7 @@ msgstr ""
 msgid "rename [<remote>:]<profile> <new-name>"
 msgstr ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid "rename [<remote>:]<project> <new-name>"
 msgstr ""
 
@@ -4073,7 +4077,7 @@ msgstr ""
 msgid "set [<remote>:]<profile> <key><value>..."
 msgstr ""
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 msgid "set [<remote>:]<project> <key>=<value>..."
 msgstr ""
 
@@ -4125,7 +4129,7 @@ msgstr ""
 msgid "show [<remote>:]<profile>"
 msgstr ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid "show [<remote>:]<project>"
 msgstr ""
 
@@ -4169,7 +4173,7 @@ msgstr ""
 msgid "switch <remote>"
 msgstr ""
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 msgid "switch [<remote>:]<project>"
 msgstr ""
 
@@ -4214,7 +4218,7 @@ msgstr ""
 msgid "unset [<remote>:]<profile> <key>"
 msgstr ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 msgid "unset [<remote>:]<project> <key>"
 msgstr ""
 
diff --git a/po/id.po b/po/id.po
index e8fb89aff2..8f07b95d9e 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: 2020-02-26 08:16-0500\n"
+"POT-Creation-Date: 2020-03-04 10:28+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -860,8 +860,8 @@ msgstr ""
 #: lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712
 #: lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29
 #: lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334
-#: lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584
-#: lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31
+#: lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590
+#: lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31
 #: lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455
 #: lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685
 #: lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33
@@ -1308,7 +1308,7 @@ msgstr ""
 msgid "ID: %s"
 msgstr ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid "IMAGES"
 msgstr ""
 
@@ -1921,7 +1921,7 @@ msgid "Missing profile name"
 msgstr ""
 
 #: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358
-#: lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 msgid "Missing project name"
 msgstr ""
 
@@ -1997,7 +1997,7 @@ msgid "Must supply instance name for: "
 msgstr ""
 
 #: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620
-#: lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558
+#: lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558
 #: lxc/storage_volume.go:1118
 msgid "NAME"
 msgstr ""
@@ -2011,7 +2011,7 @@ msgid "NICs:"
 msgstr ""
 
 #: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428
-#: lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid "NO"
 msgstr ""
 
@@ -2155,7 +2155,7 @@ msgstr ""
 msgid "PROCESSES"
 msgstr ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid "PROFILES"
 msgstr ""
 
@@ -2313,7 +2313,7 @@ msgstr ""
 msgid "Project %s deleted"
 msgstr ""
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, c-format
 msgid "Project %s renamed to %s"
 msgstr ""
@@ -2390,7 +2390,7 @@ msgstr ""
 msgid "Remote %s already exists"
 msgstr ""
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
 #: lxc/remote.go:705
 #, c-format
 msgid "Remote %s doesn't exist"
@@ -2474,7 +2474,7 @@ msgstr ""
 msgid "Rename profiles"
 msgstr ""
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 msgid "Rename projects"
 msgstr ""
 
@@ -2579,6 +2579,10 @@ msgstr ""
 msgid "STORAGE POOL"
 msgstr ""
 
+#: lxc/project.go:457
+msgid "STORAGE VOLUMES"
+msgstr ""
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid "Send a raw query to LXD"
 msgstr ""
@@ -2665,11 +2669,11 @@ msgid ""
 "    lxc profile set [<remote>:]<profile> <key> <value>"
 msgstr ""
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 msgid "Set project configuration keys"
 msgstr ""
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid ""
 "Set project configuration keys\n"
 "\n"
@@ -2776,7 +2780,7 @@ msgstr ""
 msgid "Show profile configurations"
 msgstr ""
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 msgid "Show project options"
 msgstr ""
 
@@ -2951,7 +2955,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 msgid "Switch the current project"
 msgstr ""
 
@@ -3134,7 +3138,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567
 #: lxc/storage_volume.go:1120
 msgid "USED BY"
 msgstr ""
@@ -3179,7 +3183,7 @@ msgstr ""
 msgid "Unset profile configuration keys"
 msgstr ""
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 msgid "Unset project configuration keys"
 msgstr ""
 
@@ -3274,7 +3278,7 @@ msgid "Whether or not to snapshot the instance's running state"
 msgstr ""
 
 #: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430
-#: lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid "YES"
 msgstr ""
 
@@ -3398,7 +3402,7 @@ msgstr ""
 msgid "create [<remote>:]<project>"
 msgstr ""
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 msgid "current"
 msgstr ""
 
@@ -4037,7 +4041,7 @@ msgstr ""
 msgid "rename [<remote>:]<profile> <new-name>"
 msgstr ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid "rename [<remote>:]<project> <new-name>"
 msgstr ""
 
@@ -4073,7 +4077,7 @@ msgstr ""
 msgid "set [<remote>:]<profile> <key><value>..."
 msgstr ""
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 msgid "set [<remote>:]<project> <key>=<value>..."
 msgstr ""
 
@@ -4125,7 +4129,7 @@ msgstr ""
 msgid "show [<remote>:]<profile>"
 msgstr ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid "show [<remote>:]<project>"
 msgstr ""
 
@@ -4169,7 +4173,7 @@ msgstr ""
 msgid "switch <remote>"
 msgstr ""
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 msgid "switch [<remote>:]<project>"
 msgstr ""
 
@@ -4214,7 +4218,7 @@ msgstr ""
 msgid "unset [<remote>:]<profile> <key>"
 msgstr ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 msgid "unset [<remote>:]<project> <key>"
 msgstr ""
 
diff --git a/po/it.po b/po/it.po
index a92e815064..80bc8eaec8 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: 2020-02-26 08:16-0500\n"
+"POT-Creation-Date: 2020-03-04 10:28+0000\n"
 "PO-Revision-Date: 2019-09-06 07:09+0000\n"
 "Last-Translator: Luigi Operoso <brokenpip3 at gmail.com>\n"
 "Language-Team: Italian <https://hosted.weblate.org/projects/linux-containers/"
@@ -987,8 +987,8 @@ msgstr ""
 #: lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712
 #: lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29
 #: lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334
-#: lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584
-#: lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31
+#: lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590
+#: lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31
 #: lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455
 #: lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685
 #: lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33
@@ -1441,7 +1441,7 @@ msgstr ""
 msgid "ID: %s"
 msgstr ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid "IMAGES"
 msgstr ""
 
@@ -2064,7 +2064,7 @@ msgid "Missing profile name"
 msgstr ""
 
 #: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358
-#: lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 #, fuzzy
 msgid "Missing project name"
 msgstr "Il nome del container è: %s"
@@ -2141,7 +2141,7 @@ msgid "Must supply instance name for: "
 msgstr ""
 
 #: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620
-#: lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558
+#: lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558
 #: lxc/storage_volume.go:1118
 msgid "NAME"
 msgstr ""
@@ -2155,7 +2155,7 @@ msgid "NICs:"
 msgstr ""
 
 #: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428
-#: lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid "NO"
 msgstr ""
 
@@ -2299,7 +2299,7 @@ msgstr ""
 msgid "PROCESSES"
 msgstr ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid "PROFILES"
 msgstr ""
 
@@ -2459,7 +2459,7 @@ msgstr ""
 msgid "Project %s deleted"
 msgstr ""
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, c-format
 msgid "Project %s renamed to %s"
 msgstr ""
@@ -2537,7 +2537,7 @@ msgstr ""
 msgid "Remote %s already exists"
 msgstr "il remote %s esiste già"
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
 #: lxc/remote.go:705
 #, fuzzy, c-format
 msgid "Remote %s doesn't exist"
@@ -2623,7 +2623,7 @@ msgstr ""
 msgid "Rename profiles"
 msgstr ""
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 msgid "Rename projects"
 msgstr ""
 
@@ -2730,6 +2730,10 @@ msgstr ""
 msgid "STORAGE POOL"
 msgstr ""
 
+#: lxc/project.go:457
+msgid "STORAGE VOLUMES"
+msgstr ""
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid "Send a raw query to LXD"
 msgstr ""
@@ -2816,11 +2820,11 @@ msgid ""
 "    lxc profile set [<remote>:]<profile> <key> <value>"
 msgstr ""
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 msgid "Set project configuration keys"
 msgstr ""
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid ""
 "Set project configuration keys\n"
 "\n"
@@ -2927,7 +2931,7 @@ msgstr ""
 msgid "Show profile configurations"
 msgstr ""
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 msgid "Show project options"
 msgstr ""
 
@@ -3104,7 +3108,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 msgid "Switch the current project"
 msgstr ""
 
@@ -3288,7 +3292,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567
 #: lxc/storage_volume.go:1120
 msgid "USED BY"
 msgstr ""
@@ -3334,7 +3338,7 @@ msgstr ""
 msgid "Unset profile configuration keys"
 msgstr ""
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 msgid "Unset project configuration keys"
 msgstr ""
 
@@ -3429,7 +3433,7 @@ msgid "Whether or not to snapshot the instance's running state"
 msgstr ""
 
 #: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430
-#: lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid "YES"
 msgstr ""
 
@@ -3559,7 +3563,7 @@ msgstr ""
 msgid "create [<remote>:]<project>"
 msgstr ""
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 msgid "current"
 msgstr ""
 
@@ -4215,7 +4219,7 @@ msgstr ""
 msgid "rename [<remote>:]<profile> <new-name>"
 msgstr ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid "rename [<remote>:]<project> <new-name>"
 msgstr ""
 
@@ -4254,7 +4258,7 @@ msgstr ""
 msgid "set [<remote>:]<profile> <key><value>..."
 msgstr ""
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 msgid "set [<remote>:]<project> <key>=<value>..."
 msgstr ""
 
@@ -4310,7 +4314,7 @@ msgstr ""
 msgid "show [<remote>:]<profile>"
 msgstr ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid "show [<remote>:]<project>"
 msgstr ""
 
@@ -4358,7 +4362,7 @@ msgstr ""
 msgid "switch <remote>"
 msgstr ""
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 #, fuzzy
 msgid "switch [<remote>:]<project>"
 msgstr "Creazione del container in corso"
@@ -4405,7 +4409,7 @@ msgstr ""
 msgid "unset [<remote>:]<profile> <key>"
 msgstr ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 msgid "unset [<remote>:]<project> <key>"
 msgstr ""
 
diff --git a/po/ja.po b/po/ja.po
index 277de551c0..f1fba0e499 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: 2020-02-26 08:16-0500\n"
+"POT-Creation-Date: 2020-03-04 10:28+0000\n"
 "PO-Revision-Date: 2019-11-05 18:27+0000\n"
 "Last-Translator: Hiroaki Nakamura <hnakamur at gmail.com>\n"
 "Language-Team: Japanese <https://hosted.weblate.org/projects/linux-"
@@ -920,8 +920,8 @@ msgstr "ストレージボリュームを削除します"
 #: lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712
 #: lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29
 #: lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334
-#: lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584
-#: lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31
+#: lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590
+#: lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31
 #: lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455
 #: lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685
 #: lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33
@@ -1431,7 +1431,7 @@ msgstr "ID: %d"
 msgid "ID: %s"
 msgstr ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid "IMAGES"
 msgstr ""
 
@@ -2176,7 +2176,7 @@ msgid "Missing profile name"
 msgstr "プロファイル名を指定する必要があります"
 
 #: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358
-#: lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 msgid "Missing project name"
 msgstr "プロジェクト名を指定する必要があります"
 
@@ -2262,7 +2262,7 @@ msgid "Must supply instance name for: "
 msgstr "コンテナ名を指定する必要があります: "
 
 #: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620
-#: lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558
+#: lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558
 #: lxc/storage_volume.go:1118
 msgid "NAME"
 msgstr ""
@@ -2276,7 +2276,7 @@ msgid "NICs:"
 msgstr ""
 
 #: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428
-#: lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid "NO"
 msgstr ""
 
@@ -2421,7 +2421,7 @@ msgstr "PID"
 msgid "PROCESSES"
 msgstr ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid "PROFILES"
 msgstr ""
 
@@ -2584,7 +2584,7 @@ msgstr "プロジェクト %s を作成しました"
 msgid "Project %s deleted"
 msgstr "プロジェクト %s を削除しました"
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, c-format
 msgid "Project %s renamed to %s"
 msgstr "プロジェクト名 %s を %s に変更しました"
@@ -2664,7 +2664,7 @@ msgstr "イメージの更新中: %s"
 msgid "Remote %s already exists"
 msgstr "リモート %s は既に存在します"
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
 #: lxc/remote.go:705
 #, c-format
 msgid "Remote %s doesn't exist"
@@ -2751,7 +2751,7 @@ msgstr "ネットワーク名を変更します"
 msgid "Rename profiles"
 msgstr "プロファイル名を変更します"
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 msgid "Rename projects"
 msgstr "プロジェクト名を変更します"
 
@@ -2869,6 +2869,10 @@ msgstr ""
 msgid "STORAGE POOL"
 msgstr ""
 
+#: lxc/project.go:457
+msgid "STORAGE VOLUMES"
+msgstr ""
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid "Send a raw query to LXD"
 msgstr "直接リクエスト (raw query) を LXD に送ります"
@@ -2980,11 +2984,11 @@ msgstr ""
 "後方互換性のため、単一の設定を行う場合は次の形式でも設定できます:\n"
 "    lxc profile set [<remote>:]<profile> <key> <value>"
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 msgid "Set project configuration keys"
 msgstr "プロジェクトの設定項目を設定します"
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid ""
 "Set project configuration keys\n"
 "\n"
@@ -3108,7 +3112,7 @@ msgstr "ネットワークの設定を表示します"
 msgid "Show profile configurations"
 msgstr "プロファイルの設定を表示します"
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 msgid "Show project options"
 msgstr "プロジェクトの設定を表示します"
 
@@ -3289,7 +3293,7 @@ msgstr "Swap (現在値)"
 msgid "Swap (peak)"
 msgstr "Swap (ピーク)"
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 msgid "Switch the current project"
 msgstr "現在のプロジェクトを切り替えます"
 
@@ -3502,7 +3506,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567
 #: lxc/storage_volume.go:1120
 msgid "USED BY"
 msgstr ""
@@ -3550,7 +3554,7 @@ msgstr "ネットワークの設定を削除します"
 msgid "Unset profile configuration keys"
 msgstr "プロファイルの設定を削除します"
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 msgid "Unset project configuration keys"
 msgstr "プロジェクトの設定を削除します"
 
@@ -3654,7 +3658,7 @@ msgid "Whether or not to snapshot the instance's running state"
 msgstr "コンテナの稼動状態のスナップショットを取得するかどうか"
 
 #: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430
-#: lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid "YES"
 msgstr ""
 
@@ -3786,7 +3790,7 @@ msgstr ""
 msgid "create [<remote>:]<project>"
 msgstr "create [<remote>:]<project>"
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 msgid "current"
 msgstr "現在値"
 
@@ -4592,7 +4596,7 @@ msgstr ""
 msgid "rename [<remote>:]<profile> <new-name>"
 msgstr ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid "rename [<remote>:]<project> <new-name>"
 msgstr "rename [<remote>:]<project> <new-name>"
 
@@ -4631,7 +4635,7 @@ msgstr "set [<remote>:]<pool> <volume> <key>=<value>..."
 msgid "set [<remote>:]<profile> <key><value>..."
 msgstr "set [<remote>:]<profile> <key><value>..."
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 msgid "set [<remote>:]<project> <key>=<value>..."
 msgstr "set [<remote>:]<project> <key>=<value>..."
 
@@ -4687,7 +4691,7 @@ msgstr "show [<remote>:]<pool> <volume>[/<snapshot>]"
 msgid "show [<remote>:]<profile>"
 msgstr ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid "show [<remote>:]<project>"
 msgstr ""
 
@@ -4735,7 +4739,7 @@ msgstr ""
 msgid "switch <remote>"
 msgstr "switch <remote>"
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 #, fuzzy
 msgid "switch [<remote>:]<project>"
 msgstr "switch [<remote>:] <project>"
@@ -4782,7 +4786,7 @@ msgstr ""
 msgid "unset [<remote>:]<profile> <key>"
 msgstr ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 msgid "unset [<remote>:]<project> <key>"
 msgstr "unset [<remote>:]<project> <key>"
 
diff --git a/po/ko.po b/po/ko.po
index d76c4fb1f3..7efceffdd9 100644
--- a/po/ko.po
+++ b/po/ko.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: 2020-02-26 08:16-0500\n"
+"POT-Creation-Date: 2020-03-04 10:28+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -860,8 +860,8 @@ msgstr ""
 #: lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712
 #: lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29
 #: lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334
-#: lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584
-#: lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31
+#: lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590
+#: lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31
 #: lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455
 #: lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685
 #: lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33
@@ -1308,7 +1308,7 @@ msgstr ""
 msgid "ID: %s"
 msgstr ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid "IMAGES"
 msgstr ""
 
@@ -1921,7 +1921,7 @@ msgid "Missing profile name"
 msgstr ""
 
 #: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358
-#: lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 msgid "Missing project name"
 msgstr ""
 
@@ -1997,7 +1997,7 @@ msgid "Must supply instance name for: "
 msgstr ""
 
 #: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620
-#: lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558
+#: lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558
 #: lxc/storage_volume.go:1118
 msgid "NAME"
 msgstr ""
@@ -2011,7 +2011,7 @@ msgid "NICs:"
 msgstr ""
 
 #: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428
-#: lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid "NO"
 msgstr ""
 
@@ -2155,7 +2155,7 @@ msgstr ""
 msgid "PROCESSES"
 msgstr ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid "PROFILES"
 msgstr ""
 
@@ -2313,7 +2313,7 @@ msgstr ""
 msgid "Project %s deleted"
 msgstr ""
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, c-format
 msgid "Project %s renamed to %s"
 msgstr ""
@@ -2390,7 +2390,7 @@ msgstr ""
 msgid "Remote %s already exists"
 msgstr ""
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
 #: lxc/remote.go:705
 #, c-format
 msgid "Remote %s doesn't exist"
@@ -2474,7 +2474,7 @@ msgstr ""
 msgid "Rename profiles"
 msgstr ""
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 msgid "Rename projects"
 msgstr ""
 
@@ -2579,6 +2579,10 @@ msgstr ""
 msgid "STORAGE POOL"
 msgstr ""
 
+#: lxc/project.go:457
+msgid "STORAGE VOLUMES"
+msgstr ""
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid "Send a raw query to LXD"
 msgstr ""
@@ -2665,11 +2669,11 @@ msgid ""
 "    lxc profile set [<remote>:]<profile> <key> <value>"
 msgstr ""
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 msgid "Set project configuration keys"
 msgstr ""
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid ""
 "Set project configuration keys\n"
 "\n"
@@ -2776,7 +2780,7 @@ msgstr ""
 msgid "Show profile configurations"
 msgstr ""
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 msgid "Show project options"
 msgstr ""
 
@@ -2951,7 +2955,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 msgid "Switch the current project"
 msgstr ""
 
@@ -3134,7 +3138,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567
 #: lxc/storage_volume.go:1120
 msgid "USED BY"
 msgstr ""
@@ -3179,7 +3183,7 @@ msgstr ""
 msgid "Unset profile configuration keys"
 msgstr ""
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 msgid "Unset project configuration keys"
 msgstr ""
 
@@ -3274,7 +3278,7 @@ msgid "Whether or not to snapshot the instance's running state"
 msgstr ""
 
 #: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430
-#: lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid "YES"
 msgstr ""
 
@@ -3398,7 +3402,7 @@ msgstr ""
 msgid "create [<remote>:]<project>"
 msgstr ""
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 msgid "current"
 msgstr ""
 
@@ -4037,7 +4041,7 @@ msgstr ""
 msgid "rename [<remote>:]<profile> <new-name>"
 msgstr ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid "rename [<remote>:]<project> <new-name>"
 msgstr ""
 
@@ -4073,7 +4077,7 @@ msgstr ""
 msgid "set [<remote>:]<profile> <key><value>..."
 msgstr ""
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 msgid "set [<remote>:]<project> <key>=<value>..."
 msgstr ""
 
@@ -4125,7 +4129,7 @@ msgstr ""
 msgid "show [<remote>:]<profile>"
 msgstr ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid "show [<remote>:]<project>"
 msgstr ""
 
@@ -4169,7 +4173,7 @@ msgstr ""
 msgid "switch <remote>"
 msgstr ""
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 msgid "switch [<remote>:]<project>"
 msgstr ""
 
@@ -4214,7 +4218,7 @@ msgstr ""
 msgid "unset [<remote>:]<profile> <key>"
 msgstr ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 msgid "unset [<remote>:]<project> <key>"
 msgstr ""
 
diff --git a/po/lxd.pot b/po/lxd.pot
index 166cd9c2f4..cd414e91ff 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: 2020-02-26 08:16-0500\n"
+        "POT-Creation-Date: 2020-03-04 10:28+0000\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"
@@ -797,7 +797,7 @@ msgstr  ""
 msgid   "Delete storage volumes"
 msgstr  ""
 
-#: lxc/action.go:31 lxc/action.go:50 lxc/action.go:70 lxc/action.go:91 lxc/alias.go:22 lxc/alias.go:54 lxc/alias.go:100 lxc/alias.go:144 lxc/alias.go:195 lxc/cluster.go:29 lxc/cluster.go:68 lxc/cluster.go:147 lxc/cluster.go:197 lxc/cluster.go:247 lxc/cluster.go:332 lxc/config.go:31 lxc/config.go:90 lxc/config.go:373 lxc/config.go:454 lxc/config.go:612 lxc/config.go:731 lxc/config_device.go:24 lxc/config_device.go:76 lxc/config_device.go:188 lxc/config_device.go:261 lxc/config_device.go:327 lxc/config_device.go:416 lxc/config_device.go:507 lxc/config_device.go:513 lxc/config_device.go:613 lxc/config_device.go:681 lxc/config_metadata.go:28 lxc/config_metadata.go:53 lxc/config_metadata.go:175 lxc/config_template.go:29 lxc/config_template.go:66 lxc/config_template.go:109 lxc/config_template.go:151 lxc/config_template.go:237 lxc/config_template.go:296 lxc/config_trust.go:29 lxc/config_trust.go:58 lxc/config_trust.go:116 lxc/config_trust.go:194 lxc/console.go:31 lxc/copy.go:41 lxc/delete.go:30 lxc/exec.go:40 lxc/export.go:33 lxc/file.go:72 lxc/file.go:105 lxc/file.go:154 lxc/file.go:217 lxc/file.go:407 lxc/image.go:38 lxc/image.go:128 lxc/image.go:270 lxc/image.go:321 lxc/image.go:446 lxc/image.go:605 lxc/image.go:833 lxc/image.go:968 lxc/image.go:1266 lxc/image.go:1345 lxc/image_alias.go:25 lxc/image_alias.go:58 lxc/image_alias.go:105 lxc/image_alias.go:150 lxc/image_alias.go:252 lxc/import.go:28 lxc/info.go:33 lxc/init.go:40 lxc/launch.go:23 lxc/list.go:44 lxc/main.go:50 lxc/manpage.go:19 lxc/monitor.go:30 lxc/move.go:37 lxc/network.go:32 lxc/network.go:108 lxc/network.go:181 lxc/network.go:254 lxc/network.go:326 lxc/network.go:376 lxc/network.go:461 lxc/network.go:546 lxc/network.go:669 lxc/network.go:727 lxc/network.go:807 lxc/network.go:892 lxc/network.go:961 lxc/network.go:1011 lxc/network.go:1081 lxc/network.go:1143 lxc/operation.go:24 lxc/operation.go:53 lxc/operation.go:102 lxc/operation.go:181 lxc/profile.go:29 lxc/profile.go:101 lxc/profile.go:164 lxc/profile.go:244 lxc/profile.go:300 lxc/profile.go:354 lxc/profile.go:404 lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712 lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29 lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334 lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584 lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31 lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455 lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685 lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33 lxc/storage.go:89 lxc/storage.go:163 lxc/storage.go:213 lxc/storage.go:333 lxc/storage.go:388 lxc/storage.go:508 lxc/storage.go:582 lxc/storage.go:651 lxc/storage.go:735 lxc/storage_volume.go:32 lxc/storage_volume.go:139 lxc/storage_volume.go:218 lxc/storage_volume.go:301 lxc/storage_volume.go:462 lxc/storage_volume.go:539 lxc/storage_volume.go:615 lxc/storage_volume.go:697 lxc/storage_volume.go:778 lxc/storage_volume.go:978 lxc/storage_volume.go:1069 lxc/storage_volume.go:1142 lxc/storage_volume.go:1173 lxc/storage_volume.go:1286 lxc/storage_volume.go:1362 lxc/storage_volume.go:1461 lxc/storage_volume.go:1492 lxc/storage_volume.go:1563 lxc/version.go:22
+#: lxc/action.go:31 lxc/action.go:50 lxc/action.go:70 lxc/action.go:91 lxc/alias.go:22 lxc/alias.go:54 lxc/alias.go:100 lxc/alias.go:144 lxc/alias.go:195 lxc/cluster.go:29 lxc/cluster.go:68 lxc/cluster.go:147 lxc/cluster.go:197 lxc/cluster.go:247 lxc/cluster.go:332 lxc/config.go:31 lxc/config.go:90 lxc/config.go:373 lxc/config.go:454 lxc/config.go:612 lxc/config.go:731 lxc/config_device.go:24 lxc/config_device.go:76 lxc/config_device.go:188 lxc/config_device.go:261 lxc/config_device.go:327 lxc/config_device.go:416 lxc/config_device.go:507 lxc/config_device.go:513 lxc/config_device.go:613 lxc/config_device.go:681 lxc/config_metadata.go:28 lxc/config_metadata.go:53 lxc/config_metadata.go:175 lxc/config_template.go:29 lxc/config_template.go:66 lxc/config_template.go:109 lxc/config_template.go:151 lxc/config_template.go:237 lxc/config_template.go:296 lxc/config_trust.go:29 lxc/config_trust.go:58 lxc/config_trust.go:116 lxc/config_trust.go:194 lxc/console.go:31 lxc/copy.go:41 lxc/delete.go:30 lxc/exec.go:40 lxc/export.go:33 lxc/file.go:72 lxc/file.go:105 lxc/file.go:154 lxc/file.go:217 lxc/file.go:407 lxc/image.go:38 lxc/image.go:128 lxc/image.go:270 lxc/image.go:321 lxc/image.go:446 lxc/image.go:605 lxc/image.go:833 lxc/image.go:968 lxc/image.go:1266 lxc/image.go:1345 lxc/image_alias.go:25 lxc/image_alias.go:58 lxc/image_alias.go:105 lxc/image_alias.go:150 lxc/image_alias.go:252 lxc/import.go:28 lxc/info.go:33 lxc/init.go:40 lxc/launch.go:23 lxc/list.go:44 lxc/main.go:50 lxc/manpage.go:19 lxc/monitor.go:30 lxc/move.go:37 lxc/network.go:32 lxc/network.go:108 lxc/network.go:181 lxc/network.go:254 lxc/network.go:326 lxc/network.go:376 lxc/network.go:461 lxc/network.go:546 lxc/network.go:669 lxc/network.go:727 lxc/network.go:807 lxc/network.go:892 lxc/network.go:961 lxc/network.go:1011 lxc/network.go:1081 lxc/network.go:1143 lxc/operation.go:24 lxc/operation.go:53 lxc/operation.go:102 lxc/operation.go:181 lxc/profile.go:29 lxc/profile.go:101 lxc/profile.go:164 lxc/profile.go:244 lxc/profile.go:300 lxc/profile.go:354 lxc/profile.go:404 lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712 lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29 lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334 lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590 lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31 lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455 lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685 lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33 lxc/storage.go:89 lxc/storage.go:163 lxc/storage.go:213 lxc/storage.go:333 lxc/storage.go:388 lxc/storage.go:508 lxc/storage.go:582 lxc/storage.go:651 lxc/storage.go:735 lxc/storage_volume.go:32 lxc/storage_volume.go:139 lxc/storage_volume.go:218 lxc/storage_volume.go:301 lxc/storage_volume.go:462 lxc/storage_volume.go:539 lxc/storage_volume.go:615 lxc/storage_volume.go:697 lxc/storage_volume.go:778 lxc/storage_volume.go:978 lxc/storage_volume.go:1069 lxc/storage_volume.go:1142 lxc/storage_volume.go:1173 lxc/storage_volume.go:1286 lxc/storage_volume.go:1362 lxc/storage_volume.go:1461 lxc/storage_volume.go:1492 lxc/storage_volume.go:1563 lxc/version.go:22
 msgid   "Description"
 msgstr  ""
 
@@ -1211,7 +1211,7 @@ msgstr  ""
 msgid   "ID: %s"
 msgstr  ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid   "IMAGES"
 msgstr  ""
 
@@ -1789,7 +1789,7 @@ msgstr  ""
 msgid   "Missing profile name"
 msgstr  ""
 
-#: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358 lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358 lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 msgid   "Missing project name"
 msgstr  ""
 
@@ -1862,7 +1862,7 @@ msgstr  ""
 msgid   "Must supply instance name for: "
 msgstr  ""
 
-#: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620 lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558 lxc/storage_volume.go:1118
+#: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620 lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558 lxc/storage_volume.go:1118
 msgid   "NAME"
 msgstr  ""
 
@@ -1874,7 +1874,7 @@ msgstr  ""
 msgid   "NICs:"
 msgstr  ""
 
-#: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428 lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428 lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid   "NO"
 msgstr  ""
 
@@ -2018,7 +2018,7 @@ msgstr  ""
 msgid   "PROCESSES"
 msgstr  ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid   "PROFILES"
 msgstr  ""
 
@@ -2174,7 +2174,7 @@ msgstr  ""
 msgid   "Project %s deleted"
 msgstr  ""
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, c-format
 msgid   "Project %s renamed to %s"
 msgstr  ""
@@ -2251,7 +2251,7 @@ msgstr  ""
 msgid   "Remote %s already exists"
 msgstr  ""
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667 lxc/remote.go:705
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667 lxc/remote.go:705
 #, c-format
 msgid   "Remote %s doesn't exist"
 msgstr  ""
@@ -2333,7 +2333,7 @@ msgstr  ""
 msgid   "Rename profiles"
 msgstr  ""
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 msgid   "Rename projects"
 msgstr  ""
 
@@ -2436,6 +2436,10 @@ msgstr  ""
 msgid   "STORAGE POOL"
 msgstr  ""
 
+#: lxc/project.go:457
+msgid   "STORAGE VOLUMES"
+msgstr  ""
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid   "Send a raw query to LXD"
 msgstr  ""
@@ -2512,11 +2516,11 @@ msgid   "Set profile configuration keys\n"
         "    lxc profile set [<remote>:]<profile> <key> <value>"
 msgstr  ""
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 msgid   "Set project configuration keys"
 msgstr  ""
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid   "Set project configuration keys\n"
         "\n"
         "For backward compatibility, a single configuration key may still be set with:\n"
@@ -2617,7 +2621,7 @@ msgstr  ""
 msgid   "Show profile configurations"
 msgstr  ""
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 msgid   "Show project options"
 msgstr  ""
 
@@ -2792,7 +2796,7 @@ msgstr  ""
 msgid   "Swap (peak)"
 msgstr  ""
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 msgid   "Switch the current project"
 msgstr  ""
 
@@ -2965,7 +2969,7 @@ msgstr  ""
 msgid   "URL"
 msgstr  ""
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567 lxc/storage_volume.go:1120
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567 lxc/storage_volume.go:1120
 msgid   "USED BY"
 msgstr  ""
 
@@ -3009,7 +3013,7 @@ msgstr  ""
 msgid   "Unset profile configuration keys"
 msgstr  ""
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 msgid   "Unset project configuration keys"
 msgstr  ""
 
@@ -3097,7 +3101,7 @@ msgstr  ""
 msgid   "Whether or not to snapshot the instance's running state"
 msgstr  ""
 
-#: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430 lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430 lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid   "YES"
 msgstr  ""
 
@@ -3217,7 +3221,7 @@ msgstr  ""
 msgid   "create [<remote>:]<project>"
 msgstr  ""
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 msgid   "current"
 msgstr  ""
 
@@ -3804,7 +3808,7 @@ msgstr  ""
 msgid   "rename [<remote>:]<profile> <new-name>"
 msgstr  ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid   "rename [<remote>:]<project> <new-name>"
 msgstr  ""
 
@@ -3840,7 +3844,7 @@ msgstr  ""
 msgid   "set [<remote>:]<profile> <key><value>..."
 msgstr  ""
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 msgid   "set [<remote>:]<project> <key>=<value>..."
 msgstr  ""
 
@@ -3892,7 +3896,7 @@ msgstr  ""
 msgid   "show [<remote>:]<profile>"
 msgstr  ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid   "show [<remote>:]<project>"
 msgstr  ""
 
@@ -3936,7 +3940,7 @@ msgstr  ""
 msgid   "switch <remote>"
 msgstr  ""
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 msgid   "switch [<remote>:]<project>"
 msgstr  ""
 
@@ -3981,7 +3985,7 @@ msgstr  ""
 msgid   "unset [<remote>:]<profile> <key>"
 msgstr  ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 msgid   "unset [<remote>:]<project> <key>"
 msgstr  ""
 
diff --git a/po/nb_NO.po b/po/nb_NO.po
index bda7d36132..160c694865 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: 2020-02-26 08:16-0500\n"
+"POT-Creation-Date: 2020-03-04 10:28+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -860,8 +860,8 @@ msgstr ""
 #: lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712
 #: lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29
 #: lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334
-#: lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584
-#: lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31
+#: lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590
+#: lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31
 #: lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455
 #: lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685
 #: lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33
@@ -1308,7 +1308,7 @@ msgstr ""
 msgid "ID: %s"
 msgstr ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid "IMAGES"
 msgstr ""
 
@@ -1921,7 +1921,7 @@ msgid "Missing profile name"
 msgstr ""
 
 #: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358
-#: lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 msgid "Missing project name"
 msgstr ""
 
@@ -1997,7 +1997,7 @@ msgid "Must supply instance name for: "
 msgstr ""
 
 #: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620
-#: lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558
+#: lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558
 #: lxc/storage_volume.go:1118
 msgid "NAME"
 msgstr ""
@@ -2011,7 +2011,7 @@ msgid "NICs:"
 msgstr ""
 
 #: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428
-#: lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid "NO"
 msgstr ""
 
@@ -2155,7 +2155,7 @@ msgstr ""
 msgid "PROCESSES"
 msgstr ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid "PROFILES"
 msgstr ""
 
@@ -2313,7 +2313,7 @@ msgstr ""
 msgid "Project %s deleted"
 msgstr ""
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, c-format
 msgid "Project %s renamed to %s"
 msgstr ""
@@ -2390,7 +2390,7 @@ msgstr ""
 msgid "Remote %s already exists"
 msgstr ""
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
 #: lxc/remote.go:705
 #, c-format
 msgid "Remote %s doesn't exist"
@@ -2474,7 +2474,7 @@ msgstr ""
 msgid "Rename profiles"
 msgstr ""
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 msgid "Rename projects"
 msgstr ""
 
@@ -2579,6 +2579,10 @@ msgstr ""
 msgid "STORAGE POOL"
 msgstr ""
 
+#: lxc/project.go:457
+msgid "STORAGE VOLUMES"
+msgstr ""
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid "Send a raw query to LXD"
 msgstr ""
@@ -2665,11 +2669,11 @@ msgid ""
 "    lxc profile set [<remote>:]<profile> <key> <value>"
 msgstr ""
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 msgid "Set project configuration keys"
 msgstr ""
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid ""
 "Set project configuration keys\n"
 "\n"
@@ -2776,7 +2780,7 @@ msgstr ""
 msgid "Show profile configurations"
 msgstr ""
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 msgid "Show project options"
 msgstr ""
 
@@ -2951,7 +2955,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 msgid "Switch the current project"
 msgstr ""
 
@@ -3134,7 +3138,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567
 #: lxc/storage_volume.go:1120
 msgid "USED BY"
 msgstr ""
@@ -3179,7 +3183,7 @@ msgstr ""
 msgid "Unset profile configuration keys"
 msgstr ""
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 msgid "Unset project configuration keys"
 msgstr ""
 
@@ -3274,7 +3278,7 @@ msgid "Whether or not to snapshot the instance's running state"
 msgstr ""
 
 #: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430
-#: lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid "YES"
 msgstr ""
 
@@ -3398,7 +3402,7 @@ msgstr ""
 msgid "create [<remote>:]<project>"
 msgstr ""
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 msgid "current"
 msgstr ""
 
@@ -4037,7 +4041,7 @@ msgstr ""
 msgid "rename [<remote>:]<profile> <new-name>"
 msgstr ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid "rename [<remote>:]<project> <new-name>"
 msgstr ""
 
@@ -4073,7 +4077,7 @@ msgstr ""
 msgid "set [<remote>:]<profile> <key><value>..."
 msgstr ""
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 msgid "set [<remote>:]<project> <key>=<value>..."
 msgstr ""
 
@@ -4125,7 +4129,7 @@ msgstr ""
 msgid "show [<remote>:]<profile>"
 msgstr ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid "show [<remote>:]<project>"
 msgstr ""
 
@@ -4169,7 +4173,7 @@ msgstr ""
 msgid "switch <remote>"
 msgstr ""
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 msgid "switch [<remote>:]<project>"
 msgstr ""
 
@@ -4214,7 +4218,7 @@ msgstr ""
 msgid "unset [<remote>:]<profile> <key>"
 msgstr ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 msgid "unset [<remote>:]<project> <key>"
 msgstr ""
 
diff --git a/po/nl.po b/po/nl.po
index a6f5c739f1..6dc57ab642 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: 2020-02-26 08:16-0500\n"
+"POT-Creation-Date: 2020-03-04 10:28+0000\n"
 "PO-Revision-Date: 2019-09-06 07:09+0000\n"
 "Last-Translator: Stéphane Graber <stgraber at stgraber.org>\n"
 "Language-Team: Dutch <https://hosted.weblate.org/projects/linux-containers/"
@@ -977,8 +977,8 @@ msgstr ""
 #: lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712
 #: lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29
 #: lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334
-#: lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584
-#: lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31
+#: lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590
+#: lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31
 #: lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455
 #: lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685
 #: lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33
@@ -1425,7 +1425,7 @@ msgstr ""
 msgid "ID: %s"
 msgstr ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid "IMAGES"
 msgstr ""
 
@@ -2038,7 +2038,7 @@ msgid "Missing profile name"
 msgstr ""
 
 #: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358
-#: lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 msgid "Missing project name"
 msgstr ""
 
@@ -2114,7 +2114,7 @@ msgid "Must supply instance name for: "
 msgstr ""
 
 #: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620
-#: lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558
+#: lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558
 #: lxc/storage_volume.go:1118
 msgid "NAME"
 msgstr ""
@@ -2128,7 +2128,7 @@ msgid "NICs:"
 msgstr ""
 
 #: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428
-#: lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid "NO"
 msgstr ""
 
@@ -2272,7 +2272,7 @@ msgstr ""
 msgid "PROCESSES"
 msgstr ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid "PROFILES"
 msgstr ""
 
@@ -2430,7 +2430,7 @@ msgstr ""
 msgid "Project %s deleted"
 msgstr ""
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, c-format
 msgid "Project %s renamed to %s"
 msgstr ""
@@ -2507,7 +2507,7 @@ msgstr ""
 msgid "Remote %s already exists"
 msgstr ""
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
 #: lxc/remote.go:705
 #, c-format
 msgid "Remote %s doesn't exist"
@@ -2591,7 +2591,7 @@ msgstr ""
 msgid "Rename profiles"
 msgstr ""
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 msgid "Rename projects"
 msgstr ""
 
@@ -2696,6 +2696,10 @@ msgstr ""
 msgid "STORAGE POOL"
 msgstr ""
 
+#: lxc/project.go:457
+msgid "STORAGE VOLUMES"
+msgstr ""
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid "Send a raw query to LXD"
 msgstr ""
@@ -2782,11 +2786,11 @@ msgid ""
 "    lxc profile set [<remote>:]<profile> <key> <value>"
 msgstr ""
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 msgid "Set project configuration keys"
 msgstr ""
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid ""
 "Set project configuration keys\n"
 "\n"
@@ -2893,7 +2897,7 @@ msgstr ""
 msgid "Show profile configurations"
 msgstr ""
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 msgid "Show project options"
 msgstr ""
 
@@ -3068,7 +3072,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 msgid "Switch the current project"
 msgstr ""
 
@@ -3251,7 +3255,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567
 #: lxc/storage_volume.go:1120
 msgid "USED BY"
 msgstr ""
@@ -3296,7 +3300,7 @@ msgstr ""
 msgid "Unset profile configuration keys"
 msgstr ""
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 msgid "Unset project configuration keys"
 msgstr ""
 
@@ -3391,7 +3395,7 @@ msgid "Whether or not to snapshot the instance's running state"
 msgstr ""
 
 #: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430
-#: lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid "YES"
 msgstr ""
 
@@ -3515,7 +3519,7 @@ msgstr ""
 msgid "create [<remote>:]<project>"
 msgstr ""
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 msgid "current"
 msgstr ""
 
@@ -4154,7 +4158,7 @@ msgstr ""
 msgid "rename [<remote>:]<profile> <new-name>"
 msgstr ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid "rename [<remote>:]<project> <new-name>"
 msgstr ""
 
@@ -4190,7 +4194,7 @@ msgstr ""
 msgid "set [<remote>:]<profile> <key><value>..."
 msgstr ""
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 msgid "set [<remote>:]<project> <key>=<value>..."
 msgstr ""
 
@@ -4242,7 +4246,7 @@ msgstr ""
 msgid "show [<remote>:]<profile>"
 msgstr ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid "show [<remote>:]<project>"
 msgstr ""
 
@@ -4286,7 +4290,7 @@ msgstr ""
 msgid "switch <remote>"
 msgstr ""
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 msgid "switch [<remote>:]<project>"
 msgstr ""
 
@@ -4331,7 +4335,7 @@ msgstr ""
 msgid "unset [<remote>:]<profile> <key>"
 msgstr ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 msgid "unset [<remote>:]<project> <key>"
 msgstr ""
 
diff --git a/po/pa.po b/po/pa.po
index c45cbeb18f..2118ffc77f 100644
--- a/po/pa.po
+++ b/po/pa.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: 2020-02-26 08:16-0500\n"
+"POT-Creation-Date: 2020-03-04 10:28+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -860,8 +860,8 @@ msgstr ""
 #: lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712
 #: lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29
 #: lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334
-#: lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584
-#: lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31
+#: lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590
+#: lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31
 #: lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455
 #: lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685
 #: lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33
@@ -1308,7 +1308,7 @@ msgstr ""
 msgid "ID: %s"
 msgstr ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid "IMAGES"
 msgstr ""
 
@@ -1921,7 +1921,7 @@ msgid "Missing profile name"
 msgstr ""
 
 #: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358
-#: lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 msgid "Missing project name"
 msgstr ""
 
@@ -1997,7 +1997,7 @@ msgid "Must supply instance name for: "
 msgstr ""
 
 #: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620
-#: lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558
+#: lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558
 #: lxc/storage_volume.go:1118
 msgid "NAME"
 msgstr ""
@@ -2011,7 +2011,7 @@ msgid "NICs:"
 msgstr ""
 
 #: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428
-#: lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid "NO"
 msgstr ""
 
@@ -2155,7 +2155,7 @@ msgstr ""
 msgid "PROCESSES"
 msgstr ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid "PROFILES"
 msgstr ""
 
@@ -2313,7 +2313,7 @@ msgstr ""
 msgid "Project %s deleted"
 msgstr ""
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, c-format
 msgid "Project %s renamed to %s"
 msgstr ""
@@ -2390,7 +2390,7 @@ msgstr ""
 msgid "Remote %s already exists"
 msgstr ""
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
 #: lxc/remote.go:705
 #, c-format
 msgid "Remote %s doesn't exist"
@@ -2474,7 +2474,7 @@ msgstr ""
 msgid "Rename profiles"
 msgstr ""
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 msgid "Rename projects"
 msgstr ""
 
@@ -2579,6 +2579,10 @@ msgstr ""
 msgid "STORAGE POOL"
 msgstr ""
 
+#: lxc/project.go:457
+msgid "STORAGE VOLUMES"
+msgstr ""
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid "Send a raw query to LXD"
 msgstr ""
@@ -2665,11 +2669,11 @@ msgid ""
 "    lxc profile set [<remote>:]<profile> <key> <value>"
 msgstr ""
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 msgid "Set project configuration keys"
 msgstr ""
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid ""
 "Set project configuration keys\n"
 "\n"
@@ -2776,7 +2780,7 @@ msgstr ""
 msgid "Show profile configurations"
 msgstr ""
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 msgid "Show project options"
 msgstr ""
 
@@ -2951,7 +2955,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 msgid "Switch the current project"
 msgstr ""
 
@@ -3134,7 +3138,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567
 #: lxc/storage_volume.go:1120
 msgid "USED BY"
 msgstr ""
@@ -3179,7 +3183,7 @@ msgstr ""
 msgid "Unset profile configuration keys"
 msgstr ""
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 msgid "Unset project configuration keys"
 msgstr ""
 
@@ -3274,7 +3278,7 @@ msgid "Whether or not to snapshot the instance's running state"
 msgstr ""
 
 #: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430
-#: lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid "YES"
 msgstr ""
 
@@ -3398,7 +3402,7 @@ msgstr ""
 msgid "create [<remote>:]<project>"
 msgstr ""
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 msgid "current"
 msgstr ""
 
@@ -4037,7 +4041,7 @@ msgstr ""
 msgid "rename [<remote>:]<profile> <new-name>"
 msgstr ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid "rename [<remote>:]<project> <new-name>"
 msgstr ""
 
@@ -4073,7 +4077,7 @@ msgstr ""
 msgid "set [<remote>:]<profile> <key><value>..."
 msgstr ""
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 msgid "set [<remote>:]<project> <key>=<value>..."
 msgstr ""
 
@@ -4125,7 +4129,7 @@ msgstr ""
 msgid "show [<remote>:]<profile>"
 msgstr ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid "show [<remote>:]<project>"
 msgstr ""
 
@@ -4169,7 +4173,7 @@ msgstr ""
 msgid "switch <remote>"
 msgstr ""
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 msgid "switch [<remote>:]<project>"
 msgstr ""
 
@@ -4214,7 +4218,7 @@ msgstr ""
 msgid "unset [<remote>:]<profile> <key>"
 msgstr ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 msgid "unset [<remote>:]<project> <key>"
 msgstr ""
 
diff --git a/po/pl.po b/po/pl.po
index 913cc15802..d0ef1dd9fe 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: 2020-02-26 08:16-0500\n"
+"POT-Creation-Date: 2020-03-04 10:28+0000\n"
 "PO-Revision-Date: 2018-09-08 19:22+0000\n"
 "Last-Translator: m4sk1n <me at m4sk.in>\n"
 "Language-Team: Polish <https://hosted.weblate.org/projects/linux-containers/"
@@ -987,8 +987,8 @@ msgstr ""
 #: lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712
 #: lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29
 #: lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334
-#: lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584
-#: lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31
+#: lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590
+#: lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31
 #: lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455
 #: lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685
 #: lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33
@@ -1435,7 +1435,7 @@ msgstr ""
 msgid "ID: %s"
 msgstr ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid "IMAGES"
 msgstr ""
 
@@ -2048,7 +2048,7 @@ msgid "Missing profile name"
 msgstr ""
 
 #: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358
-#: lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 msgid "Missing project name"
 msgstr ""
 
@@ -2124,7 +2124,7 @@ msgid "Must supply instance name for: "
 msgstr ""
 
 #: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620
-#: lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558
+#: lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558
 #: lxc/storage_volume.go:1118
 msgid "NAME"
 msgstr ""
@@ -2138,7 +2138,7 @@ msgid "NICs:"
 msgstr ""
 
 #: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428
-#: lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid "NO"
 msgstr ""
 
@@ -2282,7 +2282,7 @@ msgstr ""
 msgid "PROCESSES"
 msgstr ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid "PROFILES"
 msgstr ""
 
@@ -2440,7 +2440,7 @@ msgstr ""
 msgid "Project %s deleted"
 msgstr ""
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, c-format
 msgid "Project %s renamed to %s"
 msgstr ""
@@ -2517,7 +2517,7 @@ msgstr ""
 msgid "Remote %s already exists"
 msgstr ""
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
 #: lxc/remote.go:705
 #, c-format
 msgid "Remote %s doesn't exist"
@@ -2601,7 +2601,7 @@ msgstr ""
 msgid "Rename profiles"
 msgstr ""
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 msgid "Rename projects"
 msgstr ""
 
@@ -2706,6 +2706,10 @@ msgstr ""
 msgid "STORAGE POOL"
 msgstr ""
 
+#: lxc/project.go:457
+msgid "STORAGE VOLUMES"
+msgstr ""
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid "Send a raw query to LXD"
 msgstr ""
@@ -2792,11 +2796,11 @@ msgid ""
 "    lxc profile set [<remote>:]<profile> <key> <value>"
 msgstr ""
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 msgid "Set project configuration keys"
 msgstr ""
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid ""
 "Set project configuration keys\n"
 "\n"
@@ -2903,7 +2907,7 @@ msgstr ""
 msgid "Show profile configurations"
 msgstr ""
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 msgid "Show project options"
 msgstr ""
 
@@ -3078,7 +3082,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 msgid "Switch the current project"
 msgstr ""
 
@@ -3261,7 +3265,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567
 #: lxc/storage_volume.go:1120
 msgid "USED BY"
 msgstr ""
@@ -3306,7 +3310,7 @@ msgstr ""
 msgid "Unset profile configuration keys"
 msgstr ""
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 msgid "Unset project configuration keys"
 msgstr ""
 
@@ -3401,7 +3405,7 @@ msgid "Whether or not to snapshot the instance's running state"
 msgstr ""
 
 #: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430
-#: lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid "YES"
 msgstr ""
 
@@ -3525,7 +3529,7 @@ msgstr ""
 msgid "create [<remote>:]<project>"
 msgstr ""
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 msgid "current"
 msgstr ""
 
@@ -4164,7 +4168,7 @@ msgstr ""
 msgid "rename [<remote>:]<profile> <new-name>"
 msgstr ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid "rename [<remote>:]<project> <new-name>"
 msgstr ""
 
@@ -4200,7 +4204,7 @@ msgstr ""
 msgid "set [<remote>:]<profile> <key><value>..."
 msgstr ""
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 msgid "set [<remote>:]<project> <key>=<value>..."
 msgstr ""
 
@@ -4252,7 +4256,7 @@ msgstr ""
 msgid "show [<remote>:]<profile>"
 msgstr ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid "show [<remote>:]<project>"
 msgstr ""
 
@@ -4296,7 +4300,7 @@ msgstr ""
 msgid "switch <remote>"
 msgstr ""
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 msgid "switch [<remote>:]<project>"
 msgstr ""
 
@@ -4341,7 +4345,7 @@ msgstr ""
 msgid "unset [<remote>:]<profile> <key>"
 msgstr ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 msgid "unset [<remote>:]<project> <key>"
 msgstr ""
 
diff --git a/po/pt_BR.po b/po/pt_BR.po
index f2acde76fb..7f7c2b8be4 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: 2020-02-26 08:16-0500\n"
+"POT-Creation-Date: 2020-03-04 10:28+0000\n"
 "PO-Revision-Date: 2019-09-06 07:09+0000\n"
 "Last-Translator: Stéphane Graber <stgraber at stgraber.org>\n"
 "Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/"
@@ -1020,8 +1020,8 @@ msgstr ""
 #: lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712
 #: lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29
 #: lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334
-#: lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584
-#: lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31
+#: lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590
+#: lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31
 #: lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455
 #: lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685
 #: lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33
@@ -1480,7 +1480,7 @@ msgstr ""
 msgid "ID: %s"
 msgstr ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid "IMAGES"
 msgstr ""
 
@@ -2099,7 +2099,7 @@ msgid "Missing profile name"
 msgstr ""
 
 #: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358
-#: lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 msgid "Missing project name"
 msgstr ""
 
@@ -2175,7 +2175,7 @@ msgid "Must supply instance name for: "
 msgstr ""
 
 #: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620
-#: lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558
+#: lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558
 #: lxc/storage_volume.go:1118
 msgid "NAME"
 msgstr ""
@@ -2189,7 +2189,7 @@ msgid "NICs:"
 msgstr ""
 
 #: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428
-#: lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid "NO"
 msgstr ""
 
@@ -2333,7 +2333,7 @@ msgstr ""
 msgid "PROCESSES"
 msgstr ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid "PROFILES"
 msgstr ""
 
@@ -2495,7 +2495,7 @@ msgstr ""
 msgid "Project %s deleted"
 msgstr ""
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, c-format
 msgid "Project %s renamed to %s"
 msgstr ""
@@ -2573,7 +2573,7 @@ msgstr ""
 msgid "Remote %s already exists"
 msgstr ""
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
 #: lxc/remote.go:705
 #, c-format
 msgid "Remote %s doesn't exist"
@@ -2658,7 +2658,7 @@ msgstr ""
 msgid "Rename profiles"
 msgstr ""
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 msgid "Rename projects"
 msgstr ""
 
@@ -2763,6 +2763,10 @@ msgstr ""
 msgid "STORAGE POOL"
 msgstr ""
 
+#: lxc/project.go:457
+msgid "STORAGE VOLUMES"
+msgstr ""
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid "Send a raw query to LXD"
 msgstr ""
@@ -2851,12 +2855,12 @@ msgid ""
 "    lxc profile set [<remote>:]<profile> <key> <value>"
 msgstr ""
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 #, fuzzy
 msgid "Set project configuration keys"
 msgstr "Editar configurações de perfil como YAML"
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid ""
 "Set project configuration keys\n"
 "\n"
@@ -2968,7 +2972,7 @@ msgstr ""
 msgid "Show profile configurations"
 msgstr ""
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 msgid "Show project options"
 msgstr ""
 
@@ -3144,7 +3148,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 msgid "Switch the current project"
 msgstr ""
 
@@ -3327,7 +3331,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567
 #: lxc/storage_volume.go:1120
 msgid "USED BY"
 msgstr ""
@@ -3375,7 +3379,7 @@ msgstr ""
 msgid "Unset profile configuration keys"
 msgstr ""
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 #, fuzzy
 msgid "Unset project configuration keys"
 msgstr "Editar configurações de perfil como YAML"
@@ -3471,7 +3475,7 @@ msgid "Whether or not to snapshot the instance's running state"
 msgstr ""
 
 #: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430
-#: lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid "YES"
 msgstr ""
 
@@ -3595,7 +3599,7 @@ msgstr ""
 msgid "create [<remote>:]<project>"
 msgstr ""
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 msgid "current"
 msgstr ""
 
@@ -4234,7 +4238,7 @@ msgstr ""
 msgid "rename [<remote>:]<profile> <new-name>"
 msgstr ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid "rename [<remote>:]<project> <new-name>"
 msgstr ""
 
@@ -4270,7 +4274,7 @@ msgstr ""
 msgid "set [<remote>:]<profile> <key><value>..."
 msgstr ""
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 msgid "set [<remote>:]<project> <key>=<value>..."
 msgstr ""
 
@@ -4322,7 +4326,7 @@ msgstr ""
 msgid "show [<remote>:]<profile>"
 msgstr ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid "show [<remote>:]<project>"
 msgstr ""
 
@@ -4366,7 +4370,7 @@ msgstr ""
 msgid "switch <remote>"
 msgstr ""
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 msgid "switch [<remote>:]<project>"
 msgstr ""
 
@@ -4411,7 +4415,7 @@ msgstr ""
 msgid "unset [<remote>:]<profile> <key>"
 msgstr ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 msgid "unset [<remote>:]<project> <key>"
 msgstr ""
 
diff --git a/po/ru.po b/po/ru.po
index 89058b1f77..a46dc574e0 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: 2020-02-26 08:16-0500\n"
+"POT-Creation-Date: 2020-03-04 10:28+0000\n"
 "PO-Revision-Date: 2018-06-22 15:57+0000\n"
 "Last-Translator: Александр Киль <shorrey at gmail.com>\n"
 "Language-Team: Russian <https://hosted.weblate.org/projects/linux-containers/"
@@ -1009,8 +1009,8 @@ msgstr "Копирование образа: %s"
 #: lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712
 #: lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29
 #: lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334
-#: lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584
-#: lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31
+#: lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590
+#: lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31
 #: lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455
 #: lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685
 #: lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33
@@ -1466,7 +1466,7 @@ msgstr ""
 msgid "ID: %s"
 msgstr ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid "IMAGES"
 msgstr ""
 
@@ -2096,7 +2096,7 @@ msgid "Missing profile name"
 msgstr ""
 
 #: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358
-#: lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 #, fuzzy
 msgid "Missing project name"
 msgstr "Имя контейнера: %s"
@@ -2175,7 +2175,7 @@ msgid "Must supply instance name for: "
 msgstr ""
 
 #: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620
-#: lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558
+#: lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558
 #: lxc/storage_volume.go:1118
 msgid "NAME"
 msgstr ""
@@ -2189,7 +2189,7 @@ msgid "NICs:"
 msgstr ""
 
 #: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428
-#: lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid "NO"
 msgstr ""
 
@@ -2335,7 +2335,7 @@ msgstr ""
 msgid "PROCESSES"
 msgstr ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid "PROFILES"
 msgstr ""
 
@@ -2493,7 +2493,7 @@ msgstr ""
 msgid "Project %s deleted"
 msgstr ""
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, c-format
 msgid "Project %s renamed to %s"
 msgstr ""
@@ -2571,7 +2571,7 @@ msgstr "Копирование образа: %s"
 msgid "Remote %s already exists"
 msgstr ""
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
 #: lxc/remote.go:705
 #, c-format
 msgid "Remote %s doesn't exist"
@@ -2657,7 +2657,7 @@ msgstr ""
 msgid "Rename profiles"
 msgstr ""
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 msgid "Rename projects"
 msgstr ""
 
@@ -2766,6 +2766,10 @@ msgstr ""
 msgid "STORAGE POOL"
 msgstr ""
 
+#: lxc/project.go:457
+msgid "STORAGE VOLUMES"
+msgstr ""
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid "Send a raw query to LXD"
 msgstr ""
@@ -2852,11 +2856,11 @@ msgid ""
 "    lxc profile set [<remote>:]<profile> <key> <value>"
 msgstr ""
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 msgid "Set project configuration keys"
 msgstr ""
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid ""
 "Set project configuration keys\n"
 "\n"
@@ -2965,7 +2969,7 @@ msgstr ""
 msgid "Show profile configurations"
 msgstr ""
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 msgid "Show project options"
 msgstr ""
 
@@ -3144,7 +3148,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 msgid "Switch the current project"
 msgstr ""
 
@@ -3327,7 +3331,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567
 #: lxc/storage_volume.go:1120
 msgid "USED BY"
 msgstr ""
@@ -3372,7 +3376,7 @@ msgstr ""
 msgid "Unset profile configuration keys"
 msgstr ""
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 msgid "Unset project configuration keys"
 msgstr ""
 
@@ -3467,7 +3471,7 @@ msgid "Whether or not to snapshot the instance's running state"
 msgstr ""
 
 #: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430
-#: lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid "YES"
 msgstr ""
 
@@ -3612,7 +3616,7 @@ msgstr ""
 msgid "create [<remote>:]<project>"
 msgstr ""
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 msgid "current"
 msgstr ""
 
@@ -4387,7 +4391,7 @@ msgstr ""
 msgid "rename [<remote>:]<profile> <new-name>"
 msgstr ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid "rename [<remote>:]<project> <new-name>"
 msgstr ""
 
@@ -4451,7 +4455,7 @@ msgstr ""
 "\n"
 "lxc %s [<remote>:]<container> [[<remote>:]<container>...]%s"
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 #, fuzzy
 msgid "set [<remote>:]<project> <key>=<value>..."
 msgstr ""
@@ -4527,7 +4531,7 @@ msgstr ""
 msgid "show [<remote>:]<profile>"
 msgstr ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid "show [<remote>:]<project>"
 msgstr ""
 
@@ -4591,7 +4595,7 @@ msgstr ""
 msgid "switch <remote>"
 msgstr ""
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 #, fuzzy
 msgid "switch [<remote>:]<project>"
 msgstr ""
@@ -4644,7 +4648,7 @@ msgstr ""
 msgid "unset [<remote>:]<profile> <key>"
 msgstr ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 #, fuzzy
 msgid "unset [<remote>:]<project> <key>"
 msgstr ""
diff --git a/po/sl.po b/po/sl.po
index 3a0f8cad99..1dbcfd89a5 100644
--- a/po/sl.po
+++ b/po/sl.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: 2020-02-26 08:16-0500\n"
+"POT-Creation-Date: 2020-03-04 10:28+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -860,8 +860,8 @@ msgstr ""
 #: lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712
 #: lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29
 #: lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334
-#: lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584
-#: lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31
+#: lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590
+#: lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31
 #: lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455
 #: lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685
 #: lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33
@@ -1308,7 +1308,7 @@ msgstr ""
 msgid "ID: %s"
 msgstr ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid "IMAGES"
 msgstr ""
 
@@ -1921,7 +1921,7 @@ msgid "Missing profile name"
 msgstr ""
 
 #: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358
-#: lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 msgid "Missing project name"
 msgstr ""
 
@@ -1997,7 +1997,7 @@ msgid "Must supply instance name for: "
 msgstr ""
 
 #: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620
-#: lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558
+#: lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558
 #: lxc/storage_volume.go:1118
 msgid "NAME"
 msgstr ""
@@ -2011,7 +2011,7 @@ msgid "NICs:"
 msgstr ""
 
 #: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428
-#: lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid "NO"
 msgstr ""
 
@@ -2155,7 +2155,7 @@ msgstr ""
 msgid "PROCESSES"
 msgstr ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid "PROFILES"
 msgstr ""
 
@@ -2313,7 +2313,7 @@ msgstr ""
 msgid "Project %s deleted"
 msgstr ""
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, c-format
 msgid "Project %s renamed to %s"
 msgstr ""
@@ -2390,7 +2390,7 @@ msgstr ""
 msgid "Remote %s already exists"
 msgstr ""
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
 #: lxc/remote.go:705
 #, c-format
 msgid "Remote %s doesn't exist"
@@ -2474,7 +2474,7 @@ msgstr ""
 msgid "Rename profiles"
 msgstr ""
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 msgid "Rename projects"
 msgstr ""
 
@@ -2579,6 +2579,10 @@ msgstr ""
 msgid "STORAGE POOL"
 msgstr ""
 
+#: lxc/project.go:457
+msgid "STORAGE VOLUMES"
+msgstr ""
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid "Send a raw query to LXD"
 msgstr ""
@@ -2665,11 +2669,11 @@ msgid ""
 "    lxc profile set [<remote>:]<profile> <key> <value>"
 msgstr ""
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 msgid "Set project configuration keys"
 msgstr ""
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid ""
 "Set project configuration keys\n"
 "\n"
@@ -2776,7 +2780,7 @@ msgstr ""
 msgid "Show profile configurations"
 msgstr ""
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 msgid "Show project options"
 msgstr ""
 
@@ -2951,7 +2955,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 msgid "Switch the current project"
 msgstr ""
 
@@ -3134,7 +3138,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567
 #: lxc/storage_volume.go:1120
 msgid "USED BY"
 msgstr ""
@@ -3179,7 +3183,7 @@ msgstr ""
 msgid "Unset profile configuration keys"
 msgstr ""
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 msgid "Unset project configuration keys"
 msgstr ""
 
@@ -3274,7 +3278,7 @@ msgid "Whether or not to snapshot the instance's running state"
 msgstr ""
 
 #: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430
-#: lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid "YES"
 msgstr ""
 
@@ -3398,7 +3402,7 @@ msgstr ""
 msgid "create [<remote>:]<project>"
 msgstr ""
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 msgid "current"
 msgstr ""
 
@@ -4037,7 +4041,7 @@ msgstr ""
 msgid "rename [<remote>:]<profile> <new-name>"
 msgstr ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid "rename [<remote>:]<project> <new-name>"
 msgstr ""
 
@@ -4073,7 +4077,7 @@ msgstr ""
 msgid "set [<remote>:]<profile> <key><value>..."
 msgstr ""
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 msgid "set [<remote>:]<project> <key>=<value>..."
 msgstr ""
 
@@ -4125,7 +4129,7 @@ msgstr ""
 msgid "show [<remote>:]<profile>"
 msgstr ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid "show [<remote>:]<project>"
 msgstr ""
 
@@ -4169,7 +4173,7 @@ msgstr ""
 msgid "switch <remote>"
 msgstr ""
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 msgid "switch [<remote>:]<project>"
 msgstr ""
 
@@ -4214,7 +4218,7 @@ msgstr ""
 msgid "unset [<remote>:]<profile> <key>"
 msgstr ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 msgid "unset [<remote>:]<project> <key>"
 msgstr ""
 
diff --git a/po/sr.po b/po/sr.po
index 5e1a14b26d..c354e804fa 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: 2020-02-26 08:16-0500\n"
+"POT-Creation-Date: 2020-03-04 10:28+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -860,8 +860,8 @@ msgstr ""
 #: lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712
 #: lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29
 #: lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334
-#: lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584
-#: lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31
+#: lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590
+#: lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31
 #: lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455
 #: lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685
 #: lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33
@@ -1308,7 +1308,7 @@ msgstr ""
 msgid "ID: %s"
 msgstr ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid "IMAGES"
 msgstr ""
 
@@ -1921,7 +1921,7 @@ msgid "Missing profile name"
 msgstr ""
 
 #: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358
-#: lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 msgid "Missing project name"
 msgstr ""
 
@@ -1997,7 +1997,7 @@ msgid "Must supply instance name for: "
 msgstr ""
 
 #: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620
-#: lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558
+#: lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558
 #: lxc/storage_volume.go:1118
 msgid "NAME"
 msgstr ""
@@ -2011,7 +2011,7 @@ msgid "NICs:"
 msgstr ""
 
 #: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428
-#: lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid "NO"
 msgstr ""
 
@@ -2155,7 +2155,7 @@ msgstr ""
 msgid "PROCESSES"
 msgstr ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid "PROFILES"
 msgstr ""
 
@@ -2313,7 +2313,7 @@ msgstr ""
 msgid "Project %s deleted"
 msgstr ""
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, c-format
 msgid "Project %s renamed to %s"
 msgstr ""
@@ -2390,7 +2390,7 @@ msgstr ""
 msgid "Remote %s already exists"
 msgstr ""
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
 #: lxc/remote.go:705
 #, c-format
 msgid "Remote %s doesn't exist"
@@ -2474,7 +2474,7 @@ msgstr ""
 msgid "Rename profiles"
 msgstr ""
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 msgid "Rename projects"
 msgstr ""
 
@@ -2579,6 +2579,10 @@ msgstr ""
 msgid "STORAGE POOL"
 msgstr ""
 
+#: lxc/project.go:457
+msgid "STORAGE VOLUMES"
+msgstr ""
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid "Send a raw query to LXD"
 msgstr ""
@@ -2665,11 +2669,11 @@ msgid ""
 "    lxc profile set [<remote>:]<profile> <key> <value>"
 msgstr ""
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 msgid "Set project configuration keys"
 msgstr ""
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid ""
 "Set project configuration keys\n"
 "\n"
@@ -2776,7 +2780,7 @@ msgstr ""
 msgid "Show profile configurations"
 msgstr ""
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 msgid "Show project options"
 msgstr ""
 
@@ -2951,7 +2955,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 msgid "Switch the current project"
 msgstr ""
 
@@ -3134,7 +3138,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567
 #: lxc/storage_volume.go:1120
 msgid "USED BY"
 msgstr ""
@@ -3179,7 +3183,7 @@ msgstr ""
 msgid "Unset profile configuration keys"
 msgstr ""
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 msgid "Unset project configuration keys"
 msgstr ""
 
@@ -3274,7 +3278,7 @@ msgid "Whether or not to snapshot the instance's running state"
 msgstr ""
 
 #: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430
-#: lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid "YES"
 msgstr ""
 
@@ -3398,7 +3402,7 @@ msgstr ""
 msgid "create [<remote>:]<project>"
 msgstr ""
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 msgid "current"
 msgstr ""
 
@@ -4037,7 +4041,7 @@ msgstr ""
 msgid "rename [<remote>:]<profile> <new-name>"
 msgstr ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid "rename [<remote>:]<project> <new-name>"
 msgstr ""
 
@@ -4073,7 +4077,7 @@ msgstr ""
 msgid "set [<remote>:]<profile> <key><value>..."
 msgstr ""
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 msgid "set [<remote>:]<project> <key>=<value>..."
 msgstr ""
 
@@ -4125,7 +4129,7 @@ msgstr ""
 msgid "show [<remote>:]<profile>"
 msgstr ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid "show [<remote>:]<project>"
 msgstr ""
 
@@ -4169,7 +4173,7 @@ msgstr ""
 msgid "switch <remote>"
 msgstr ""
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 msgid "switch [<remote>:]<project>"
 msgstr ""
 
@@ -4214,7 +4218,7 @@ msgstr ""
 msgid "unset [<remote>:]<profile> <key>"
 msgstr ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 msgid "unset [<remote>:]<project> <key>"
 msgstr ""
 
diff --git a/po/sv.po b/po/sv.po
index 7ded6f1d52..67c23d8195 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: 2020-02-26 08:16-0500\n"
+"POT-Creation-Date: 2020-03-04 10:28+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -860,8 +860,8 @@ msgstr ""
 #: lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712
 #: lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29
 #: lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334
-#: lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584
-#: lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31
+#: lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590
+#: lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31
 #: lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455
 #: lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685
 #: lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33
@@ -1308,7 +1308,7 @@ msgstr ""
 msgid "ID: %s"
 msgstr ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid "IMAGES"
 msgstr ""
 
@@ -1921,7 +1921,7 @@ msgid "Missing profile name"
 msgstr ""
 
 #: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358
-#: lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 msgid "Missing project name"
 msgstr ""
 
@@ -1997,7 +1997,7 @@ msgid "Must supply instance name for: "
 msgstr ""
 
 #: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620
-#: lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558
+#: lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558
 #: lxc/storage_volume.go:1118
 msgid "NAME"
 msgstr ""
@@ -2011,7 +2011,7 @@ msgid "NICs:"
 msgstr ""
 
 #: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428
-#: lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid "NO"
 msgstr ""
 
@@ -2155,7 +2155,7 @@ msgstr ""
 msgid "PROCESSES"
 msgstr ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid "PROFILES"
 msgstr ""
 
@@ -2313,7 +2313,7 @@ msgstr ""
 msgid "Project %s deleted"
 msgstr ""
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, c-format
 msgid "Project %s renamed to %s"
 msgstr ""
@@ -2390,7 +2390,7 @@ msgstr ""
 msgid "Remote %s already exists"
 msgstr ""
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
 #: lxc/remote.go:705
 #, c-format
 msgid "Remote %s doesn't exist"
@@ -2474,7 +2474,7 @@ msgstr ""
 msgid "Rename profiles"
 msgstr ""
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 msgid "Rename projects"
 msgstr ""
 
@@ -2579,6 +2579,10 @@ msgstr ""
 msgid "STORAGE POOL"
 msgstr ""
 
+#: lxc/project.go:457
+msgid "STORAGE VOLUMES"
+msgstr ""
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid "Send a raw query to LXD"
 msgstr ""
@@ -2665,11 +2669,11 @@ msgid ""
 "    lxc profile set [<remote>:]<profile> <key> <value>"
 msgstr ""
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 msgid "Set project configuration keys"
 msgstr ""
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid ""
 "Set project configuration keys\n"
 "\n"
@@ -2776,7 +2780,7 @@ msgstr ""
 msgid "Show profile configurations"
 msgstr ""
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 msgid "Show project options"
 msgstr ""
 
@@ -2951,7 +2955,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 msgid "Switch the current project"
 msgstr ""
 
@@ -3134,7 +3138,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567
 #: lxc/storage_volume.go:1120
 msgid "USED BY"
 msgstr ""
@@ -3179,7 +3183,7 @@ msgstr ""
 msgid "Unset profile configuration keys"
 msgstr ""
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 msgid "Unset project configuration keys"
 msgstr ""
 
@@ -3274,7 +3278,7 @@ msgid "Whether or not to snapshot the instance's running state"
 msgstr ""
 
 #: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430
-#: lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid "YES"
 msgstr ""
 
@@ -3398,7 +3402,7 @@ msgstr ""
 msgid "create [<remote>:]<project>"
 msgstr ""
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 msgid "current"
 msgstr ""
 
@@ -4037,7 +4041,7 @@ msgstr ""
 msgid "rename [<remote>:]<profile> <new-name>"
 msgstr ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid "rename [<remote>:]<project> <new-name>"
 msgstr ""
 
@@ -4073,7 +4077,7 @@ msgstr ""
 msgid "set [<remote>:]<profile> <key><value>..."
 msgstr ""
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 msgid "set [<remote>:]<project> <key>=<value>..."
 msgstr ""
 
@@ -4125,7 +4129,7 @@ msgstr ""
 msgid "show [<remote>:]<profile>"
 msgstr ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid "show [<remote>:]<project>"
 msgstr ""
 
@@ -4169,7 +4173,7 @@ msgstr ""
 msgid "switch <remote>"
 msgstr ""
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 msgid "switch [<remote>:]<project>"
 msgstr ""
 
@@ -4214,7 +4218,7 @@ msgstr ""
 msgid "unset [<remote>:]<profile> <key>"
 msgstr ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 msgid "unset [<remote>:]<project> <key>"
 msgstr ""
 
diff --git a/po/te.po b/po/te.po
index af9afb22ac..eba025a504 100644
--- a/po/te.po
+++ b/po/te.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: 2020-02-26 08:16-0500\n"
+"POT-Creation-Date: 2020-03-04 10:28+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -860,8 +860,8 @@ msgstr ""
 #: lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712
 #: lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29
 #: lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334
-#: lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584
-#: lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31
+#: lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590
+#: lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31
 #: lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455
 #: lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685
 #: lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33
@@ -1308,7 +1308,7 @@ msgstr ""
 msgid "ID: %s"
 msgstr ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid "IMAGES"
 msgstr ""
 
@@ -1921,7 +1921,7 @@ msgid "Missing profile name"
 msgstr ""
 
 #: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358
-#: lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 msgid "Missing project name"
 msgstr ""
 
@@ -1997,7 +1997,7 @@ msgid "Must supply instance name for: "
 msgstr ""
 
 #: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620
-#: lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558
+#: lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558
 #: lxc/storage_volume.go:1118
 msgid "NAME"
 msgstr ""
@@ -2011,7 +2011,7 @@ msgid "NICs:"
 msgstr ""
 
 #: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428
-#: lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid "NO"
 msgstr ""
 
@@ -2155,7 +2155,7 @@ msgstr ""
 msgid "PROCESSES"
 msgstr ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid "PROFILES"
 msgstr ""
 
@@ -2313,7 +2313,7 @@ msgstr ""
 msgid "Project %s deleted"
 msgstr ""
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, c-format
 msgid "Project %s renamed to %s"
 msgstr ""
@@ -2390,7 +2390,7 @@ msgstr ""
 msgid "Remote %s already exists"
 msgstr ""
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
 #: lxc/remote.go:705
 #, c-format
 msgid "Remote %s doesn't exist"
@@ -2474,7 +2474,7 @@ msgstr ""
 msgid "Rename profiles"
 msgstr ""
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 msgid "Rename projects"
 msgstr ""
 
@@ -2579,6 +2579,10 @@ msgstr ""
 msgid "STORAGE POOL"
 msgstr ""
 
+#: lxc/project.go:457
+msgid "STORAGE VOLUMES"
+msgstr ""
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid "Send a raw query to LXD"
 msgstr ""
@@ -2665,11 +2669,11 @@ msgid ""
 "    lxc profile set [<remote>:]<profile> <key> <value>"
 msgstr ""
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 msgid "Set project configuration keys"
 msgstr ""
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid ""
 "Set project configuration keys\n"
 "\n"
@@ -2776,7 +2780,7 @@ msgstr ""
 msgid "Show profile configurations"
 msgstr ""
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 msgid "Show project options"
 msgstr ""
 
@@ -2951,7 +2955,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 msgid "Switch the current project"
 msgstr ""
 
@@ -3134,7 +3138,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567
 #: lxc/storage_volume.go:1120
 msgid "USED BY"
 msgstr ""
@@ -3179,7 +3183,7 @@ msgstr ""
 msgid "Unset profile configuration keys"
 msgstr ""
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 msgid "Unset project configuration keys"
 msgstr ""
 
@@ -3274,7 +3278,7 @@ msgid "Whether or not to snapshot the instance's running state"
 msgstr ""
 
 #: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430
-#: lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid "YES"
 msgstr ""
 
@@ -3398,7 +3402,7 @@ msgstr ""
 msgid "create [<remote>:]<project>"
 msgstr ""
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 msgid "current"
 msgstr ""
 
@@ -4037,7 +4041,7 @@ msgstr ""
 msgid "rename [<remote>:]<profile> <new-name>"
 msgstr ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid "rename [<remote>:]<project> <new-name>"
 msgstr ""
 
@@ -4073,7 +4077,7 @@ msgstr ""
 msgid "set [<remote>:]<profile> <key><value>..."
 msgstr ""
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 msgid "set [<remote>:]<project> <key>=<value>..."
 msgstr ""
 
@@ -4125,7 +4129,7 @@ msgstr ""
 msgid "show [<remote>:]<profile>"
 msgstr ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid "show [<remote>:]<project>"
 msgstr ""
 
@@ -4169,7 +4173,7 @@ msgstr ""
 msgid "switch <remote>"
 msgstr ""
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 msgid "switch [<remote>:]<project>"
 msgstr ""
 
@@ -4214,7 +4218,7 @@ msgstr ""
 msgid "unset [<remote>:]<profile> <key>"
 msgstr ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 msgid "unset [<remote>:]<project> <key>"
 msgstr ""
 
diff --git a/po/tr.po b/po/tr.po
index d6fdf32bea..c8bab7dfe5 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: 2020-02-26 08:16-0500\n"
+"POT-Creation-Date: 2020-03-04 10:28+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -860,8 +860,8 @@ msgstr ""
 #: lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712
 #: lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29
 #: lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334
-#: lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584
-#: lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31
+#: lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590
+#: lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31
 #: lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455
 #: lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685
 #: lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33
@@ -1308,7 +1308,7 @@ msgstr ""
 msgid "ID: %s"
 msgstr ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid "IMAGES"
 msgstr ""
 
@@ -1921,7 +1921,7 @@ msgid "Missing profile name"
 msgstr ""
 
 #: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358
-#: lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 msgid "Missing project name"
 msgstr ""
 
@@ -1997,7 +1997,7 @@ msgid "Must supply instance name for: "
 msgstr ""
 
 #: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620
-#: lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558
+#: lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558
 #: lxc/storage_volume.go:1118
 msgid "NAME"
 msgstr ""
@@ -2011,7 +2011,7 @@ msgid "NICs:"
 msgstr ""
 
 #: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428
-#: lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid "NO"
 msgstr ""
 
@@ -2155,7 +2155,7 @@ msgstr ""
 msgid "PROCESSES"
 msgstr ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid "PROFILES"
 msgstr ""
 
@@ -2313,7 +2313,7 @@ msgstr ""
 msgid "Project %s deleted"
 msgstr ""
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, c-format
 msgid "Project %s renamed to %s"
 msgstr ""
@@ -2390,7 +2390,7 @@ msgstr ""
 msgid "Remote %s already exists"
 msgstr ""
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
 #: lxc/remote.go:705
 #, c-format
 msgid "Remote %s doesn't exist"
@@ -2474,7 +2474,7 @@ msgstr ""
 msgid "Rename profiles"
 msgstr ""
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 msgid "Rename projects"
 msgstr ""
 
@@ -2579,6 +2579,10 @@ msgstr ""
 msgid "STORAGE POOL"
 msgstr ""
 
+#: lxc/project.go:457
+msgid "STORAGE VOLUMES"
+msgstr ""
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid "Send a raw query to LXD"
 msgstr ""
@@ -2665,11 +2669,11 @@ msgid ""
 "    lxc profile set [<remote>:]<profile> <key> <value>"
 msgstr ""
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 msgid "Set project configuration keys"
 msgstr ""
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid ""
 "Set project configuration keys\n"
 "\n"
@@ -2776,7 +2780,7 @@ msgstr ""
 msgid "Show profile configurations"
 msgstr ""
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 msgid "Show project options"
 msgstr ""
 
@@ -2951,7 +2955,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 msgid "Switch the current project"
 msgstr ""
 
@@ -3134,7 +3138,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567
 #: lxc/storage_volume.go:1120
 msgid "USED BY"
 msgstr ""
@@ -3179,7 +3183,7 @@ msgstr ""
 msgid "Unset profile configuration keys"
 msgstr ""
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 msgid "Unset project configuration keys"
 msgstr ""
 
@@ -3274,7 +3278,7 @@ msgid "Whether or not to snapshot the instance's running state"
 msgstr ""
 
 #: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430
-#: lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid "YES"
 msgstr ""
 
@@ -3398,7 +3402,7 @@ msgstr ""
 msgid "create [<remote>:]<project>"
 msgstr ""
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 msgid "current"
 msgstr ""
 
@@ -4037,7 +4041,7 @@ msgstr ""
 msgid "rename [<remote>:]<profile> <new-name>"
 msgstr ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid "rename [<remote>:]<project> <new-name>"
 msgstr ""
 
@@ -4073,7 +4077,7 @@ msgstr ""
 msgid "set [<remote>:]<profile> <key><value>..."
 msgstr ""
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 msgid "set [<remote>:]<project> <key>=<value>..."
 msgstr ""
 
@@ -4125,7 +4129,7 @@ msgstr ""
 msgid "show [<remote>:]<profile>"
 msgstr ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid "show [<remote>:]<project>"
 msgstr ""
 
@@ -4169,7 +4173,7 @@ msgstr ""
 msgid "switch <remote>"
 msgstr ""
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 msgid "switch [<remote>:]<project>"
 msgstr ""
 
@@ -4214,7 +4218,7 @@ msgstr ""
 msgid "unset [<remote>:]<profile> <key>"
 msgstr ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 msgid "unset [<remote>:]<project> <key>"
 msgstr ""
 
diff --git a/po/uk.po b/po/uk.po
index b7e1884cca..9ee3cd7b28 100644
--- a/po/uk.po
+++ b/po/uk.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: 2020-02-26 08:16-0500\n"
+"POT-Creation-Date: 2020-03-04 10:28+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -860,8 +860,8 @@ msgstr ""
 #: lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712
 #: lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29
 #: lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334
-#: lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584
-#: lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31
+#: lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590
+#: lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31
 #: lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455
 #: lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685
 #: lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33
@@ -1308,7 +1308,7 @@ msgstr ""
 msgid "ID: %s"
 msgstr ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid "IMAGES"
 msgstr ""
 
@@ -1921,7 +1921,7 @@ msgid "Missing profile name"
 msgstr ""
 
 #: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358
-#: lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 msgid "Missing project name"
 msgstr ""
 
@@ -1997,7 +1997,7 @@ msgid "Must supply instance name for: "
 msgstr ""
 
 #: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620
-#: lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558
+#: lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558
 #: lxc/storage_volume.go:1118
 msgid "NAME"
 msgstr ""
@@ -2011,7 +2011,7 @@ msgid "NICs:"
 msgstr ""
 
 #: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428
-#: lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid "NO"
 msgstr ""
 
@@ -2155,7 +2155,7 @@ msgstr ""
 msgid "PROCESSES"
 msgstr ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid "PROFILES"
 msgstr ""
 
@@ -2313,7 +2313,7 @@ msgstr ""
 msgid "Project %s deleted"
 msgstr ""
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, c-format
 msgid "Project %s renamed to %s"
 msgstr ""
@@ -2390,7 +2390,7 @@ msgstr ""
 msgid "Remote %s already exists"
 msgstr ""
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
 #: lxc/remote.go:705
 #, c-format
 msgid "Remote %s doesn't exist"
@@ -2474,7 +2474,7 @@ msgstr ""
 msgid "Rename profiles"
 msgstr ""
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 msgid "Rename projects"
 msgstr ""
 
@@ -2579,6 +2579,10 @@ msgstr ""
 msgid "STORAGE POOL"
 msgstr ""
 
+#: lxc/project.go:457
+msgid "STORAGE VOLUMES"
+msgstr ""
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid "Send a raw query to LXD"
 msgstr ""
@@ -2665,11 +2669,11 @@ msgid ""
 "    lxc profile set [<remote>:]<profile> <key> <value>"
 msgstr ""
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 msgid "Set project configuration keys"
 msgstr ""
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid ""
 "Set project configuration keys\n"
 "\n"
@@ -2776,7 +2780,7 @@ msgstr ""
 msgid "Show profile configurations"
 msgstr ""
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 msgid "Show project options"
 msgstr ""
 
@@ -2951,7 +2955,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 msgid "Switch the current project"
 msgstr ""
 
@@ -3134,7 +3138,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567
 #: lxc/storage_volume.go:1120
 msgid "USED BY"
 msgstr ""
@@ -3179,7 +3183,7 @@ msgstr ""
 msgid "Unset profile configuration keys"
 msgstr ""
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 msgid "Unset project configuration keys"
 msgstr ""
 
@@ -3274,7 +3278,7 @@ msgid "Whether or not to snapshot the instance's running state"
 msgstr ""
 
 #: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430
-#: lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid "YES"
 msgstr ""
 
@@ -3398,7 +3402,7 @@ msgstr ""
 msgid "create [<remote>:]<project>"
 msgstr ""
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 msgid "current"
 msgstr ""
 
@@ -4037,7 +4041,7 @@ msgstr ""
 msgid "rename [<remote>:]<profile> <new-name>"
 msgstr ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid "rename [<remote>:]<project> <new-name>"
 msgstr ""
 
@@ -4073,7 +4077,7 @@ msgstr ""
 msgid "set [<remote>:]<profile> <key><value>..."
 msgstr ""
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 msgid "set [<remote>:]<project> <key>=<value>..."
 msgstr ""
 
@@ -4125,7 +4129,7 @@ msgstr ""
 msgid "show [<remote>:]<profile>"
 msgstr ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid "show [<remote>:]<project>"
 msgstr ""
 
@@ -4169,7 +4173,7 @@ msgstr ""
 msgid "switch <remote>"
 msgstr ""
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 msgid "switch [<remote>:]<project>"
 msgstr ""
 
@@ -4214,7 +4218,7 @@ msgstr ""
 msgid "unset [<remote>:]<profile> <key>"
 msgstr ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 msgid "unset [<remote>:]<project> <key>"
 msgstr ""
 
diff --git a/po/zh_Hans.po b/po/zh_Hans.po
index 11b544ea1c..3cc04e512a 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: 2020-02-26 08:16-0500\n"
+"POT-Creation-Date: 2020-03-04 10:28+0000\n"
 "PO-Revision-Date: 2018-09-11 19:15+0000\n"
 "Last-Translator: 0x0916 <w at laoqinren.net>\n"
 "Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/"
@@ -863,8 +863,8 @@ msgstr ""
 #: lxc/profile.go:528 lxc/profile.go:577 lxc/profile.go:636 lxc/profile.go:712
 #: lxc/profile.go:762 lxc/profile.go:821 lxc/profile.go:875 lxc/project.go:29
 #: lxc/project.go:86 lxc/project.go:151 lxc/project.go:214 lxc/project.go:334
-#: lxc/project.go:384 lxc/project.go:469 lxc/project.go:524 lxc/project.go:584
-#: lxc/project.go:613 lxc/project.go:666 lxc/publish.go:35 lxc/query.go:31
+#: lxc/project.go:384 lxc/project.go:475 lxc/project.go:530 lxc/project.go:590
+#: lxc/project.go:619 lxc/project.go:672 lxc/publish.go:35 lxc/query.go:31
 #: lxc/remote.go:34 lxc/remote.go:85 lxc/remote.go:419 lxc/remote.go:455
 #: lxc/remote.go:535 lxc/remote.go:597 lxc/remote.go:647 lxc/remote.go:685
 #: lxc/rename.go:21 lxc/restore.go:24 lxc/snapshot.go:24 lxc/storage.go:33
@@ -1311,7 +1311,7 @@ msgstr ""
 msgid "ID: %s"
 msgstr ""
 
-#: lxc/project.go:450
+#: lxc/project.go:455
 msgid "IMAGES"
 msgstr ""
 
@@ -1924,7 +1924,7 @@ msgid "Missing profile name"
 msgstr ""
 
 #: lxc/project.go:111 lxc/project.go:180 lxc/project.go:258 lxc/project.go:358
-#: lxc/project.go:493 lxc/project.go:551 lxc/project.go:637
+#: lxc/project.go:499 lxc/project.go:557 lxc/project.go:643
 msgid "Missing project name"
 msgstr ""
 
@@ -2000,7 +2000,7 @@ msgid "Must supply instance name for: "
 msgstr ""
 
 #: lxc/cluster.go:126 lxc/list.go:427 lxc/network.go:867 lxc/profile.go:620
-#: lxc/project.go:449 lxc/remote.go:513 lxc/storage.go:558
+#: lxc/project.go:454 lxc/remote.go:513 lxc/storage.go:558
 #: lxc/storage_volume.go:1118
 msgid "NAME"
 msgstr ""
@@ -2014,7 +2014,7 @@ msgid "NICs:"
 msgstr ""
 
 #: lxc/network.go:852 lxc/operation.go:143 lxc/project.go:428
-#: lxc/project.go:433 lxc/remote.go:476 lxc/remote.go:481
+#: lxc/project.go:433 lxc/project.go:438 lxc/remote.go:476 lxc/remote.go:481
 msgid "NO"
 msgstr ""
 
@@ -2158,7 +2158,7 @@ msgstr ""
 msgid "PROCESSES"
 msgstr ""
 
-#: lxc/list.go:430 lxc/project.go:451
+#: lxc/list.go:430 lxc/project.go:456
 msgid "PROFILES"
 msgstr ""
 
@@ -2316,7 +2316,7 @@ msgstr ""
 msgid "Project %s deleted"
 msgstr ""
 
-#: lxc/project.go:508
+#: lxc/project.go:514
 #, c-format
 msgid "Project %s renamed to %s"
 msgstr ""
@@ -2393,7 +2393,7 @@ msgstr ""
 msgid "Remote %s already exists"
 msgstr ""
 
-#: lxc/project.go:693 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
+#: lxc/project.go:699 lxc/remote.go:555 lxc/remote.go:617 lxc/remote.go:667
 #: lxc/remote.go:705
 #, c-format
 msgid "Remote %s doesn't exist"
@@ -2477,7 +2477,7 @@ msgstr ""
 msgid "Rename profiles"
 msgstr ""
 
-#: lxc/project.go:468 lxc/project.go:469
+#: lxc/project.go:474 lxc/project.go:475
 msgid "Rename projects"
 msgstr ""
 
@@ -2582,6 +2582,10 @@ msgstr ""
 msgid "STORAGE POOL"
 msgstr ""
 
+#: lxc/project.go:457
+msgid "STORAGE VOLUMES"
+msgstr ""
+
 #: lxc/query.go:30 lxc/query.go:31
 msgid "Send a raw query to LXD"
 msgstr ""
@@ -2668,11 +2672,11 @@ msgid ""
 "    lxc profile set [<remote>:]<profile> <key> <value>"
 msgstr ""
 
-#: lxc/project.go:523
+#: lxc/project.go:529
 msgid "Set project configuration keys"
 msgstr ""
 
-#: lxc/project.go:524
+#: lxc/project.go:530
 msgid ""
 "Set project configuration keys\n"
 "\n"
@@ -2779,7 +2783,7 @@ msgstr ""
 msgid "Show profile configurations"
 msgstr ""
 
-#: lxc/project.go:612 lxc/project.go:613
+#: lxc/project.go:618 lxc/project.go:619
 msgid "Show project options"
 msgstr ""
 
@@ -2954,7 +2958,7 @@ msgstr ""
 msgid "Swap (peak)"
 msgstr ""
 
-#: lxc/project.go:665 lxc/project.go:666
+#: lxc/project.go:671 lxc/project.go:672
 msgid "Switch the current project"
 msgstr ""
 
@@ -3137,7 +3141,7 @@ msgstr ""
 msgid "URL"
 msgstr ""
 
-#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:452 lxc/storage.go:567
+#: lxc/network.go:871 lxc/profile.go:621 lxc/project.go:458 lxc/storage.go:567
 #: lxc/storage_volume.go:1120
 msgid "USED BY"
 msgstr ""
@@ -3182,7 +3186,7 @@ msgstr ""
 msgid "Unset profile configuration keys"
 msgstr ""
 
-#: lxc/project.go:583 lxc/project.go:584
+#: lxc/project.go:589 lxc/project.go:590
 msgid "Unset project configuration keys"
 msgstr ""
 
@@ -3277,7 +3281,7 @@ msgid "Whether or not to snapshot the instance's running state"
 msgstr ""
 
 #: lxc/network.go:854 lxc/operation.go:145 lxc/project.go:430
-#: lxc/project.go:435 lxc/remote.go:478 lxc/remote.go:483
+#: lxc/project.go:435 lxc/project.go:440 lxc/remote.go:478 lxc/remote.go:483
 msgid "YES"
 msgstr ""
 
@@ -3401,7 +3405,7 @@ msgstr ""
 msgid "create [<remote>:]<project>"
 msgstr ""
 
-#: lxc/project.go:440
+#: lxc/project.go:445
 msgid "current"
 msgstr ""
 
@@ -4040,7 +4044,7 @@ msgstr ""
 msgid "rename [<remote>:]<profile> <new-name>"
 msgstr ""
 
-#: lxc/project.go:466
+#: lxc/project.go:472
 msgid "rename [<remote>:]<project> <new-name>"
 msgstr ""
 
@@ -4076,7 +4080,7 @@ msgstr ""
 msgid "set [<remote>:]<profile> <key><value>..."
 msgstr ""
 
-#: lxc/project.go:522
+#: lxc/project.go:528
 msgid "set [<remote>:]<project> <key>=<value>..."
 msgstr ""
 
@@ -4128,7 +4132,7 @@ msgstr ""
 msgid "show [<remote>:]<profile>"
 msgstr ""
 
-#: lxc/project.go:611
+#: lxc/project.go:617
 msgid "show [<remote>:]<project>"
 msgstr ""
 
@@ -4172,7 +4176,7 @@ msgstr ""
 msgid "switch <remote>"
 msgstr ""
 
-#: lxc/project.go:664
+#: lxc/project.go:670
 msgid "switch [<remote>:]<project>"
 msgstr ""
 
@@ -4217,7 +4221,7 @@ msgstr ""
 msgid "unset [<remote>:]<profile> <key>"
 msgstr ""
 
-#: lxc/project.go:582
+#: lxc/project.go:588
 msgid "unset [<remote>:]<project> <key>"
 msgstr ""
 

From 6334154cf0ffd4487fa086e4fbe8aa9fdd27b76e Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 12:53:11 +0000
Subject: [PATCH 11/40] lxd/daemon/storage: Error message quoting

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/daemon_storage.go | 44 +++++++++++++++++++++----------------------
 1 file changed, 22 insertions(+), 22 deletions(-)

diff --git a/lxd/daemon_storage.go b/lxd/daemon_storage.go
index 86d72ec743..46c2aad72c 100644
--- a/lxd/daemon_storage.go
+++ b/lxd/daemon_storage.go
@@ -53,7 +53,7 @@ func daemonStorageMount(s *state.State) error {
 		// Mount volume.
 		_, err = pool.MountCustomVolume(volumeName, nil)
 		if err != nil {
-			return errors.Wrapf(err, "Failed to mount storage volume \"%s\"", source)
+			return errors.Wrapf(err, "Failed to mount storage volume %q", source)
 		}
 
 		return nil
@@ -119,7 +119,7 @@ func daemonStorageValidate(s *state.State, target string) error {
 	// Validate pool exists.
 	poolID, dbPool, err := s.Cluster.StoragePoolGet(poolName)
 	if err != nil {
-		return errors.Wrapf(err, "Unable to load storage pool \"%s\"", poolName)
+		return errors.Wrapf(err, "Unable to load storage pool %q", poolName)
 	}
 
 	// Validate pool driver (can't be CEPH or CEPHFS).
@@ -130,12 +130,12 @@ func daemonStorageValidate(s *state.State, target string) error {
 	// Confirm volume exists.
 	_, _, err = s.Cluster.StoragePoolNodeVolumeGetType(volumeName, db.StoragePoolVolumeTypeCustom, poolID)
 	if err != nil {
-		return errors.Wrapf(err, "Unable to load storage volume \"%s\"", target)
+		return errors.Wrapf(err, "Unable to load storage volume %q", target)
 	}
 
 	snapshots, err := s.Cluster.StoragePoolVolumeSnapshotsGetType(volumeName, db.StoragePoolVolumeTypeCustom, poolID)
 	if err != nil {
-		return errors.Wrapf(err, "Unable to load storage volume snapshots \"%s\"", target)
+		return errors.Wrapf(err, "Unable to load storage volume snapshots %q", target)
 	}
 
 	if len(snapshots) != 0 {
@@ -150,7 +150,7 @@ func daemonStorageValidate(s *state.State, target string) error {
 	// Mount volume.
 	ourMount, err := pool.MountCustomVolume(volumeName, nil)
 	if err != nil {
-		return errors.Wrapf(err, "Failed to mount storage volume \"%s\"", target)
+		return errors.Wrapf(err, "Failed to mount storage volume %q", target)
 	}
 	if ourMount {
 		defer pool.UnmountCustomVolume(volumeName, nil)
@@ -161,7 +161,7 @@ func daemonStorageValidate(s *state.State, target string) error {
 
 	entries, err := ioutil.ReadDir(mountpoint)
 	if err != nil {
-		return errors.Wrapf(err, "Failed to list \"%s\"", mountpoint)
+		return errors.Wrapf(err, "Failed to list %q", mountpoint)
 	}
 
 	for _, entry := range entries {
@@ -171,7 +171,7 @@ func daemonStorageValidate(s *state.State, target string) error {
 			continue
 		}
 
-		return fmt.Errorf("Storage volume \"%s\" isn't empty", target)
+		return fmt.Errorf("Storage volume %q isn't empty", target)
 	}
 
 	return nil
@@ -226,19 +226,19 @@ func daemonStorageMove(s *state.State, storageType string, target string) error
 		// Remove the symlink.
 		err = os.Remove(destPath)
 		if err != nil {
-			return errors.Wrapf(err, "Failed to delete storage symlink at \"%s\"", destPath)
+			return errors.Wrapf(err, "Failed to delete storage symlink at %q", destPath)
 		}
 
 		// Re-create as a directory.
 		err = os.MkdirAll(destPath, 0700)
 		if err != nil {
-			return errors.Wrapf(err, "Failed to create directory \"%s\"", destPath)
+			return errors.Wrapf(err, "Failed to create directory %q", destPath)
 		}
 
 		// Move the data across.
 		err = moveContent(sourcePath, destPath)
 		if err != nil {
-			return errors.Wrapf(err, "Failed to move data over to directory \"%s\"", destPath)
+			return errors.Wrapf(err, "Failed to move data over to directory %q", destPath)
 		}
 
 		pool, err := storagePools.GetPoolByName(s, sourcePool)
@@ -249,7 +249,7 @@ func daemonStorageMove(s *state.State, storageType string, target string) error
 		// Unmount old volume.
 		_, err = pool.UnmountCustomVolume(sourceVolume, nil)
 		if err != nil {
-			return errors.Wrapf(err, "Failed to umount storage volume \"%s/%s\"", sourcePool, sourceVolume)
+			return errors.Wrapf(err, `Failed to umount storage volume "%s/%s"`, sourcePool, sourceVolume)
 		}
 
 		return nil
@@ -272,7 +272,7 @@ func daemonStorageMove(s *state.State, storageType string, target string) error
 	// Mount volume.
 	_, err = pool.MountCustomVolume(volumeName, nil)
 	if err != nil {
-		return errors.Wrapf(err, "Failed to mount storage volume \"%s\"", target)
+		return errors.Wrapf(err, "Failed to mount storage volume %q", target)
 	}
 
 	// Set ownership & mode.
@@ -281,12 +281,12 @@ func daemonStorageMove(s *state.State, storageType string, target string) error
 
 	err = os.Chmod(mountpoint, 0700)
 	if err != nil {
-		return errors.Wrapf(err, "Failed to set permissions on \"%s\"", mountpoint)
+		return errors.Wrapf(err, "Failed to set permissions on %q", mountpoint)
 	}
 
 	err = os.Chown(mountpoint, 0, 0)
 	if err != nil {
-		return errors.Wrapf(err, "Failed to set ownership on \"%s\"", mountpoint)
+		return errors.Wrapf(err, "Failed to set ownership on %q", mountpoint)
 	}
 
 	// Handle changes.
@@ -294,19 +294,19 @@ func daemonStorageMove(s *state.State, storageType string, target string) error
 		// Remove the symlink.
 		err := os.Remove(shared.VarPath(storageType))
 		if err != nil {
-			return errors.Wrapf(err, "Failed to remove the new symlink at \"%s\"", shared.VarPath(storageType))
+			return errors.Wrapf(err, "Failed to remove the new symlink at %q", shared.VarPath(storageType))
 		}
 
 		// Create the new symlink.
 		err = os.Symlink(destPath, shared.VarPath(storageType))
 		if err != nil {
-			return errors.Wrapf(err, "Failed to create the new symlink at \"%s\"", shared.VarPath(storageType))
+			return errors.Wrapf(err, "Failed to create the new symlink at %q", shared.VarPath(storageType))
 		}
 
 		// Move the data across.
 		err = moveContent(sourcePath, destPath)
 		if err != nil {
-			return errors.Wrapf(err, "Failed to move data over to directory \"%s\"", destPath)
+			return errors.Wrapf(err, "Failed to move data over to directory %q", destPath)
 		}
 
 		pool, err := storagePools.GetPoolByName(s, sourcePool)
@@ -317,7 +317,7 @@ func daemonStorageMove(s *state.State, storageType string, target string) error
 		// Unmount old volume.
 		_, err = pool.UnmountCustomVolume(sourceVolume, nil)
 		if err != nil {
-			return errors.Wrapf(err, "Failed to umount storage volume \"%s/%s\"", sourcePool, sourceVolume)
+			return errors.Wrapf(err, `Failed to umount storage volume "%s/%s"`, sourcePool, sourceVolume)
 		}
 
 		return nil
@@ -328,25 +328,25 @@ func daemonStorageMove(s *state.State, storageType string, target string) error
 	// Rename the existing storage.
 	err = os.Rename(shared.VarPath(storageType), sourcePath)
 	if err != nil {
-		return errors.Wrapf(err, "Failed to rename existing storage \"%s\"", shared.VarPath(storageType))
+		return errors.Wrapf(err, "Failed to rename existing storage %q", shared.VarPath(storageType))
 	}
 
 	// Create the new symlink.
 	err = os.Symlink(destPath, shared.VarPath(storageType))
 	if err != nil {
-		return errors.Wrapf(err, "Failed to create the new symlink at \"%s\"", shared.VarPath(storageType))
+		return errors.Wrapf(err, "Failed to create the new symlink at %q", shared.VarPath(storageType))
 	}
 
 	// Move the data across.
 	err = moveContent(sourcePath, destPath)
 	if err != nil {
-		return errors.Wrapf(err, "Failed to move data over to directory \"%s\"", destPath)
+		return errors.Wrapf(err, "Failed to move data over to directory %q", destPath)
 	}
 
 	// Remove the old data.
 	err = os.RemoveAll(sourcePath)
 	if err != nil {
-		return errors.Wrapf(err, "Failed to cleanup old directory \"%s\"", sourcePath)
+		return errors.Wrapf(err, "Failed to cleanup old directory %q", sourcePath)
 	}
 
 	return nil

From cda5e2c99b391ce329ee3a99c2b2547bf9cb4a8c Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 12:53:44 +0000
Subject: [PATCH 12/40] lxd/daemon/storage: Updates storage custom volume
 functions to pass project.Default

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/daemon_storage.go | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/lxd/daemon_storage.go b/lxd/daemon_storage.go
index 46c2aad72c..9a59cd4bc1 100644
--- a/lxd/daemon_storage.go
+++ b/lxd/daemon_storage.go
@@ -11,6 +11,7 @@ import (
 
 	"github.com/lxc/lxd/lxd/db"
 	"github.com/lxc/lxd/lxd/node"
+	"github.com/lxc/lxd/lxd/project"
 	"github.com/lxc/lxd/lxd/rsync"
 	"github.com/lxc/lxd/lxd/state"
 	storagePools "github.com/lxc/lxd/lxd/storage"
@@ -51,7 +52,7 @@ func daemonStorageMount(s *state.State) error {
 		}
 
 		// Mount volume.
-		_, err = pool.MountCustomVolume(volumeName, nil)
+		_, err = pool.MountCustomVolume(project.Default, volumeName, nil)
 		if err != nil {
 			return errors.Wrapf(err, "Failed to mount storage volume %q", source)
 		}
@@ -148,12 +149,12 @@ func daemonStorageValidate(s *state.State, target string) error {
 	}
 
 	// Mount volume.
-	ourMount, err := pool.MountCustomVolume(volumeName, nil)
+	ourMount, err := pool.MountCustomVolume(project.Default, volumeName, nil)
 	if err != nil {
 		return errors.Wrapf(err, "Failed to mount storage volume %q", target)
 	}
 	if ourMount {
-		defer pool.UnmountCustomVolume(volumeName, nil)
+		defer pool.UnmountCustomVolume(project.Default, volumeName, nil)
 	}
 
 	// Validate volume is empty (ignore lost+found).
@@ -247,7 +248,7 @@ func daemonStorageMove(s *state.State, storageType string, target string) error
 		}
 
 		// Unmount old volume.
-		_, err = pool.UnmountCustomVolume(sourceVolume, nil)
+		_, err = pool.UnmountCustomVolume(project.Default, sourceVolume, nil)
 		if err != nil {
 			return errors.Wrapf(err, `Failed to umount storage volume "%s/%s"`, sourcePool, sourceVolume)
 		}
@@ -270,7 +271,7 @@ func daemonStorageMove(s *state.State, storageType string, target string) error
 	}
 
 	// Mount volume.
-	_, err = pool.MountCustomVolume(volumeName, nil)
+	_, err = pool.MountCustomVolume(project.Default, volumeName, nil)
 	if err != nil {
 		return errors.Wrapf(err, "Failed to mount storage volume %q", target)
 	}
@@ -315,7 +316,7 @@ func daemonStorageMove(s *state.State, storageType string, target string) error
 		}
 
 		// Unmount old volume.
-		_, err = pool.UnmountCustomVolume(sourceVolume, nil)
+		_, err = pool.UnmountCustomVolume(project.Default, sourceVolume, nil)
 		if err != nil {
 			return errors.Wrapf(err, `Failed to umount storage volume "%s/%s"`, sourcePool, sourceVolume)
 		}

From 27078534b68bf85bba6af020bad6d1787dbf68ab Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 13:01:13 +0000
Subject: [PATCH 13/40] lxd/device/disk: Updates custom volume disks to support
 projects

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/device/disk.go | 36 ++++++++++++++++++++++--------------
 1 file changed, 22 insertions(+), 14 deletions(-)

diff --git a/lxd/device/disk.go b/lxd/device/disk.go
index 7b8dc60c19..a0b2e17ccc 100644
--- a/lxd/device/disk.go
+++ b/lxd/device/disk.go
@@ -757,7 +757,7 @@ func (d *disk) createDevice() (string, error) {
 			volumeTypeName = db.StoragePoolVolumeTypeNameCustom
 			fallthrough
 		case db.StoragePoolVolumeTypeNameCustom:
-			srcPath = shared.VarPath("storage-pools", d.config["pool"], volumeTypeName, volumeName)
+			break
 		case db.StoragePoolVolumeTypeNameImage:
 			return "", fmt.Errorf("Using image storage volumes is not supported")
 		default:
@@ -774,18 +774,26 @@ func (d *disk) createDevice() (string, error) {
 			return "", err
 		}
 
+		projectName, err := project.StorageVolumeProject(d.state.Cluster, d.inst.Project())
+		if err != nil {
+			return "", err
+		}
+
+		volStorageName := project.StorageVolume(projectName, volumeName)
+		srcPath = storageDrivers.GetVolumeMountPath(d.config["pool"], storageDrivers.VolumeTypeCustom, volStorageName)
+
 		// Mount and prepare the volume to be attached.
 		err = func() error {
-			ourMount, err := pool.MountCustomVolume(volumeName, nil)
+			ourMount, err := pool.MountCustomVolume(projectName, volumeName, nil)
 			if err != nil {
 				return errors.Wrapf(err, "Could not mount storage volume %q of type %q on storage pool %q", volumeName, volumeTypeName, d.config["pool"])
 			}
 
 			if ourMount {
-				revert.Add(func() { pool.UnmountCustomVolume(volumeName, nil) })
+				revert.Add(func() { pool.UnmountCustomVolume(projectName, volumeName, nil) })
 			}
 
-			err = d.storagePoolVolumeAttachPrepare(pool.Name(), volumeName, volumeType)
+			err = d.storagePoolVolumeAttachPrepare(projectName, pool.Name(), volumeName, volumeType, srcPath)
 			if err != nil {
 				return errors.Wrapf(err, "Could not attach storage volume %q of type %q on storage pool %q", volumeName, volumeTypeName, d.config["pool"])
 			}
@@ -851,15 +859,14 @@ func (d *disk) createDevice() (string, error) {
 	return devPath, nil
 }
 
-func (d *disk) storagePoolVolumeAttachPrepare(poolName string, volumeName string, volumeType int) error {
+func (d *disk) storagePoolVolumeAttachPrepare(projectName, poolName, volumeName string, volumeType int, remapPath string) error {
 	// Load the DB records.
 	poolID, pool, err := d.state.Cluster.StoragePoolGet(poolName)
 	if err != nil {
 		return err
 	}
 
-	// Custom storage volumes do not currently support projects, so hardcode "default" project.
-	_, volume, err := d.state.Cluster.StoragePoolNodeVolumeGetTypeByProject("default", volumeName, volumeType, poolID)
+	_, volume, err := d.state.Cluster.StoragePoolNodeVolumeGetTypeByProject(projectName, volumeName, volumeType, poolID)
 	if err != nil {
 		return err
 	}
@@ -905,15 +912,11 @@ func (d *disk) storagePoolVolumeAttachPrepare(poolName string, volumeName string
 	}
 	poolVolumePut.Config["volatile.idmap.next"] = nextJSONMap
 
-	// Get mountpoint of storage volume.
-	remapPath := storagePools.GetStoragePoolVolumeMountPoint(poolName, volumeName)
-
 	if !nextIdmap.Equals(lastIdmap) {
 		logger.Debugf("Shifting storage volume")
 
 		if !shared.IsTrue(poolVolumePut.Config["security.shifted"]) {
-			// Custom storage volumes do not currently support projects, so hardcode "default" project.
-			volumeUsedBy, err := storagePools.VolumeUsedByInstancesGet(d.state, "default", poolName, volumeName)
+			volumeUsedBy, err := storagePools.VolumeUsedByInstancesGet(d.state, projectName, poolName, volumeName)
 			if err != nil {
 				return err
 			}
@@ -1006,7 +1009,7 @@ func (d *disk) storagePoolVolumeAttachPrepare(poolName string, volumeName string
 	// Update last idmap.
 	poolVolumePut.Config["volatile.idmap.last"] = jsonIdmap
 
-	err = d.state.Cluster.StoragePoolVolumeUpdateByProject("default", volumeName, volumeType, poolID, poolVolumePut.Description, poolVolumePut.Config)
+	err = d.state.Cluster.StoragePoolVolumeUpdateByProject(projectName, volumeName, volumeType, poolID, poolVolumePut.Description, poolVolumePut.Config)
 	if err != nil {
 		return err
 	}
@@ -1073,7 +1076,12 @@ func (d *disk) postStop() error {
 			return err
 		}
 
-		_, err = pool.UnmountCustomVolume(d.config["source"], nil)
+		projectName, err := project.StorageVolumeProject(d.state.Cluster, d.inst.Project())
+		if err != nil {
+			return err
+		}
+
+		_, err = pool.UnmountCustomVolume(projectName, d.config["source"], nil)
 		if err != nil {
 			return err
 		}

From 61ad0a3c384ddde037fe0f1ab7581cb0103f9054 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 13:01:41 +0000
Subject: [PATCH 14/40] lxd/patches: Updates patchStorageApiPermissions to use
 project.Default for custom volumes

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/patches.go | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/lxd/patches.go b/lxd/patches.go
index fbfaea3420..fff30133b1 100644
--- a/lxd/patches.go
+++ b/lxd/patches.go
@@ -20,6 +20,7 @@ import (
 	deviceConfig "github.com/lxc/lxd/lxd/device/config"
 	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/instance/instancetype"
+	"github.com/lxc/lxd/lxd/project"
 	"github.com/lxc/lxd/lxd/rsync"
 	driver "github.com/lxc/lxd/lxd/storage"
 	storagePools "github.com/lxc/lxd/lxd/storage"
@@ -3038,13 +3039,13 @@ func patchStorageApiPermissions(name string, d *Daemon) error {
 
 			// Run task in anonymous function so as not to stack up defers.
 			err = func() error {
-				ourMount, err := pool.MountCustomVolume(vol, nil)
+				ourMount, err := pool.MountCustomVolume(project.Default, vol, nil)
 				if err != nil {
 					return err
 				}
 
 				if ourMount {
-					defer pool.UnmountCustomVolume(vol, nil)
+					defer pool.UnmountCustomVolume(project.Default, vol, nil)
 				}
 
 				cuMntPoint := driver.GetStoragePoolVolumeMountPoint(poolName, vol)

From d31e436f644dea5c3a49d473db106c8b3b0514ff Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 13:02:25 +0000
Subject: [PATCH 15/40] lxd/project/project: Adds StorageVolumeProject function

This function returns the project name that the storage volume should use, based on whether the project has the `features.storage.volumes` flag enabled.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/project/project.go | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/lxd/project/project.go b/lxd/project/project.go
index bb6823d4fc..3a03966fd4 100644
--- a/lxd/project/project.go
+++ b/lxd/project/project.go
@@ -3,6 +3,11 @@ package project
 import (
 	"fmt"
 	"strings"
+
+	"github.com/pkg/errors"
+
+	"github.com/lxc/lxd/lxd/db"
+	"github.com/lxc/lxd/shared/api"
 )
 
 // Default is the string used for a default project.
@@ -41,3 +46,30 @@ func InstanceParts(projectInstanceName string) (string, string) {
 func StorageVolume(projectName, storageVolumeName string) string {
 	return fmt.Sprintf("%s%s%s", projectName, separator, storageVolumeName)
 }
+
+// StorageVolumeProject returns the project name to use to for the volume.
+// If the project specified has the "features.storage.volumes" flag enabled then the project name is returned,
+// otherwise the default project name is returned.
+func StorageVolumeProject(c *db.Cluster, projectName string) (string, error) {
+	var project *api.Project
+	var err error
+
+	err = c.Transaction(func(tx *db.ClusterTx) error {
+		project, err = tx.ProjectGet(projectName)
+		if err != nil {
+			return err
+		}
+
+		return nil
+	})
+
+	if err != nil {
+		return "", errors.Wrapf(err, "Failed to load project %q", projectName)
+	}
+
+	if project.Config["features.storage.volumes"] == "true" {
+		return projectName, nil
+	}
+
+	return Default, nil
+}

From 8bbbad523d961f0105e9deb78a39d60da1f375ab Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 13:04:44 +0000
Subject: [PATCH 16/40] lxd/storage/backend/mock: Updates custom volume
 signatures to support projectName

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/backend_mock.go | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/lxd/storage/backend_mock.go b/lxd/storage/backend_mock.go
index 3a9e1911f4..40218b9cfb 100644
--- a/lxd/storage/backend_mock.go
+++ b/lxd/storage/backend_mock.go
@@ -177,23 +177,23 @@ func (b *mockBackend) UpdateImage(fingerprint, newDesc string, newConfig map[str
 	return nil
 }
 
-func (b *mockBackend) CreateCustomVolume(volName, desc string, config map[string]string, op *operations.Operation) error {
+func (b *mockBackend) CreateCustomVolume(projectName, volName, desc string, config map[string]string, op *operations.Operation) error {
 	return nil
 }
 
-func (b *mockBackend) CreateCustomVolumeFromCopy(volName, desc string, config map[string]string, srcPoolName, srcVolName string, srcVolOnly bool, op *operations.Operation) error {
+func (b *mockBackend) CreateCustomVolumeFromCopy(projectName, volName, desc string, config map[string]string, srcPoolName, srcVolName string, srcVolOnly bool, op *operations.Operation) error {
 	return nil
 }
 
-func (b *mockBackend) RenameCustomVolume(volName string, newName string, op *operations.Operation) error {
+func (b *mockBackend) RenameCustomVolume(projectName, volName, newName string, op *operations.Operation) error {
 	return nil
 }
 
-func (b *mockBackend) UpdateCustomVolume(volName, newDesc string, newConfig map[string]string, op *operations.Operation) error {
+func (b *mockBackend) UpdateCustomVolume(projectName, volName, newDesc string, newConfig map[string]string, op *operations.Operation) error {
 	return ErrNotImplemented
 }
 
-func (b *mockBackend) DeleteCustomVolume(volName string, op *operations.Operation) error {
+func (b *mockBackend) DeleteCustomVolume(projectName, volName string, op *operations.Operation) error {
 	return nil
 }
 
@@ -205,34 +205,34 @@ func (b *mockBackend) CreateCustomVolumeFromMigration(conn io.ReadWriteCloser, a
 	return nil
 }
 
-func (b *mockBackend) GetCustomVolumeUsage(volName string) (int64, error) {
+func (b *mockBackend) GetCustomVolumeUsage(projectName, volName string) (int64, error) {
 	return 0, nil
 }
 
-func (b *mockBackend) MountCustomVolume(volName string, op *operations.Operation) (bool, error) {
+func (b *mockBackend) MountCustomVolume(projectName, volName string, op *operations.Operation) (bool, error) {
 	return true, nil
 }
 
-func (b *mockBackend) UnmountCustomVolume(volName string, op *operations.Operation) (bool, error) {
+func (b *mockBackend) UnmountCustomVolume(projectName, volName string, op *operations.Operation) (bool, error) {
 	return true, nil
 }
 
-func (b *mockBackend) CreateCustomVolumeSnapshot(volName string, newSnapshotName string, op *operations.Operation) error {
+func (b *mockBackend) CreateCustomVolumeSnapshot(projectName, volName, newSnapshotName string, op *operations.Operation) error {
 	return nil
 }
 
-func (b *mockBackend) RenameCustomVolumeSnapshot(volName string, newName string, op *operations.Operation) error {
+func (b *mockBackend) RenameCustomVolumeSnapshot(projectName, volName, newName string, op *operations.Operation) error {
 	return nil
 }
 
-func (b *mockBackend) DeleteCustomVolumeSnapshot(volName string, op *operations.Operation) error {
+func (b *mockBackend) DeleteCustomVolumeSnapshot(projectName, volName string, op *operations.Operation) error {
 	return nil
 }
 
-func (b *mockBackend) UpdateCustomVolumeSnapshot(volName, newDesc string, newConfig map[string]string, op *operations.Operation) error {
+func (b *mockBackend) UpdateCustomVolumeSnapshot(projectName, volName, newDesc string, newConfig map[string]string, op *operations.Operation) error {
 	return nil
 }
 
-func (b *mockBackend) RestoreCustomVolume(volName string, snapshotName string, op *operations.Operation) error {
+func (b *mockBackend) RestoreCustomVolume(projectName, volName, snapshotName string, op *operations.Operation) error {
 	return nil
 }

From 8e372ba2c0be010be1f5f7e52b82c81628d7bcd8 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 13:06:27 +0000
Subject: [PATCH 17/40] lxd/storage/pool/interface: Updates custom volume
 functions to support projectName

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/pool_interface.go | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/lxd/storage/pool_interface.go b/lxd/storage/pool_interface.go
index 1808b6a037..3934b02394 100644
--- a/lxd/storage/pool_interface.go
+++ b/lxd/storage/pool_interface.go
@@ -65,21 +65,21 @@ type Pool interface {
 	UpdateImage(fingerprint, newDesc string, newConfig map[string]string, op *operations.Operation) error
 
 	// Custom volumes.
-	CreateCustomVolume(volName, desc string, config map[string]string, op *operations.Operation) error
-	CreateCustomVolumeFromCopy(volName, desc string, config map[string]string, srcPoolName, srcVolName string, srcVolOnly bool, op *operations.Operation) error
-	UpdateCustomVolume(volName, newDesc string, newConfig map[string]string, op *operations.Operation) error
-	RenameCustomVolume(volName string, newVolName string, op *operations.Operation) error
-	DeleteCustomVolume(volName string, op *operations.Operation) error
-	GetCustomVolumeUsage(volName string) (int64, error)
-	MountCustomVolume(volName string, op *operations.Operation) (bool, error)
-	UnmountCustomVolume(volName string, op *operations.Operation) (bool, error)
+	CreateCustomVolume(projectName, volName, desc string, config map[string]string, op *operations.Operation) error
+	CreateCustomVolumeFromCopy(projectName, volName, desc string, config map[string]string, srcPoolName, srcVolName string, srcVolOnly bool, op *operations.Operation) error
+	UpdateCustomVolume(projectName, volName, newDesc string, newConfig map[string]string, op *operations.Operation) error
+	RenameCustomVolume(projectName, volName, newVolName string, op *operations.Operation) error
+	DeleteCustomVolume(projectName, volName string, op *operations.Operation) error
+	GetCustomVolumeUsage(projectName, volName string) (int64, error)
+	MountCustomVolume(projectName, volName string, op *operations.Operation) (bool, error)
+	UnmountCustomVolume(projectName, volName string, op *operations.Operation) (bool, error)
 
 	// Custom volume snapshots.
-	CreateCustomVolumeSnapshot(volName string, newSnapshotName string, op *operations.Operation) error
-	RenameCustomVolumeSnapshot(volName string, newSnapshotName string, op *operations.Operation) error
-	DeleteCustomVolumeSnapshot(volName string, op *operations.Operation) error
-	UpdateCustomVolumeSnapshot(volName, newDesc string, newConfig map[string]string, op *operations.Operation) error
-	RestoreCustomVolume(volName string, snapshotName string, op *operations.Operation) error
+	CreateCustomVolumeSnapshot(projectName, volName, newSnapshotName string, op *operations.Operation) error
+	RenameCustomVolumeSnapshot(projectName, volName, newSnapshotName string, op *operations.Operation) error
+	DeleteCustomVolumeSnapshot(projectName, volName string, op *operations.Operation) error
+	UpdateCustomVolumeSnapshot(projectName, volName, newDesc string, newConfig map[string]string, op *operations.Operation) error
+	RestoreCustomVolume(projectName, volName, snapshotName string, op *operations.Operation) error
 
 	// Custom volume migration.
 	MigrationTypes(contentType drivers.ContentType, refresh bool) []migration.Type

From f9760f67d8fae6aec38850c6918897d0da320b97 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 13:08:18 +0000
Subject: [PATCH 18/40] lxd/storage/volumes: Error message quoting and comment
 tweaks

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage_volumes.go | 43 ++++++++++++++++++------------------------
 1 file changed, 18 insertions(+), 25 deletions(-)

diff --git a/lxd/storage_volumes.go b/lxd/storage_volumes.go
index 1c5a63db55..2aafd0957b 100644
--- a/lxd/storage_volumes.go
+++ b/lxd/storage_volumes.go
@@ -170,8 +170,7 @@ func storagePoolVolumesGet(d *Daemon, r *http.Request) response.Response {
 func storagePoolVolumesTypeGet(d *Daemon, r *http.Request) response.Response {
 	project := projectParam(r)
 
-	// Get the name of the pool the storage volume is supposed to be
-	// attached to.
+	// Get the name of the pool the storage volume is supposed to be attached to.
 	poolName := mux.Vars(r)["name"]
 
 	// Get the name of the volume type.
@@ -184,20 +183,19 @@ func storagePoolVolumesTypeGet(d *Daemon, r *http.Request) response.Response {
 	if err != nil {
 		return response.BadRequest(err)
 	}
+
 	// Check that the storage volume type is valid.
 	if !shared.IntInSlice(volumeType, supportedVolumeTypes) {
-		return response.BadRequest(fmt.Errorf("Invalid storage volume type %s", volumeTypeName))
+		return response.BadRequest(fmt.Errorf("Invalid storage volume type %q", volumeTypeName))
 	}
 
-	// Retrieve ID of the storage pool (and check if the storage pool
-	// exists).
+	// Retrieve ID of the storage pool (and check if the storage pool exists).
 	poolID, err := d.cluster.StoragePoolGetID(poolName)
 	if err != nil {
 		return response.SmartError(err)
 	}
 
-	// Get the names of all storage volumes of a given volume type currently
-	// attached to the storage pool.
+	// Get the names of all storage volumes of a given volume type currently attached to the storage pool.
 	volumes, err := d.cluster.StoragePoolNodeVolumesGetType(volumeType, poolID)
 	if err != nil {
 		return response.SmartError(err)
@@ -275,8 +273,7 @@ func storagePoolVolumesTypePost(d *Daemon, r *http.Request) response.Response {
 	// storagePoolVolumeTypeCustom. So check, that nothing else was
 	// requested.
 	if req.Type != db.StoragePoolVolumeTypeNameCustom {
-		return response.BadRequest(fmt.Errorf(`Currently not allowed to create `+
-			`storage volumes of type %s`, req.Type))
+		return response.BadRequest(fmt.Errorf(`Currently not allowed to create storage volumes of type %q`, req.Type))
 	}
 
 	poolName := mux.Vars(r)["name"]
@@ -377,8 +374,7 @@ func storagePoolVolumesPost(d *Daemon, r *http.Request) response.Response {
 	// storagePoolVolumeTypeCustom. So check, that nothing else was
 	// requested.
 	if req.Type != db.StoragePoolVolumeTypeNameCustom {
-		return response.BadRequest(fmt.Errorf(`Currently not allowed to create `+
-			`storage volumes of type %s`, req.Type))
+		return response.BadRequest(fmt.Errorf(`Currently not allowed to create storage volumes of type %q`, req.Type))
 	}
 
 	poolName := mux.Vars(r)["name"]
@@ -405,7 +401,7 @@ func storagePoolVolumesPost(d *Daemon, r *http.Request) response.Response {
 	case "migration":
 		return doVolumeMigration(d, poolName, &req)
 	default:
-		return response.BadRequest(fmt.Errorf("unknown source type %s", req.Source.Type))
+		return response.BadRequest(fmt.Errorf("Unknown source type %q", req.Source.Type))
 	}
 }
 
@@ -752,8 +748,7 @@ func storagePoolVolumeTypeGet(d *Daemon, r *http.Request, volumeTypeName string)
 		return response.BadRequest(err)
 	}
 
-	// Get the name of the storage pool the volume is supposed to be
-	// attached to.
+	// Get the name of the storage pool the volume is supposed to be attached to.
 	poolName := mux.Vars(r)["pool"]
 
 	// Convert the volume type name to our internal integer representation.
@@ -761,13 +756,13 @@ func storagePoolVolumeTypeGet(d *Daemon, r *http.Request, volumeTypeName string)
 	if err != nil {
 		return response.BadRequest(err)
 	}
+
 	// Check that the storage volume type is valid.
 	if !shared.IntInSlice(volumeType, supportedVolumeTypes) {
-		return response.BadRequest(fmt.Errorf("Invalid storage volume type %s", volumeTypeName))
+		return response.BadRequest(fmt.Errorf("Invalid storage volume type %q", volumeTypeName))
 	}
 
-	// Get the ID of the storage pool the storage volume is supposed to be
-	// attached to.
+	// Get the ID of the storage pool the storage volume is supposed to be attached to.
 	poolID, err := d.cluster.StoragePoolGetID(poolName)
 	if err != nil {
 		return response.SmartError(err)
@@ -828,8 +823,7 @@ func storagePoolVolumeTypePut(d *Daemon, r *http.Request, volumeTypeName string)
 		return response.BadRequest(err)
 	}
 
-	// Get the name of the storage pool the volume is supposed to be
-	// attached to.
+	// Get the name of the storage pool the volume is supposed to be attached to.
 	poolName := mux.Vars(r)["pool"]
 
 	// Convert the volume type name to our internal integer representation.
@@ -840,7 +834,7 @@ func storagePoolVolumeTypePut(d *Daemon, r *http.Request, volumeTypeName string)
 
 	// Check that the storage volume type is valid.
 	if !shared.IntInSlice(volumeType, supportedVolumeTypes) {
-		return response.BadRequest(fmt.Errorf("Invalid storage volume type %s", volumeTypeName))
+		return response.BadRequest(fmt.Errorf("Invalid storage volume type %q", volumeTypeName))
 	}
 
 	pool, err := storagePools.GetPoolByName(d.State(), poolName)
@@ -1046,11 +1040,10 @@ func storagePoolVolumeTypeDelete(d *Daemon, r *http.Request, volumeTypeName stri
 	volumeName := mux.Vars(r)["name"]
 
 	if shared.IsSnapshot(volumeName) {
-		return response.BadRequest(fmt.Errorf("Invalid storage volume %s", volumeName))
+		return response.BadRequest(fmt.Errorf("Invalid storage volume %q", volumeName))
 	}
 
-	// Get the name of the storage pool the volume is supposed to be
-	// attached to.
+	// Get the name of the storage pool the volume is supposed to be attached to.
 	poolName := mux.Vars(r)["pool"]
 
 	// Convert the volume type name to our internal integer representation.
@@ -1060,7 +1053,7 @@ func storagePoolVolumeTypeDelete(d *Daemon, r *http.Request, volumeTypeName stri
 	}
 	// Check that the storage volume type is valid.
 	if !shared.IntInSlice(volumeType, supportedVolumeTypes) {
-		return response.BadRequest(fmt.Errorf("Invalid storage volume type %s", volumeTypeName))
+		return response.BadRequest(fmt.Errorf("Invalid storage volume type %q", volumeTypeName))
 	}
 
 	resp := ForwardedResponseIfTargetIsRemote(d, r)
@@ -1109,7 +1102,7 @@ func storagePoolVolumeTypeDelete(d *Daemon, r *http.Request, volumeTypeName stri
 	case db.StoragePoolVolumeTypeImage:
 		err = pool.DeleteImage(volumeName, nil)
 	default:
-		return response.BadRequest(fmt.Errorf(`Storage volumes of type %q cannot be deleted with the storage api`, volumeTypeName))
+		return response.BadRequest(fmt.Errorf(`Storage volumes of type %q cannot be deleted with the storage API`, volumeTypeName))
 	}
 	if err != nil {
 		return response.SmartError(err)

From 28c0ce94d9db70141b341c4b498364759734c0fe Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 13:15:01 +0000
Subject: [PATCH 19/40] lxd/storage/volumes: Improve volume type checks

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage_volumes.go | 13 ++++---------
 1 file changed, 4 insertions(+), 9 deletions(-)

diff --git a/lxd/storage_volumes.go b/lxd/storage_volumes.go
index 2aafd0957b..0178796d7d 100644
--- a/lxd/storage_volumes.go
+++ b/lxd/storage_volumes.go
@@ -957,9 +957,9 @@ func storagePoolVolumeTypePatch(d *Daemon, r *http.Request, volumeTypeName strin
 		return response.BadRequest(err)
 	}
 
-	// Check that the storage volume type is valid.
-	if !shared.IntInSlice(volumeType, supportedVolumeTypes) {
-		return response.BadRequest(fmt.Errorf("Invalid storage volume type %s", volumeTypeName))
+	// Check that the storage volume type is custom.
+	if volumeType != db.StoragePoolVolumeTypeCustom {
+		return response.BadRequest(fmt.Errorf("Invalid storage volume type %q", volumeTypeName))
 	}
 
 	pool, err := storagePools.GetPoolByName(d.State(), poolName)
@@ -1071,12 +1071,7 @@ func storagePoolVolumeTypeDelete(d *Daemon, r *http.Request, volumeTypeName stri
 		return resp
 	}
 
-	switch volumeType {
-	case db.StoragePoolVolumeTypeCustom:
-		// allowed
-	case db.StoragePoolVolumeTypeImage:
-		// allowed
-	default:
+	if volumeType != db.StoragePoolVolumeTypeCustom && volumeType != db.StoragePoolVolumeTypeImage {
 		return response.BadRequest(fmt.Errorf("Storage volumes of type %q cannot be deleted with the storage API", volumeTypeName))
 	}
 

From 0bb9109fb2308716b011274e05b7917e8ee0409c Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 13:18:39 +0000
Subject: [PATCH 20/40] lxd/storage/volumes: Add custom volume project support

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage_volumes.go | 117 +++++++++++++++++++++++++++++------------
 1 file changed, 83 insertions(+), 34 deletions(-)

diff --git a/lxd/storage_volumes.go b/lxd/storage_volumes.go
index 0178796d7d..8bb1f9c294 100644
--- a/lxd/storage_volumes.go
+++ b/lxd/storage_volumes.go
@@ -14,6 +14,7 @@ import (
 	"github.com/lxc/lxd/lxd/db"
 	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/operations"
+	"github.com/lxc/lxd/lxd/project"
 	"github.com/lxc/lxd/lxd/response"
 	"github.com/lxc/lxd/lxd/state"
 	storagePools "github.com/lxc/lxd/lxd/storage"
@@ -82,7 +83,11 @@ var storagePoolVolumeTypeImageCmd = APIEndpoint{
 // /1.0/storage-pools/{name}/volumes
 // List all storage volumes attached to a given storage pool.
 func storagePoolVolumesGet(d *Daemon, r *http.Request) response.Response {
-	project := projectParam(r)
+	projectName, err := project.StorageVolumeProject(d.State().Cluster, projectParam(r))
+	if err != nil {
+		return response.SmartError(err)
+	}
+
 	poolName := mux.Vars(r)["name"]
 
 	recursion := util.IsRecursionRequest(r)
@@ -103,17 +108,17 @@ func storagePoolVolumesGet(d *Daemon, r *http.Request) response.Response {
 	// project. This means that we want to filter image volumes and return
 	// only the ones that have fingerprints matching images actually in use
 	// by the project.
-	volumes, err := d.cluster.StoragePoolVolumesGet(project, poolID, supportedVolumeTypesExceptImages)
+	volumes, err := d.cluster.StoragePoolVolumesGet(projectName, poolID, supportedVolumeTypesExceptImages)
 	if err != nil && err != db.ErrNoSuchObject {
 		return response.SmartError(err)
 	}
 
-	imageVolumes, err := d.cluster.StoragePoolVolumesGet("default", poolID, []int{db.StoragePoolVolumeTypeImage})
+	imageVolumes, err := d.cluster.StoragePoolVolumesGet(project.Default, poolID, []int{db.StoragePoolVolumeTypeImage})
 	if err != nil && err != db.ErrNoSuchObject {
 		return response.SmartError(err)
 	}
 
-	projectImages, err := d.cluster.ImagesGet(project, false)
+	projectImages, err := d.cluster.ImagesGet(projectName, false)
 	if err != nil {
 		return response.SmartError(err)
 	}
@@ -150,7 +155,7 @@ func storagePoolVolumesGet(d *Daemon, r *http.Request) response.Response {
 						version.APIVersion, poolName, apiEndpoint, volume.Name))
 			}
 		} else {
-			volumeUsedBy, err := storagePoolVolumeUsedByGet(d.State(), project, poolName, volume.Name, volume.Type)
+			volumeUsedBy, err := storagePoolVolumeUsedByGet(d.State(), projectName, poolName, volume.Name, volume.Type)
 			if err != nil {
 				return response.InternalError(err)
 			}
@@ -245,6 +250,11 @@ func storagePoolVolumesTypeGet(d *Daemon, r *http.Request) response.Response {
 // /1.0/storage-pools/{name}/volumes/{type}
 // Create a storage volume in a given storage pool.
 func storagePoolVolumesTypePost(d *Daemon, r *http.Request) response.Response {
+	projectName, err := project.StorageVolumeProject(d.State().Cluster, projectParam(r))
+	if err != nil {
+		return response.SmartError(err)
+	}
+
 	resp := ForwardedResponseIfTargetIsRemote(d, r)
 	if resp != nil {
 		return resp
@@ -253,7 +263,7 @@ func storagePoolVolumesTypePost(d *Daemon, r *http.Request) response.Response {
 	req := api.StorageVolumesPost{}
 
 	// Parse the request.
-	err := json.NewDecoder(r.Body).Decode(&req)
+	err = json.NewDecoder(r.Body).Decode(&req)
 	if err != nil {
 		return response.BadRequest(err)
 	}
@@ -283,7 +293,7 @@ func storagePoolVolumesTypePost(d *Daemon, r *http.Request) response.Response {
 	}
 
 	// Check if destination volume exists.
-	_, _, err = d.cluster.StoragePoolNodeVolumeGetTypeByProject("default", req.Name, db.StoragePoolVolumeTypeCustom, poolID)
+	_, _, err = d.cluster.StoragePoolNodeVolumeGetTypeByProject(projectName, req.Name, db.StoragePoolVolumeTypeCustom, poolID)
 	if err != db.ErrNoSuchObject {
 		if err != nil {
 			return response.SmartError(err)
@@ -294,17 +304,17 @@ func storagePoolVolumesTypePost(d *Daemon, r *http.Request) response.Response {
 
 	switch req.Source.Type {
 	case "":
-		return doVolumeCreateOrCopy(d, poolName, &req)
+		return doVolumeCreateOrCopy(d, projectName, poolName, &req)
 	case "copy":
-		return doVolumeCreateOrCopy(d, poolName, &req)
+		return doVolumeCreateOrCopy(d, projectName, poolName, &req)
 	case "migration":
 		return doVolumeMigration(d, poolName, &req)
 	default:
-		return response.BadRequest(fmt.Errorf("unknown source type %s", req.Source.Type))
+		return response.BadRequest(fmt.Errorf("Unknown source type %q", req.Source.Type))
 	}
 }
 
-func doVolumeCreateOrCopy(d *Daemon, poolName string, req *api.StorageVolumesPost) response.Response {
+func doVolumeCreateOrCopy(d *Daemon, projectName, poolName string, req *api.StorageVolumesPost) response.Response {
 	var run func(op *operations.Operation) error
 
 	pool, err := storagePools.GetPoolByName(d.State(), poolName)
@@ -314,10 +324,10 @@ func doVolumeCreateOrCopy(d *Daemon, poolName string, req *api.StorageVolumesPos
 
 	run = func(op *operations.Operation) error {
 		if req.Source.Name == "" {
-			return pool.CreateCustomVolume(req.Name, req.Description, req.Config, op)
+			return pool.CreateCustomVolume(projectName, req.Name, req.Description, req.Config, op)
 		}
 
-		return pool.CreateCustomVolumeFromCopy(req.Name, req.Description, req.Config, req.Source.Pool, req.Source.Name, req.Source.VolumeOnly, op)
+		return pool.CreateCustomVolumeFromCopy(projectName, req.Name, req.Description, req.Config, req.Source.Pool, req.Source.Name, req.Source.VolumeOnly, op)
 	}
 
 	// If no source name supplied then this a volume create operation.
@@ -342,6 +352,11 @@ func doVolumeCreateOrCopy(d *Daemon, poolName string, req *api.StorageVolumesPos
 // /1.0/storage-pools/{name}/volumes/{type}
 // Create a storage volume of a given volume type in a given storage pool.
 func storagePoolVolumesPost(d *Daemon, r *http.Request) response.Response {
+	projectName, err := project.StorageVolumeProject(d.State().Cluster, projectParam(r))
+	if err != nil {
+		return response.SmartError(err)
+	}
+
 	resp := ForwardedResponseIfTargetIsRemote(d, r)
 	if resp != nil {
 		return resp
@@ -350,7 +365,7 @@ func storagePoolVolumesPost(d *Daemon, r *http.Request) response.Response {
 	req := api.StorageVolumesPost{}
 
 	// Parse the request.
-	err := json.NewDecoder(r.Body).Decode(&req)
+	err = json.NewDecoder(r.Body).Decode(&req)
 	if err != nil {
 		return response.BadRequest(err)
 	}
@@ -384,7 +399,7 @@ func storagePoolVolumesPost(d *Daemon, r *http.Request) response.Response {
 	}
 
 	// Check if destination volume exists.
-	_, _, err = d.cluster.StoragePoolNodeVolumeGetTypeByProject("default", req.Name, db.StoragePoolVolumeTypeCustom, poolID)
+	_, _, err = d.cluster.StoragePoolNodeVolumeGetTypeByProject(projectName, req.Name, db.StoragePoolVolumeTypeCustom, poolID)
 	if err != db.ErrNoSuchObject {
 		if err != nil {
 			return response.SmartError(err)
@@ -395,9 +410,9 @@ func storagePoolVolumesPost(d *Daemon, r *http.Request) response.Response {
 
 	switch req.Source.Type {
 	case "":
-		return doVolumeCreateOrCopy(d, poolName, &req)
+		return doVolumeCreateOrCopy(d, projectName, poolName, &req)
 	case "copy":
-		return doVolumeCreateOrCopy(d, poolName, &req)
+		return doVolumeCreateOrCopy(d, projectName, poolName, &req)
 	case "migration":
 		return doVolumeMigration(d, poolName, &req)
 	default:
@@ -488,6 +503,8 @@ func doVolumeMigration(d *Daemon, poolName string, req *api.StorageVolumesPost)
 // Rename a storage volume of a given volume type in a given storage pool.
 // Also supports moving a storage volume between pools and migrating to a different host.
 func storagePoolVolumeTypePost(d *Daemon, r *http.Request, volumeTypeName string) response.Response {
+	projectName := projectParam(r)
+
 	// Get the name of the storage volume.
 	volumeName := mux.Vars(r)["name"]
 
@@ -595,11 +612,11 @@ func storagePoolVolumeTypePost(d *Daemon, r *http.Request, volumeTypeName string
 
 	// Detect a rename request.
 	if req.Pool == "" || req.Pool == poolName {
-		return storagePoolVolumeTypePostRename(d, poolName, volumeName, volumeType, req)
+		return storagePoolVolumeTypePostRename(d, projectName, poolName, volumeName, volumeType, req)
 	}
 
 	// Otherwise this is a move request.
-	return storagePoolVolumeTypePostMove(d, poolName, volumeName, volumeType, req)
+	return storagePoolVolumeTypePostMove(d, projectName, poolName, volumeName, volumeType, req)
 }
 
 // storagePoolVolumeTypePostMigration handles volume migration type POST requests.
@@ -641,9 +658,14 @@ func storagePoolVolumeTypePostMigration(state *state.State, poolName string, vol
 }
 
 // storagePoolVolumeTypePostRename handles volume rename type POST requests.
-func storagePoolVolumeTypePostRename(d *Daemon, poolName string, volumeName string, volumeType int, req api.StorageVolumePost) response.Response {
+func storagePoolVolumeTypePostRename(d *Daemon, projectName, poolName, volumeName string, volumeType int, req api.StorageVolumePost) response.Response {
+	projectName, err := project.StorageVolumeProject(d.State().Cluster, projectName)
+	if err != nil {
+		return response.SmartError(err)
+	}
+
 	// Notify users of the volume that it's name is changing.
-	err := storagePoolVolumeUpdateUsers(d, poolName, volumeName, req.Pool, req.Name)
+	err = storagePoolVolumeUpdateUsers(d, poolName, volumeName, req.Pool, req.Name)
 	if err != nil {
 		return response.SmartError(err)
 	}
@@ -653,7 +675,7 @@ func storagePoolVolumeTypePostRename(d *Daemon, poolName string, volumeName stri
 		return response.SmartError(err)
 	}
 
-	err = pool.RenameCustomVolume(volumeName, req.Name, nil)
+	err = pool.RenameCustomVolume(projectName, volumeName, req.Name, nil)
 	if err != nil {
 		// Notify users of the volume that it's name is changing back.
 		storagePoolVolumeUpdateUsers(d, req.Pool, req.Name, poolName, volumeName)
@@ -664,7 +686,12 @@ func storagePoolVolumeTypePostRename(d *Daemon, poolName string, volumeName stri
 }
 
 // storagePoolVolumeTypePostMove handles volume move type POST requests.
-func storagePoolVolumeTypePostMove(d *Daemon, poolName string, volumeName string, volumeType int, req api.StorageVolumePost) response.Response {
+func storagePoolVolumeTypePostMove(d *Daemon, projectName, poolName, volumeName string, volumeType int, req api.StorageVolumePost) response.Response {
+	projectName, err := project.StorageVolumeProject(d.State().Cluster, projectName)
+	if err != nil {
+		return response.SmartError(err)
+	}
+
 	var run func(op *operations.Operation) error
 
 	srcPool, err := storagePools.GetPoolByName(d.State(), poolName)
@@ -686,14 +713,14 @@ func storagePoolVolumeTypePostMove(d *Daemon, poolName string, volumeName string
 
 		// Provide empty description and nil config to instruct
 		// CreateCustomVolumeFromCopy to copy it from source volume.
-		err = pool.CreateCustomVolumeFromCopy(req.Name, "", nil, poolName, volumeName, false, op)
+		err = pool.CreateCustomVolumeFromCopy(projectName, req.Name, "", nil, poolName, volumeName, false, op)
 		if err != nil {
 			// Notify users of the volume that it's name is changing back.
 			storagePoolVolumeUpdateUsers(d, req.Pool, req.Name, poolName, volumeName)
 			return err
 		}
 
-		return srcPool.DeleteCustomVolume(volumeName, op)
+		return srcPool.DeleteCustomVolume(projectName, volumeName, op)
 	}
 
 	op, err := operations.OperationCreate(d.State(), "", operations.OperationClassTask, db.OperationVolumeMove, nil, nil, run, nil, nil)
@@ -815,7 +842,7 @@ func storagePoolVolumeTypeImageGet(d *Daemon, r *http.Request) response.Response
 // This function does allow limited functionality for non-custom volume types, specifically you
 // can modify the volume's description only.
 func storagePoolVolumeTypePut(d *Daemon, r *http.Request, volumeTypeName string) response.Response {
-	project := projectParam(r)
+	projectName := projectParam(r)
 
 	// Get the name of the storage volume.
 	volumeName, err := storageGetVolumeNameFromURL(r)
@@ -837,6 +864,14 @@ func storagePoolVolumeTypePut(d *Daemon, r *http.Request, volumeTypeName string)
 		return response.BadRequest(fmt.Errorf("Invalid storage volume type %q", volumeTypeName))
 	}
 
+	// Decide which project this custom volume should be in.
+	if volumeType == db.StoragePoolVolumeTypeCustom {
+		projectName, err = project.StorageVolumeProject(d.State().Cluster, projectName)
+		if err != nil {
+			return response.SmartError(err)
+		}
+	}
+
 	pool, err := storagePools.GetPoolByName(d.State(), poolName)
 	if err != nil {
 		return response.SmartError(err)
@@ -853,7 +888,7 @@ func storagePoolVolumeTypePut(d *Daemon, r *http.Request, volumeTypeName string)
 	}
 
 	// Get the existing storage volume.
-	_, vol, err := d.cluster.StoragePoolNodeVolumeGetTypeByProject(project, volumeName, volumeType, pool.ID())
+	_, vol, err := d.cluster.StoragePoolNodeVolumeGetTypeByProject(projectName, volumeName, volumeType, pool.ID())
 	if err != nil {
 		return response.SmartError(err)
 	}
@@ -876,19 +911,19 @@ func storagePoolVolumeTypePut(d *Daemon, r *http.Request, volumeTypeName string)
 		// before applying config changes so that changes are applied to the
 		// restored volume.
 		if req.Restore != "" {
-			err = pool.RestoreCustomVolume(vol.Name, req.Restore, nil)
+			err = pool.RestoreCustomVolume(projectName, vol.Name, req.Restore, nil)
 			if err != nil {
 				return response.SmartError(err)
 			}
 		}
 
 		// Handle custom volume update requests.
-		err = pool.UpdateCustomVolume(vol.Name, req.Description, req.Config, nil)
+		err = pool.UpdateCustomVolume(projectName, vol.Name, req.Description, req.Config, nil)
 		if err != nil {
 			return response.SmartError(err)
 		}
 	} else if volumeType == db.StoragePoolVolumeTypeContainer || volumeType == db.StoragePoolVolumeTypeVM {
-		inst, err := instance.LoadByProjectAndName(d.State(), project, vol.Name)
+		inst, err := instance.LoadByProjectAndName(d.State(), projectName, vol.Name)
 		if err != nil {
 			return response.NotFound(err)
 		}
@@ -941,6 +976,11 @@ func storagePoolVolumeTypeImagePut(d *Daemon, r *http.Request) response.Response
 
 // /1.0/storage-pools/{pool}/volumes/{type}/{name}
 func storagePoolVolumeTypePatch(d *Daemon, r *http.Request, volumeTypeName string) response.Response {
+	projectName, err := project.StorageVolumeProject(d.State().Cluster, projectParam(r))
+	if err != nil {
+		return response.SmartError(err)
+	}
+
 	// Get the name of the storage volume.
 	volumeName := mux.Vars(r)["name"]
 
@@ -1008,7 +1048,7 @@ func storagePoolVolumeTypePatch(d *Daemon, r *http.Request, volumeTypeName strin
 		}
 	}
 
-	err = pool.UpdateCustomVolume(vol.Name, req.Description, req.Config, nil)
+	err = pool.UpdateCustomVolume(projectName, vol.Name, req.Description, req.Config, nil)
 	if err != nil {
 		return response.SmartError(err)
 	}
@@ -1034,7 +1074,7 @@ func storagePoolVolumeTypeImagePatch(d *Daemon, r *http.Request) response.Respon
 
 // /1.0/storage-pools/{pool}/volumes/{type}/{name}
 func storagePoolVolumeTypeDelete(d *Daemon, r *http.Request, volumeTypeName string) response.Response {
-	project := projectParam(r)
+	projectName := projectParam(r)
 
 	// Get the name of the storage volume.
 	volumeName := mux.Vars(r)["name"]
@@ -1051,11 +1091,20 @@ func storagePoolVolumeTypeDelete(d *Daemon, r *http.Request, volumeTypeName stri
 	if err != nil {
 		return response.BadRequest(err)
 	}
+
 	// Check that the storage volume type is valid.
 	if !shared.IntInSlice(volumeType, supportedVolumeTypes) {
 		return response.BadRequest(fmt.Errorf("Invalid storage volume type %q", volumeTypeName))
 	}
 
+	// Decide which project this custom volume should be in.
+	if volumeType == db.StoragePoolVolumeTypeCustom {
+		projectName, err = project.StorageVolumeProject(d.State().Cluster, projectName)
+		if err != nil {
+			return response.SmartError(err)
+		}
+	}
+
 	resp := ForwardedResponseIfTargetIsRemote(d, r)
 	if resp != nil {
 		return resp
@@ -1075,7 +1124,7 @@ func storagePoolVolumeTypeDelete(d *Daemon, r *http.Request, volumeTypeName stri
 		return response.BadRequest(fmt.Errorf("Storage volumes of type %q cannot be deleted with the storage API", volumeTypeName))
 	}
 
-	volumeUsedBy, err := storagePoolVolumeUsedByGet(d.State(), project, poolName, volumeName, volumeTypeName)
+	volumeUsedBy, err := storagePoolVolumeUsedByGet(d.State(), projectName, poolName, volumeName, volumeTypeName)
 	if err != nil {
 		return response.SmartError(err)
 	}
@@ -1093,7 +1142,7 @@ func storagePoolVolumeTypeDelete(d *Daemon, r *http.Request, volumeTypeName stri
 
 	switch volumeType {
 	case db.StoragePoolVolumeTypeCustom:
-		err = pool.DeleteCustomVolume(volumeName, nil)
+		err = pool.DeleteCustomVolume(projectName, volumeName, nil)
 	case db.StoragePoolVolumeTypeImage:
 		err = pool.DeleteImage(volumeName, nil)
 	default:

From 9aa7e32d1f3fc37f1f60fc28b9e0571427886d20 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 13:22:42 +0000
Subject: [PATCH 21/40] lxd/storage/volumes/snapshots: Improve volume type
 validation

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage_volumes_snapshot.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lxd/storage_volumes_snapshot.go b/lxd/storage_volumes_snapshot.go
index dca4382915..3ea16e577e 100644
--- a/lxd/storage_volumes_snapshot.go
+++ b/lxd/storage_volumes_snapshot.go
@@ -58,8 +58,8 @@ func storagePoolVolumeSnapshotsTypePost(d *Daemon, r *http.Request) response.Res
 	}
 
 	// Check that the storage volume type is valid.
-	if !shared.IntInSlice(volumeType, supportedVolumeTypes) {
-		return response.BadRequest(fmt.Errorf("Invalid storage volume type \"%d\"", volumeType))
+	if volumeType != db.StoragePoolVolumeTypeCustom {
+		return response.BadRequest(fmt.Errorf("Invalid storage volume type %q", volumeTypeName))
 	}
 
 	// Get a snapshot name.

From 7f3be75b85debc2d68caeceb3e1e2c128666d29f Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 13:23:14 +0000
Subject: [PATCH 22/40] lxd/storage/volumes/snapshot: Error message quoting

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage_volumes_snapshot.go | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/lxd/storage_volumes_snapshot.go b/lxd/storage_volumes_snapshot.go
index 3ea16e577e..b8c10acee0 100644
--- a/lxd/storage_volumes_snapshot.go
+++ b/lxd/storage_volumes_snapshot.go
@@ -150,17 +150,16 @@ func storagePoolVolumeSnapshotsTypeGet(d *Daemon, r *http.Request) response.Resp
 	}
 	// Check that the storage volume type is valid.
 	if !shared.IntInSlice(volumeType, supportedVolumeTypes) {
-		return response.BadRequest(fmt.Errorf("invalid storage volume type %s", volumeTypeName))
+		return response.BadRequest(fmt.Errorf("Invalid storage volume type %q", volumeTypeName))
 	}
 
-	// Retrieve ID of the storage pool (and check if the storage pool
-	// exists).
+	// Retrieve ID of the storage pool (and check if the storage pool exists).
 	poolID, err := d.cluster.StoragePoolGetID(poolName)
 	if err != nil {
 		return response.SmartError(err)
 	}
 
-	// Get the names of all storage volume snapshots of a given volume
+	// Get the names of all storage volume snapshots of a given volume.
 	volumes, err := d.cluster.StoragePoolVolumeSnapshotsGetType(volumeName, volumeType, poolID)
 	if err != nil {
 		return response.SmartError(err)
@@ -244,7 +243,7 @@ func storagePoolVolumeSnapshotTypePost(d *Daemon, r *http.Request) response.Resp
 
 	// Check that the storage volume type is valid.
 	if volumeType != db.StoragePoolVolumeTypeCustom {
-		return response.BadRequest(fmt.Errorf("invalid storage volume type %s", volumeTypeName))
+		return response.BadRequest(fmt.Errorf("Invalid storage volume type %q", volumeTypeName))
 	}
 
 	resp := ForwardedResponseIfTargetIsRemote(d, r)
@@ -305,7 +304,7 @@ func storagePoolVolumeSnapshotTypeGet(d *Daemon, r *http.Request) response.Respo
 
 	// Check that the storage volume type is valid.
 	if volumeType != db.StoragePoolVolumeTypeCustom {
-		return response.BadRequest(fmt.Errorf("invalid storage volume type %s", volumeTypeName))
+		return response.BadRequest(fmt.Errorf("Invalid storage volume type %q", volumeTypeName))
 	}
 
 	resp := ForwardedResponseIfTargetIsRemote(d, r)
@@ -362,7 +361,7 @@ func storagePoolVolumeSnapshotTypePut(d *Daemon, r *http.Request) response.Respo
 
 	// Check that the storage volume type is valid.
 	if volumeType != db.StoragePoolVolumeTypeCustom {
-		return response.BadRequest(fmt.Errorf("Invalid storage volume type %s", volumeTypeName))
+		return response.BadRequest(fmt.Errorf("Invalid storage volume type %q", volumeTypeName))
 	}
 
 	resp := ForwardedResponseIfTargetIsRemote(d, r)
@@ -442,7 +441,7 @@ func storagePoolVolumeSnapshotTypeDelete(d *Daemon, r *http.Request) response.Re
 
 	// Check that the storage volume type is valid.
 	if volumeType != db.StoragePoolVolumeTypeCustom {
-		return response.BadRequest(fmt.Errorf("invalid storage volume type %s", volumeTypeName))
+		return response.BadRequest(fmt.Errorf("Invalid storage volume type %q", volumeTypeName))
 	}
 
 	resp := ForwardedResponseIfTargetIsRemote(d, r)

From 853c48a7baf65c3752f9e66699a1ba49b82943d0 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 13:23:55 +0000
Subject: [PATCH 23/40] lxd/storage/volumes/snapshot: Adds project support for
 custom volumes

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage_volumes_snapshot.go | 46 +++++++++++++++++++++++++--------
 1 file changed, 35 insertions(+), 11 deletions(-)

diff --git a/lxd/storage_volumes_snapshot.go b/lxd/storage_volumes_snapshot.go
index b8c10acee0..ae0344a1d4 100644
--- a/lxd/storage_volumes_snapshot.go
+++ b/lxd/storage_volumes_snapshot.go
@@ -10,6 +10,7 @@ import (
 
 	"github.com/lxc/lxd/lxd/db"
 	"github.com/lxc/lxd/lxd/operations"
+	"github.com/lxc/lxd/lxd/project"
 	"github.com/lxc/lxd/lxd/response"
 	storagePools "github.com/lxc/lxd/lxd/storage"
 	"github.com/lxc/lxd/lxd/util"
@@ -35,6 +36,11 @@ var storagePoolVolumeSnapshotTypeCmd = APIEndpoint{
 }
 
 func storagePoolVolumeSnapshotsTypePost(d *Daemon, r *http.Request) response.Response {
+	projectName, err := project.StorageVolumeProject(d.State().Cluster, projectParam(r))
+	if err != nil {
+		return response.SmartError(err)
+	}
+
 	// Get the name of the pool.
 	poolName := mux.Vars(r)["pool"]
 
@@ -46,7 +52,7 @@ func storagePoolVolumeSnapshotsTypePost(d *Daemon, r *http.Request) response.Res
 
 	// Parse the request.
 	req := api.StorageVolumeSnapshotsPost{}
-	err := json.NewDecoder(r.Body).Decode(&req)
+	err = json.NewDecoder(r.Body).Decode(&req)
 	if err != nil {
 		return response.BadRequest(err)
 	}
@@ -116,7 +122,7 @@ func storagePoolVolumeSnapshotsTypePost(d *Daemon, r *http.Request) response.Res
 			return err
 		}
 
-		return pool.CreateCustomVolumeSnapshot(volumeName, req.Name, op)
+		return pool.CreateCustomVolumeSnapshot(projectName, volumeName, req.Name, op)
 	}
 
 	resources := map[string][]string{}
@@ -131,8 +137,12 @@ func storagePoolVolumeSnapshotsTypePost(d *Daemon, r *http.Request) response.Res
 }
 
 func storagePoolVolumeSnapshotsTypeGet(d *Daemon, r *http.Request) response.Response {
-	// Get the name of the pool the storage volume is supposed to be
-	// attached to.
+	projectName, err := project.StorageVolumeProject(d.State().Cluster, projectParam(r))
+	if err != nil {
+		return response.SmartError(err)
+	}
+
+	// Get the name of the pool the storage volume is supposed to be attached to.
 	poolName := mux.Vars(r)["pool"]
 
 	recursion := util.IsRecursionRequest(r)
@@ -182,7 +192,7 @@ func storagePoolVolumeSnapshotsTypeGet(d *Daemon, r *http.Request) response.Resp
 				continue
 			}
 
-			volumeUsedBy, err := storagePoolVolumeUsedByGet(d.State(), "default", poolName, vol.Name, vol.Type)
+			volumeUsedBy, err := storagePoolVolumeUsedByGet(d.State(), projectName, poolName, vol.Name, vol.Type)
 			if err != nil {
 				return response.SmartError(err)
 			}
@@ -205,8 +215,12 @@ func storagePoolVolumeSnapshotsTypeGet(d *Daemon, r *http.Request) response.Resp
 }
 
 func storagePoolVolumeSnapshotTypePost(d *Daemon, r *http.Request) response.Response {
-	// Get the name of the storage pool the volume is supposed to be
-	// attached to.
+	projectName, err := project.StorageVolumeProject(d.State().Cluster, projectParam(r))
+	if err != nil {
+		return response.SmartError(err)
+	}
+
+	// Get the name of the storage pool the volume is supposed to be attached to.
 	poolName := mux.Vars(r)["pool"]
 
 	// Get the name of the volume type.
@@ -221,7 +235,7 @@ func storagePoolVolumeSnapshotTypePost(d *Daemon, r *http.Request) response.Resp
 	req := api.StorageVolumeSnapshotPost{}
 
 	// Parse the request.
-	err := json.NewDecoder(r.Body).Decode(&req)
+	err = json.NewDecoder(r.Body).Decode(&req)
 	if err != nil {
 		return response.BadRequest(err)
 	}
@@ -268,7 +282,7 @@ func storagePoolVolumeSnapshotTypePost(d *Daemon, r *http.Request) response.Resp
 			return err
 		}
 
-		return pool.RenameCustomVolumeSnapshot(fullSnapshotName, req.Name, op)
+		return pool.RenameCustomVolumeSnapshot(projectName, fullSnapshotName, req.Name, op)
 	}
 
 	resources := map[string][]string{}
@@ -340,6 +354,11 @@ func storagePoolVolumeSnapshotTypeGet(d *Daemon, r *http.Request) response.Respo
 
 // storagePoolVolumeSnapshotTypePut allows a snapshot's description to be changed.
 func storagePoolVolumeSnapshotTypePut(d *Daemon, r *http.Request) response.Response {
+	projectName, err := project.StorageVolumeProject(d.State().Cluster, projectParam(r))
+	if err != nil {
+		return response.SmartError(err)
+	}
+
 	// Get the name of the storage pool the volume is supposed to be
 	// attached to.
 	poolName := mux.Vars(r)["pool"]
@@ -405,7 +424,7 @@ func storagePoolVolumeSnapshotTypePut(d *Daemon, r *http.Request) response.Respo
 		}
 
 		// Handle custom volume update requests.
-		return pool.UpdateCustomVolumeSnapshot(vol.Name, req.Description, nil, op)
+		return pool.UpdateCustomVolumeSnapshot(projectName, vol.Name, req.Description, nil, op)
 	}
 
 	resources := map[string][]string{}
@@ -420,6 +439,11 @@ func storagePoolVolumeSnapshotTypePut(d *Daemon, r *http.Request) response.Respo
 }
 
 func storagePoolVolumeSnapshotTypeDelete(d *Daemon, r *http.Request) response.Response {
+	projectName, err := project.StorageVolumeProject(d.State().Cluster, projectParam(r))
+	if err != nil {
+		return response.SmartError(err)
+	}
+
 	// Get the name of the storage pool the volume is supposed to be
 	// attached to.
 	poolName := mux.Vars(r)["pool"]
@@ -466,7 +490,7 @@ func storagePoolVolumeSnapshotTypeDelete(d *Daemon, r *http.Request) response.Re
 			return err
 		}
 
-		return pool.DeleteCustomVolumeSnapshot(fullSnapshotName, op)
+		return pool.DeleteCustomVolumeSnapshot(projectName, fullSnapshotName, op)
 	}
 
 	resources := map[string][]string{}

From d941dee7dab429d5dcc4915e2c2f55187cbabf09 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 13:44:07 +0000
Subject: [PATCH 24/40] lxd/storage/backend/lxd: Updates custom volume
 functions to support projects

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/backend_lxd.go | 208 +++++++++++++++++++++++--------------
 1 file changed, 128 insertions(+), 80 deletions(-)

diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index 393da41e7b..94dc913b87 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -1943,7 +1943,7 @@ func (b *lxdBackend) EnsureImage(fingerprint string, op *operations.Operation) e
 	}
 
 	// Try and load any existing volume config on this storage pool so we can compare filesystems if needed.
-	_, imgDBVol, err := b.state.Cluster.StoragePoolNodeVolumeGetTypeByProject("default", fingerprint, db.StoragePoolVolumeTypeImage, b.ID())
+	_, imgDBVol, err := b.state.Cluster.StoragePoolNodeVolumeGetTypeByProject(project.Default, fingerprint, db.StoragePoolVolumeTypeImage, b.ID())
 	if err != nil {
 		if err != db.ErrNoSuchObject {
 			return err
@@ -1981,7 +1981,7 @@ func (b *lxdBackend) EnsureImage(fingerprint string, op *operations.Operation) e
 		return err
 	}
 
-	err = VolumeDBCreate(b.state, "default", b.name, fingerprint, "", db.StoragePoolVolumeTypeNameImage, false, nil)
+	err = VolumeDBCreate(b.state, project.Default, b.name, fingerprint, "", db.StoragePoolVolumeTypeNameImage, false, nil)
 	if err != nil {
 		return err
 	}
@@ -2027,7 +2027,7 @@ func (b *lxdBackend) DeleteImage(fingerprint string, op *operations.Operation) e
 		return err
 	}
 
-	err = b.state.Cluster.StoragePoolVolumeDelete("default", fingerprint, db.StoragePoolVolumeTypeImage, b.ID())
+	err = b.state.Cluster.StoragePoolVolumeDelete(project.Default, fingerprint, db.StoragePoolVolumeTypeImage, b.ID())
 	if err != nil {
 		return err
 	}
@@ -2073,24 +2073,27 @@ func (b *lxdBackend) UpdateImage(fingerprint, newDesc string, newConfig map[stri
 	logger.Debug("UpdateImage started")
 	defer logger.Debug("UpdateImage finished")
 
-	return b.updateVolumeDescriptionOnly("default", fingerprint, db.StoragePoolVolumeTypeImage, newDesc, newConfig)
+	return b.updateVolumeDescriptionOnly(project.Default, fingerprint, db.StoragePoolVolumeTypeImage, newDesc, newConfig)
 }
 
 // CreateCustomVolume creates an empty custom volume.
-func (b *lxdBackend) CreateCustomVolume(volName, desc string, config map[string]string, op *operations.Operation) error {
-	logger := logging.AddContext(b.logger, log.Ctx{"volName": volName, "desc": desc, "config": config})
+func (b *lxdBackend) CreateCustomVolume(projectName, volName, desc string, config map[string]string, op *operations.Operation) error {
+	logger := logging.AddContext(b.logger, log.Ctx{"project": projectName, "volName": volName, "desc": desc, "config": config})
 	logger.Debug("CreateCustomVolume started")
 	defer logger.Debug("CreateCustomVolume finished")
 
+	// Get the volume name on storage.
+	volStorageName := project.StorageVolume(projectName, volName)
+
 	// Validate config.
-	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volName, config)
+	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volStorageName, config)
 	err := b.driver.ValidateVolume(vol, false)
 	if err != nil {
 		return err
 	}
 
 	// Create database entry for new storage volume.
-	err = VolumeDBCreate(b.state, "default", b.name, volName, desc, db.StoragePoolVolumeTypeNameCustom, false, vol.Config())
+	err = VolumeDBCreate(b.state, projectName, b.name, volName, desc, db.StoragePoolVolumeTypeNameCustom, false, vol.Config())
 	if err != nil {
 		return err
 	}
@@ -2098,7 +2101,7 @@ func (b *lxdBackend) CreateCustomVolume(volName, desc string, config map[string]
 	revertDB := true
 	defer func() {
 		if revertDB {
-			b.state.Cluster.StoragePoolVolumeDelete("default", volName, db.StoragePoolVolumeTypeCustom, b.ID())
+			b.state.Cluster.StoragePoolVolumeDelete(projectName, volName, db.StoragePoolVolumeTypeCustom, b.ID())
 		}
 	}()
 
@@ -2114,8 +2117,8 @@ func (b *lxdBackend) CreateCustomVolume(volName, desc string, config map[string]
 
 // CreateCustomVolumeFromCopy creates a custom volume from an existing custom volume.
 // It copies the snapshots from the source volume by default, but can be disabled if requested.
-func (b *lxdBackend) CreateCustomVolumeFromCopy(volName, desc string, config map[string]string, srcPoolName, srcVolName string, srcVolOnly bool, op *operations.Operation) error {
-	logger := logging.AddContext(b.logger, log.Ctx{"volName": volName, "desc": desc, "config": config, "srcPoolName": srcPoolName, "srcVolName": srcVolName, "srcVolOnly": srcVolOnly})
+func (b *lxdBackend) CreateCustomVolumeFromCopy(projectName, volName, desc string, config map[string]string, srcPoolName, srcVolName string, srcVolOnly bool, op *operations.Operation) error {
+	logger := logging.AddContext(b.logger, log.Ctx{"project": projectName, "volName": volName, "desc": desc, "config": config, "srcPoolName": srcPoolName, "srcVolName": srcVolName, "srcVolOnly": srcVolOnly})
 	logger.Debug("CreateCustomVolumeFromCopy started")
 	defer logger.Debug("CreateCustomVolumeFromCopy finished")
 
@@ -2140,7 +2143,7 @@ func (b *lxdBackend) CreateCustomVolumeFromCopy(volName, desc string, config map
 	}
 
 	// Check source volume exists and is custom type.
-	_, srcVolRow, err := b.state.Cluster.StoragePoolNodeVolumeGetTypeByProject("default", srcVolName, db.StoragePoolVolumeTypeCustom, srcPool.ID())
+	_, srcVolRow, err := b.state.Cluster.StoragePoolNodeVolumeGetTypeByProject(projectName, srcVolName, db.StoragePoolVolumeTypeCustom, srcPool.ID())
 	if err != nil {
 		if err == db.ErrNoSuchObject {
 			return fmt.Errorf("Source volume doesn't exist")
@@ -2162,6 +2165,7 @@ func (b *lxdBackend) CreateCustomVolumeFromCopy(volName, desc string, config map
 	// If we are copying snapshots, retrieve a list of snapshots from source volume.
 	snapshotNames := []string{}
 	if !srcVolOnly {
+		// tomp TODO shouldnt this use projectName?
 		snapshots, err := VolumeSnapshotsGet(b.state, srcPoolName, srcVolName, db.StoragePoolVolumeTypeCustom)
 		if err != nil {
 			return err
@@ -2183,12 +2187,17 @@ func (b *lxdBackend) CreateCustomVolumeFromCopy(volName, desc string, config map
 		defer func() {
 			// Remove any DB volume rows created if we are reverting.
 			for _, volName := range revertDBVolumes {
-				b.state.Cluster.StoragePoolVolumeDelete("default", volName, db.StoragePoolVolumeTypeCustom, b.ID())
+				b.state.Cluster.StoragePoolVolumeDelete(projectName, volName, db.StoragePoolVolumeTypeCustom, b.ID())
 			}
 		}()
 
-		vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volName, config)
-		srcVol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, srcVolName, srcVolRow.Config)
+		// Get the volume name on storage.
+		volStorageName := project.StorageVolume(projectName, volName)
+		vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volStorageName, config)
+
+		// Get the src volume name on storage.
+		srcVolStorageName := project.StorageVolume(projectName, srcVolName)
+		srcVol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, srcVolStorageName, srcVolRow.Config)
 
 		// Check the supplied config and remove any fields not relevant for pool type.
 		err := b.driver.ValidateVolume(vol, true)
@@ -2197,7 +2206,7 @@ func (b *lxdBackend) CreateCustomVolumeFromCopy(volName, desc string, config map
 		}
 
 		// Create database entry for new storage volume.
-		err = VolumeDBCreate(b.state, "default", b.name, volName, desc, db.StoragePoolVolumeTypeNameCustom, false, vol.Config())
+		err = VolumeDBCreate(b.state, projectName, b.name, volName, desc, db.StoragePoolVolumeTypeNameCustom, false, vol.Config())
 		if err != nil {
 			return err
 		}
@@ -2209,7 +2218,7 @@ func (b *lxdBackend) CreateCustomVolumeFromCopy(volName, desc string, config map
 				newSnapshotName := drivers.GetSnapshotVolumeName(volName, snapName)
 
 				// Create database entry for new storage volume snapshot.
-				err = VolumeDBCreate(b.state, "default", b.name, newSnapshotName, desc, db.StoragePoolVolumeTypeNameCustom, true, vol.Config())
+				err = VolumeDBCreate(b.state, projectName, b.name, newSnapshotName, desc, db.StoragePoolVolumeTypeNameCustom, true, vol.Config())
 				if err != nil {
 					return err
 				}
@@ -2296,8 +2305,12 @@ func (b *lxdBackend) MigrateCustomVolume(conn io.ReadWriteCloser, args *migratio
 	logger.Debug("MigrateCustomVolume started")
 	defer logger.Debug("MigrateCustomVolume finished")
 
+	// Get the volume name on storage.
+	// tomp TODO add support for projects in migration.
+	volStorageName := project.StorageVolume(project.Default, args.Name)
+
 	// Volume config not needed to send a volume so set to nil.
-	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, args.Name, nil)
+	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volStorageName, nil)
 	err := b.driver.MigrateVolume(vol, conn, args, op)
 	if err != nil {
 		return err
@@ -2317,19 +2330,23 @@ func (b *lxdBackend) CreateCustomVolumeFromMigration(conn io.ReadWriteCloser, ar
 	defer func() {
 		// Remove any DB volume rows created if we are reverting.
 		for _, volName := range revertDBVolumes {
-			b.state.Cluster.StoragePoolVolumeDelete("default", volName, db.StoragePoolVolumeTypeCustom, b.ID())
+			b.state.Cluster.StoragePoolVolumeDelete(project.Default, volName, db.StoragePoolVolumeTypeCustom, b.ID())
 		}
 	}()
 
+	// Get the volume name on storage.
+	// tomp TODO add support for projects in migrations.
+	volStorageName := project.StorageVolume(project.Default, args.Name)
+
 	// Check the supplied config and remove any fields not relevant for destination pool type.
-	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, args.Name, args.Config)
+	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volStorageName, args.Config)
 	err := b.driver.ValidateVolume(vol, true)
 	if err != nil {
 		return err
 	}
 
 	// Create database entry for new storage volume.
-	err = VolumeDBCreate(b.state, "default", b.name, args.Name, args.Description, db.StoragePoolVolumeTypeNameCustom, false, vol.Config())
+	err = VolumeDBCreate(b.state, project.Default, b.name, args.Name, args.Description, db.StoragePoolVolumeTypeNameCustom, false, vol.Config())
 	if err != nil {
 		return err
 	}
@@ -2341,7 +2358,7 @@ func (b *lxdBackend) CreateCustomVolumeFromMigration(conn io.ReadWriteCloser, ar
 			newSnapshotName := drivers.GetSnapshotVolumeName(args.Name, snapName)
 
 			// Create database entry for new storage volume snapshot.
-			err = VolumeDBCreate(b.state, "default", b.name, newSnapshotName, args.Description, db.StoragePoolVolumeTypeNameCustom, true, vol.Config())
+			err = VolumeDBCreate(b.state, project.Default, b.name, newSnapshotName, args.Description, db.StoragePoolVolumeTypeNameCustom, true, vol.Config())
 			if err != nil {
 				return err
 			}
@@ -2361,8 +2378,8 @@ func (b *lxdBackend) CreateCustomVolumeFromMigration(conn io.ReadWriteCloser, ar
 }
 
 // RenameCustomVolume renames a custom volume and its snapshots.
-func (b *lxdBackend) RenameCustomVolume(volName string, newVolName string, op *operations.Operation) error {
-	logger := logging.AddContext(b.logger, log.Ctx{"volName": volName, "newVolName": newVolName})
+func (b *lxdBackend) RenameCustomVolume(projectName, volName string, newVolName string, op *operations.Operation) error {
+	logger := logging.AddContext(b.logger, log.Ctx{"project": projectName, "volName": volName, "newVolName": newVolName})
 	logger.Debug("RenameCustomVolume started")
 	defer logger.Debug("RenameCustomVolume finished")
 
@@ -2384,11 +2401,12 @@ func (b *lxdBackend) RenameCustomVolume(volName string, newVolName string, op *o
 	defer func() {
 		// Remove any DB volume rows created if we are reverting.
 		for _, vol := range revertDBVolumes {
-			b.state.Cluster.StoragePoolVolumeRename("default", vol.newName, vol.oldName, db.StoragePoolVolumeTypeCustom, b.ID())
+			b.state.Cluster.StoragePoolVolumeRename(projectName, vol.newName, vol.oldName, db.StoragePoolVolumeTypeCustom, b.ID())
 		}
 	}()
 
 	// Rename each snapshot to have the new parent volume prefix.
+	// tomp TODO shouldnt this use projectName?
 	snapshots, err := VolumeSnapshotsGet(b.state, b.name, volName, db.StoragePoolVolumeTypeCustom)
 	if err != nil {
 		return err
@@ -2397,7 +2415,7 @@ func (b *lxdBackend) RenameCustomVolume(volName string, newVolName string, op *o
 	for _, srcSnapshot := range snapshots {
 		_, snapName, _ := shared.InstanceGetParentAndSnapshotName(srcSnapshot.Name)
 		newSnapVolName := drivers.GetSnapshotVolumeName(newVolName, snapName)
-		err = b.state.Cluster.StoragePoolVolumeRename("default", srcSnapshot.Name, newSnapVolName, db.StoragePoolVolumeTypeCustom, b.ID())
+		err = b.state.Cluster.StoragePoolVolumeRename(projectName, srcSnapshot.Name, newSnapVolName, db.StoragePoolVolumeTypeCustom, b.ID())
 		if err != nil {
 			return err
 		}
@@ -2408,7 +2426,7 @@ func (b *lxdBackend) RenameCustomVolume(volName string, newVolName string, op *o
 		})
 	}
 
-	err = b.state.Cluster.StoragePoolVolumeRename("default", volName, newVolName, db.StoragePoolVolumeTypeCustom, b.ID())
+	err = b.state.Cluster.StoragePoolVolumeRename(projectName, volName, newVolName, db.StoragePoolVolumeTypeCustom, b.ID())
 	if err != nil {
 		return err
 	}
@@ -2418,9 +2436,11 @@ func (b *lxdBackend) RenameCustomVolume(volName string, newVolName string, op *o
 		oldName: volName,
 	})
 
-	// There's no need to pass the config as it's not needed when renaming a
-	// volume.
-	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volName, nil)
+	// Get the volume name on storage.
+	volStorageName := project.StorageVolume(projectName, volName)
+
+	// There's no need to pass the config as it's not needed when renaming a volume.
+	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volStorageName, nil)
 
 	err = b.driver.RenameVolume(vol, newVolName, op)
 	if err != nil {
@@ -2462,8 +2482,8 @@ func (b *lxdBackend) detectChangedConfig(curConfig, newConfig map[string]string)
 }
 
 // UpdateCustomVolume applies the supplied config to the custom volume.
-func (b *lxdBackend) UpdateCustomVolume(volName, newDesc string, newConfig map[string]string, op *operations.Operation) error {
-	logger := logging.AddContext(b.logger, log.Ctx{"volName": volName, "newDesc": newDesc, "newConfig": newConfig})
+func (b *lxdBackend) UpdateCustomVolume(projectName, volName, newDesc string, newConfig map[string]string, op *operations.Operation) error {
+	logger := logging.AddContext(b.logger, log.Ctx{"project": projectName, "volName": volName, "newDesc": newDesc, "newConfig": newConfig})
 	logger.Debug("UpdateCustomVolume started")
 	defer logger.Debug("UpdateCustomVolume finished")
 
@@ -2471,15 +2491,18 @@ func (b *lxdBackend) UpdateCustomVolume(volName, newDesc string, newConfig map[s
 		return fmt.Errorf("Volume name cannot be a snapshot")
 	}
 
+	// Get the volume name on storage.
+	volStorageName := project.StorageVolume(projectName, volName)
+
 	// Validate config.
-	newVol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volName, newConfig)
+	newVol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volStorageName, newConfig)
 	err := b.driver.ValidateVolume(newVol, false)
 	if err != nil {
 		return err
 	}
 
 	// Get current config to compare what has changed.
-	_, curVol, err := b.state.Cluster.StoragePoolNodeVolumeGetTypeByProject("default", volName, db.StoragePoolVolumeTypeCustom, b.ID())
+	_, curVol, err := b.state.Cluster.StoragePoolNodeVolumeGetTypeByProject(projectName, volName, db.StoragePoolVolumeTypeCustom, b.ID())
 	if err != nil {
 		if err == db.ErrNoSuchObject {
 			return fmt.Errorf("Volume doesn't exist")
@@ -2496,7 +2519,7 @@ func (b *lxdBackend) UpdateCustomVolume(volName, newDesc string, newConfig map[s
 			return fmt.Errorf("Custom volume 'block.filesystem' property cannot be changed")
 		}
 
-		curVol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volName, curVol.Config)
+		curVol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volStorageName, curVol.Config)
 		if !userOnly {
 			err = b.driver.UpdateVolume(curVol, changedConfig)
 			if err != nil {
@@ -2530,7 +2553,7 @@ func (b *lxdBackend) UpdateCustomVolume(volName, newDesc string, newConfig map[s
 
 	// Update the database if something changed.
 	if len(changedConfig) != 0 || newDesc != curVol.Description {
-		err = b.state.Cluster.StoragePoolVolumeUpdateByProject("default", volName, db.StoragePoolVolumeTypeCustom, b.ID(), newDesc, newConfig)
+		err = b.state.Cluster.StoragePoolVolumeUpdateByProject(projectName, volName, db.StoragePoolVolumeTypeCustom, b.ID(), newDesc, newConfig)
 		if err != nil {
 			return err
 		}
@@ -2541,8 +2564,8 @@ func (b *lxdBackend) UpdateCustomVolume(volName, newDesc string, newConfig map[s
 
 // UpdateCustomVolumeSnapshot updates the description of a custom volume snapshot.
 // Volume config is not allowd to be updated and will return an error.
-func (b *lxdBackend) UpdateCustomVolumeSnapshot(volName, newDesc string, newConfig map[string]string, op *operations.Operation) error {
-	logger := logging.AddContext(b.logger, log.Ctx{"volName": volName, "newDesc": newDesc, "newConfig": newConfig})
+func (b *lxdBackend) UpdateCustomVolumeSnapshot(projectName, volName, newDesc string, newConfig map[string]string, op *operations.Operation) error {
+	logger := logging.AddContext(b.logger, log.Ctx{"project": projectName, "volName": volName, "newDesc": newDesc, "newConfig": newConfig})
 	logger.Debug("UpdateCustomVolumeSnapshot started")
 	defer logger.Debug("UpdateCustomVolumeSnapshot finished")
 
@@ -2550,12 +2573,12 @@ func (b *lxdBackend) UpdateCustomVolumeSnapshot(volName, newDesc string, newConf
 		return fmt.Errorf("Volume must be a snapshot")
 	}
 
-	return b.updateVolumeDescriptionOnly("default", volName, db.StoragePoolVolumeTypeCustom, newDesc, newConfig)
+	return b.updateVolumeDescriptionOnly(projectName, volName, db.StoragePoolVolumeTypeCustom, newDesc, newConfig)
 }
 
 // DeleteCustomVolume removes a custom volume and its snapshots.
-func (b *lxdBackend) DeleteCustomVolume(volName string, op *operations.Operation) error {
-	logger := logging.AddContext(b.logger, log.Ctx{"volName": volName})
+func (b *lxdBackend) DeleteCustomVolume(projectName, volName string, op *operations.Operation) error {
+	logger := logging.AddContext(b.logger, log.Ctx{"project": projectName, "volName": volName})
 	logger.Debug("DeleteCustomVolume started")
 	defer logger.Debug("DeleteCustomVolume finished")
 
@@ -2565,6 +2588,7 @@ func (b *lxdBackend) DeleteCustomVolume(volName string, op *operations.Operation
 	}
 
 	// Retrieve a list of snapshots.
+	// tomp TODO shouldnt this be using projectName?
 	snapshots, err := VolumeSnapshotsGet(b.state, b.name, volName, db.StoragePoolVolumeTypeCustom)
 	if err != nil {
 		return err
@@ -2572,14 +2596,17 @@ func (b *lxdBackend) DeleteCustomVolume(volName string, op *operations.Operation
 
 	// Remove each snapshot.
 	for _, snapshot := range snapshots {
-		err = b.DeleteCustomVolumeSnapshot(snapshot.Name, op)
+		err = b.DeleteCustomVolumeSnapshot(projectName, snapshot.Name, op)
 		if err != nil {
 			return err
 		}
 	}
 
+	// Get the volume name on storage.
+	volStorageName := project.StorageVolume(projectName, volName)
+
 	// There's no need to pass config as it's not needed when deleting a volume.
-	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volName, nil)
+	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volStorageName, nil)
 
 	// Delete the volume from the storage device. Must come after snapshots are removed.
 	err = b.driver.DeleteVolume(vol, op)
@@ -2588,7 +2615,7 @@ func (b *lxdBackend) DeleteCustomVolume(volName string, op *operations.Operation
 	}
 
 	// Finally, remove the volume record from the database.
-	err = b.state.Cluster.StoragePoolVolumeDelete("default", volName, db.StoragePoolVolumeTypeCustom, b.ID())
+	err = b.state.Cluster.StoragePoolVolumeDelete(projectName, volName, db.StoragePoolVolumeTypeCustom, b.ID())
 	if err != nil {
 		return err
 	}
@@ -2597,49 +2624,55 @@ func (b *lxdBackend) DeleteCustomVolume(volName string, op *operations.Operation
 }
 
 // GetCustomVolumeUsage returns the disk space used by the custom volume.
-func (b *lxdBackend) GetCustomVolumeUsage(volName string) (int64, error) {
-	// There's no need to pass config as it's not needed when getting the volume
-	// usage.
-	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volName, nil)
+func (b *lxdBackend) GetCustomVolumeUsage(projectName, volName string) (int64, error) {
+	// Get the volume name on storage.
+	volStorageName := project.StorageVolume(projectName, volName)
+
+	// There's no need to pass config as it's not needed when getting the volume usage.
+	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volStorageName, nil)
 
 	return b.driver.GetVolumeUsage(vol)
 }
 
 // MountCustomVolume mounts a custom volume.
-func (b *lxdBackend) MountCustomVolume(volName string, op *operations.Operation) (bool, error) {
-	logger := logging.AddContext(b.logger, log.Ctx{"volName": volName})
+func (b *lxdBackend) MountCustomVolume(projectName, volName string, op *operations.Operation) (bool, error) {
+	logger := logging.AddContext(b.logger, log.Ctx{"project": projectName, "volName": volName})
 	logger.Debug("MountCustomVolume started")
 	defer logger.Debug("MountCustomVolume finished")
 
-	_, volume, err := b.state.Cluster.StoragePoolNodeVolumeGetTypeByProject("default", volName, db.StoragePoolVolumeTypeCustom, b.id)
+	_, volume, err := b.state.Cluster.StoragePoolNodeVolumeGetTypeByProject(projectName, volName, db.StoragePoolVolumeTypeCustom, b.id)
 	if err != nil {
 		return false, err
 	}
 
-	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volName, volume.Config)
+	// Get the volume name on storage.
+	volStorageName := project.StorageVolume(projectName, volName)
+	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volStorageName, volume.Config)
 
 	return b.driver.MountVolume(vol, op)
 }
 
 // UnmountCustomVolume unmounts a custom volume.
-func (b *lxdBackend) UnmountCustomVolume(volName string, op *operations.Operation) (bool, error) {
-	logger := logging.AddContext(b.logger, log.Ctx{"volName": volName})
+func (b *lxdBackend) UnmountCustomVolume(projectName, volName string, op *operations.Operation) (bool, error) {
+	logger := logging.AddContext(b.logger, log.Ctx{"project": projectName, "volName": volName})
 	logger.Debug("UnmountCustomVolume started")
 	defer logger.Debug("UnmountCustomVolume finished")
 
-	_, volume, err := b.state.Cluster.StoragePoolNodeVolumeGetTypeByProject("default", volName, db.StoragePoolVolumeTypeCustom, b.id)
+	_, volume, err := b.state.Cluster.StoragePoolNodeVolumeGetTypeByProject(projectName, volName, db.StoragePoolVolumeTypeCustom, b.id)
 	if err != nil {
 		return false, err
 	}
 
-	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volName, volume.Config)
+	// Get the volume name on storage.
+	volStorageName := project.StorageVolume(projectName, volName)
+	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volStorageName, volume.Config)
 
 	return b.driver.UnmountVolume(vol, op)
 }
 
 // CreateCustomVolumeSnapshot creates a snapshot of a custom volume.
-func (b *lxdBackend) CreateCustomVolumeSnapshot(volName string, newSnapshotName string, op *operations.Operation) error {
-	logger := logging.AddContext(b.logger, log.Ctx{"volName": volName, "newSnapshotName": newSnapshotName})
+func (b *lxdBackend) CreateCustomVolumeSnapshot(projectName, volName string, newSnapshotName string, op *operations.Operation) error {
+	logger := logging.AddContext(b.logger, log.Ctx{"project": projectName, "volName": volName, "newSnapshotName": newSnapshotName})
 	logger.Debug("CreateCustomVolumeSnapshot started")
 	defer logger.Debug("CreateCustomVolumeSnapshot finished")
 
@@ -2654,7 +2687,7 @@ func (b *lxdBackend) CreateCustomVolumeSnapshot(volName string, newSnapshotName
 	fullSnapshotName := drivers.GetSnapshotVolumeName(volName, newSnapshotName)
 
 	// Check snapshot volume doesn't exist already.
-	_, _, err := b.state.Cluster.StoragePoolNodeVolumeGetTypeByProject("default", fullSnapshotName, db.StoragePoolVolumeTypeCustom, b.ID())
+	_, _, err := b.state.Cluster.StoragePoolNodeVolumeGetTypeByProject(projectName, fullSnapshotName, db.StoragePoolVolumeTypeCustom, b.ID())
 	if err != db.ErrNoSuchObject {
 		if err != nil {
 			return err
@@ -2664,7 +2697,7 @@ func (b *lxdBackend) CreateCustomVolumeSnapshot(volName string, newSnapshotName
 	}
 
 	// Load parent volume information and check it exists.
-	_, parentVol, err := b.state.Cluster.StoragePoolNodeVolumeGetTypeByProject("default", volName, db.StoragePoolVolumeTypeCustom, b.ID())
+	_, parentVol, err := b.state.Cluster.StoragePoolNodeVolumeGetTypeByProject(projectName, volName, db.StoragePoolVolumeTypeCustom, b.ID())
 	if err != nil {
 		if err == db.ErrNoSuchObject {
 			return fmt.Errorf("Parent volume doesn't exist")
@@ -2674,7 +2707,7 @@ func (b *lxdBackend) CreateCustomVolumeSnapshot(volName string, newSnapshotName
 	}
 
 	// Create database entry for new storage volume snapshot.
-	err = VolumeDBCreate(b.state, "default", b.name, fullSnapshotName, parentVol.Description, db.StoragePoolVolumeTypeNameCustom, true, parentVol.Config)
+	err = VolumeDBCreate(b.state, projectName, b.name, fullSnapshotName, parentVol.Description, db.StoragePoolVolumeTypeNameCustom, true, parentVol.Config)
 	if err != nil {
 		return err
 	}
@@ -2682,11 +2715,13 @@ func (b *lxdBackend) CreateCustomVolumeSnapshot(volName string, newSnapshotName
 	revertDB := true
 	defer func() {
 		if revertDB {
-			b.state.Cluster.StoragePoolVolumeDelete("default", fullSnapshotName, db.StoragePoolVolumeTypeCustom, b.ID())
+			b.state.Cluster.StoragePoolVolumeDelete(projectName, fullSnapshotName, db.StoragePoolVolumeTypeCustom, b.ID())
 		}
 	}()
 
-	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, fullSnapshotName, parentVol.Config)
+	// Get the volume name on storage.
+	volStorageName := project.StorageVolume(projectName, fullSnapshotName)
+	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volStorageName, parentVol.Config)
 
 	// Create the snapshot on the storage device.
 	err = b.driver.CreateVolumeSnapshot(vol, op)
@@ -2699,8 +2734,8 @@ func (b *lxdBackend) CreateCustomVolumeSnapshot(volName string, newSnapshotName
 }
 
 // RenameCustomVolumeSnapshot renames a custom volume.
-func (b *lxdBackend) RenameCustomVolumeSnapshot(volName string, newSnapshotName string, op *operations.Operation) error {
-	logger := logging.AddContext(b.logger, log.Ctx{"volName": volName, "newSnapshotName": newSnapshotName})
+func (b *lxdBackend) RenameCustomVolumeSnapshot(projectName, volName string, newSnapshotName string, op *operations.Operation) error {
+	logger := logging.AddContext(b.logger, log.Ctx{"project": projectName, "volName": volName, "newSnapshotName": newSnapshotName})
 	logger.Debug("RenameCustomVolumeSnapshot started")
 	defer logger.Debug("RenameCustomVolumeSnapshot finished")
 
@@ -2713,8 +2748,11 @@ func (b *lxdBackend) RenameCustomVolumeSnapshot(volName string, newSnapshotName
 		return fmt.Errorf("Invalid new snapshot name")
 	}
 
+	// Get the volume name on storage.
+	volStorageName := project.StorageVolume(projectName, volName)
+
 	// There's no need to pass config as it's not needed when renaming a volume.
-	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volName, nil)
+	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volStorageName, nil)
 
 	err := b.driver.RenameVolumeSnapshot(vol, newSnapshotName, op)
 	if err != nil {
@@ -2722,10 +2760,13 @@ func (b *lxdBackend) RenameCustomVolumeSnapshot(volName string, newSnapshotName
 	}
 
 	newVolName := drivers.GetSnapshotVolumeName(parentName, newSnapshotName)
-	err = b.state.Cluster.StoragePoolVolumeRename("default", volName, newVolName, db.StoragePoolVolumeTypeCustom, b.ID())
+	err = b.state.Cluster.StoragePoolVolumeRename(projectName, volName, newVolName, db.StoragePoolVolumeTypeCustom, b.ID())
 	if err != nil {
+		// Get the volume name on storage.
+		newVolStorageName := project.StorageVolume(projectName, newVolName)
+
 		// Revert rename.
-		newVol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, newVolName, nil)
+		newVol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, newVolStorageName, nil)
 		b.driver.RenameVolumeSnapshot(newVol, oldSnapshotName, op)
 		return err
 	}
@@ -2734,8 +2775,8 @@ func (b *lxdBackend) RenameCustomVolumeSnapshot(volName string, newSnapshotName
 }
 
 // DeleteCustomVolumeSnapshot removes a custom volume snapshot.
-func (b *lxdBackend) DeleteCustomVolumeSnapshot(volName string, op *operations.Operation) error {
-	logger := logging.AddContext(b.logger, log.Ctx{"volName": volName})
+func (b *lxdBackend) DeleteCustomVolumeSnapshot(projectName, volName string, op *operations.Operation) error {
+	logger := logging.AddContext(b.logger, log.Ctx{"project": projectName, "volName": volName})
 	logger.Debug("DeleteCustomVolumeSnapshot started")
 	defer logger.Debug("DeleteCustomVolumeSnapshot finished")
 
@@ -2745,9 +2786,11 @@ func (b *lxdBackend) DeleteCustomVolumeSnapshot(volName string, op *operations.O
 		return fmt.Errorf("Volume name must be a snapshot")
 	}
 
-	// There's no need to pass config as it's not needed when deleting a volume
-	// snapshot.
-	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volName, nil)
+	// Get the volume name on storage.
+	volStorageName := project.StorageVolume(projectName, volName)
+
+	// There's no need to pass config as it's not needed when deleting a volume snapshot.
+	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volStorageName, nil)
 
 	// Delete the snapshot from the storage device.
 	// Must come before DB StoragePoolVolumeDelete so that the volume ID is still available.
@@ -2757,7 +2800,7 @@ func (b *lxdBackend) DeleteCustomVolumeSnapshot(volName string, op *operations.O
 	}
 
 	// Remove the snapshot volume record from the database.
-	err = b.state.Cluster.StoragePoolVolumeDelete("default", volName, db.StoragePoolVolumeTypeCustom, b.ID())
+	err = b.state.Cluster.StoragePoolVolumeDelete(projectName, volName, db.StoragePoolVolumeTypeCustom, b.ID())
 	if err != nil {
 		return err
 	}
@@ -2766,8 +2809,8 @@ func (b *lxdBackend) DeleteCustomVolumeSnapshot(volName string, op *operations.O
 }
 
 // RestoreCustomVolume restores a custom volume from a snapshot.
-func (b *lxdBackend) RestoreCustomVolume(volName string, snapshotName string, op *operations.Operation) error {
-	logger := logging.AddContext(b.logger, log.Ctx{"volName": volName, "snapshotName": snapshotName})
+func (b *lxdBackend) RestoreCustomVolume(projectName, volName string, snapshotName string, op *operations.Operation) error {
+	logger := logging.AddContext(b.logger, log.Ctx{"project": projectName, "volName": volName, "snapshotName": snapshotName})
 	logger.Debug("RestoreCustomVolume started")
 	defer logger.Debug("RestoreCustomVolume finished")
 
@@ -2781,6 +2824,7 @@ func (b *lxdBackend) RestoreCustomVolume(volName string, snapshotName string, op
 	}
 
 	// Check that the volume isn't in use.
+	// tomp TODO shouldnt this use project?
 	usingVolume, err := VolumeUsedByInstancesWithProfiles(b.state, b.Name(), volName, db.StoragePoolVolumeTypeNameCustom, true)
 	if err != nil {
 		return err
@@ -2791,7 +2835,7 @@ func (b *lxdBackend) RestoreCustomVolume(volName string, snapshotName string, op
 	}
 
 	// Get the volume config.
-	_, dbVol, err := b.state.Cluster.StoragePoolNodeVolumeGetTypeByProject("default", volName, db.StoragePoolVolumeTypeCustom, b.ID())
+	_, dbVol, err := b.state.Cluster.StoragePoolNodeVolumeGetTypeByProject(projectName, volName, db.StoragePoolVolumeTypeCustom, b.ID())
 	if err != nil {
 		if err == db.ErrNoSuchObject {
 			return fmt.Errorf("Volume doesn't exist")
@@ -2800,20 +2844,24 @@ func (b *lxdBackend) RestoreCustomVolume(volName string, snapshotName string, op
 		return err
 	}
 
-	err = b.driver.RestoreVolume(b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volName, dbVol.Config), snapshotName, op)
+	// Get the volume name on storage.
+	volStorageName := project.StorageVolume(projectName, volName)
+	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volStorageName, dbVol.Config)
+
+	err = b.driver.RestoreVolume(vol, snapshotName, op)
 	if err != nil {
 		snapErr, ok := err.(drivers.ErrDeleteSnapshots)
 		if ok {
 			// We need to delete some snapshots and try again.
 			for _, snapName := range snapErr.Snapshots {
-				err := b.DeleteCustomVolumeSnapshot(fmt.Sprintf("%s/%s", volName, snapName), op)
+				err := b.DeleteCustomVolumeSnapshot(projectName, fmt.Sprintf("%s/%s", volName, snapName), op)
 				if err != nil {
 					return err
 				}
 			}
 
 			// Now try again.
-			err = b.driver.RestoreVolume(b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volName, dbVol.Config), snapshotName, op)
+			err = b.driver.RestoreVolume(vol, snapshotName, op)
 			if err != nil {
 				return err
 			}

From d6b07e4723bceaca7d65d7370b2d345c578d6e27 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 15:12:31 +0000
Subject: [PATCH 25/40] lxd/db/storage/pools: Removes incorrect assumption
 about custom vol projects in storagePoolVolumeGetType

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/db/storage_pools.go | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/lxd/db/storage_pools.go b/lxd/db/storage_pools.go
index 45ec44b3f2..49e26c0739 100644
--- a/lxd/db/storage_pools.go
+++ b/lxd/db/storage_pools.go
@@ -867,12 +867,6 @@ func (c *Cluster) StoragePoolNodeVolumesGetType(volumeType int, poolID int64) ([
 // Return a single storage volume attached to a given storage pool of a given
 // type, on the node with the given ID.
 func (c *Cluster) storagePoolVolumeGetType(project string, volumeName string, volumeType int, poolID, nodeID int64) (int64, *api.StorageVolume, error) {
-	// Custom volumes are "global", i.e. they are associated with the
-	// default project.
-	if volumeType == StoragePoolVolumeTypeCustom {
-		project = "default"
-	}
-
 	isSnapshot := strings.Contains(volumeName, shared.SnapshotDelimiter)
 
 	volumeID, err := c.storagePoolVolumeGetTypeID(project, volumeName, volumeType, poolID, nodeID)

From f908a82766daadaddf8ffca2b0a05c440600afbc Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 15:13:03 +0000
Subject: [PATCH 26/40] lxd/patches: Switches to using
 storageDrivers.GetVolumeMountPath

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/patches.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lxd/patches.go b/lxd/patches.go
index fff30133b1..43ab82e8ee 100644
--- a/lxd/patches.go
+++ b/lxd/patches.go
@@ -3048,7 +3048,7 @@ func patchStorageApiPermissions(name string, d *Daemon) error {
 					defer pool.UnmountCustomVolume(project.Default, vol, nil)
 				}
 
-				cuMntPoint := driver.GetStoragePoolVolumeMountPoint(poolName, vol)
+				cuMntPoint := storageDrivers.GetVolumeMountPath(poolName, storageDrivers.VolumeTypeCustom, vol)
 				err = os.Chmod(cuMntPoint, 0711)
 				if err != nil && !os.IsNotExist(err) {
 					return err

From a4fd5da762a61372433d3a45fa0887072dbf3536 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 15:13:19 +0000
Subject: [PATCH 27/40] lxd/storage/storage: Removes unused
 GetStoragePoolVolumeMountPoint

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/storage.go | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/lxd/storage/storage.go b/lxd/storage/storage.go
index 9bbd9279bd..2c680aa8f6 100644
--- a/lxd/storage/storage.go
+++ b/lxd/storage/storage.go
@@ -66,12 +66,6 @@ func GetImageMountPoint(poolName string, fingerprint string) string {
 	return shared.VarPath("storage-pools", poolName, "images", fingerprint)
 }
 
-// GetStoragePoolVolumeMountPoint returns the mountpoint of the given pool volume.
-// ${LXD_DIR}/storage-pools/<pool>/custom/<storage_volume>
-func GetStoragePoolVolumeMountPoint(poolName string, volumeName string) string {
-	return shared.VarPath("storage-pools", poolName, "custom", volumeName)
-}
-
 // GetStoragePoolVolumeSnapshotMountPoint returns the mountpoint of the given pool volume snapshot.
 // ${LXD_DIR}/storage-pools/<pool>/custom-snapshots/<custom volume name>/<snapshot name>
 func GetStoragePoolVolumeSnapshotMountPoint(poolName string, snapshotName string) string {

From 94f4c5f161dc9300f9bf35ff96c8fc3e4ce15329 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 4 Mar 2020 15:48:15 +0000
Subject: [PATCH 28/40] lxd/api: Updates projectParam to use project.Default

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/api.go | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/lxd/api.go b/lxd/api.go
index 999e0fad4a..8f5a8316d0 100644
--- a/lxd/api.go
+++ b/lxd/api.go
@@ -10,6 +10,7 @@ import (
 	"github.com/gorilla/mux"
 	"github.com/lxc/lxd/lxd/cluster"
 	"github.com/lxc/lxd/lxd/db"
+	"github.com/lxc/lxd/lxd/project"
 	"github.com/lxc/lxd/lxd/response"
 	"github.com/lxc/lxd/shared/logger"
 )
@@ -122,11 +123,11 @@ func isClusterNotification(r *http.Request) bool {
 
 // projectParam returns the project query parameter from the given request or "default" if parameter is not set.
 func projectParam(request *http.Request) string {
-	project := queryParam(request, "project")
-	if project == "" {
-		project = "default"
+	projectParam := queryParam(request, "project")
+	if projectParam == "" {
+		projectParam = project.Default
 	}
-	return project
+	return projectParam
 }
 
 // Extract the given query parameter directly from the URL, never from an

From 42d0f3dc3181acca7b29fad8bbd888271c3c2d22 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 5 Mar 2020 08:23:48 +0000
Subject: [PATCH 29/40] lxd: project.Default usage

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/api_1.0.go                      |  9 ++--
 lxd/api_project.go                  | 10 ++--
 lxd/container.go                    |  5 +-
 lxd/container_snapshot.go           | 13 +++---
 lxd/containers.go                   |  9 ++--
 lxd/devlxd.go                       |  6 +--
 lxd/images.go                       |  3 +-
 lxd/instance/drivers/driver_lxc.go  |  2 +-
 lxd/instance/drivers/driver_qemu.go |  2 +-
 lxd/networks.go                     |  3 +-
 lxd/operations.go                   |  9 ++--
 lxd/profiles.go                     | 71 +++++++++++++++--------------
 lxd/profiles_utils.go               |  2 +-
 lxd/storage_volumes_utils.go        | 11 +++--
 14 files changed, 82 insertions(+), 73 deletions(-)

diff --git a/lxd/api_1.0.go b/lxd/api_1.0.go
index 0cfb1b0bbf..d54eff5c72 100644
--- a/lxd/api_1.0.go
+++ b/lxd/api_1.0.go
@@ -13,6 +13,7 @@ import (
 	"github.com/lxc/lxd/lxd/config"
 	"github.com/lxc/lxd/lxd/db"
 	"github.com/lxc/lxd/lxd/node"
+	"github.com/lxc/lxd/lxd/project"
 	"github.com/lxc/lxd/lxd/response"
 	"github.com/lxc/lxd/lxd/util"
 	"github.com/lxc/lxd/shared"
@@ -182,9 +183,9 @@ func api10Get(d *Daemon, r *http.Request) response.Response {
 		architectures = append(architectures, architectureName)
 	}
 
-	project := r.FormValue("project")
-	if project == "" {
-		project = "default"
+	projectName := r.FormValue("project")
+	if projectName == "" {
+		projectName = project.Default
 	}
 
 	env := api.ServerEnvironment{
@@ -197,7 +198,7 @@ func api10Get(d *Daemon, r *http.Request) response.Response {
 		Kernel:                 uname.Sysname,
 		KernelArchitecture:     uname.Machine,
 		KernelVersion:          uname.Release,
-		Project:                project,
+		Project:                projectName,
 		Server:                 "lxd",
 		ServerPid:              os.Getpid(),
 		ServerVersion:          version.Version,
diff --git a/lxd/api_project.go b/lxd/api_project.go
index 66899b6072..b8a9462ca5 100644
--- a/lxd/api_project.go
+++ b/lxd/api_project.go
@@ -176,7 +176,7 @@ func projectCreateDefaultProfile(tx *db.ClusterTx, project string) error {
 	// Create a default profile
 	profile := db.Profile{}
 	profile.Project = project
-	profile.Name = "default"
+	profile.Name = projecthelpers.Default
 	profile.Description = fmt.Sprintf("Default LXD profile for project %s", project)
 
 	_, err := tx.ProfileCreate(profile)
@@ -348,7 +348,7 @@ func projectChange(d *Daemon, project *api.Project, req api.ProjectPut) response
 	}
 
 	// Sanity checks.
-	if project.Name == "default" && featuresChanged {
+	if project.Name == projecthelpers.Default && featuresChanged {
 		return response.BadRequest(fmt.Errorf("You can't change the features of the default project"))
 	}
 
@@ -382,7 +382,7 @@ func projectChange(d *Daemon, project *api.Project, req api.ProjectPut) response
 				}
 			} else {
 				// Delete the project-specific default profile.
-				err = tx.ProfileDelete(project.Name, "default")
+				err = tx.ProfileDelete(project.Name, projecthelpers.Default)
 				if err != nil {
 					return errors.Wrap(err, "Delete project default profile")
 				}
@@ -411,7 +411,7 @@ func projectPost(d *Daemon, r *http.Request) response.Response {
 	}
 
 	// Sanity checks
-	if name == "default" {
+	if name == projecthelpers.Default {
 		return response.Forbidden(fmt.Errorf("The 'default' project cannot be renamed"))
 	}
 
@@ -470,7 +470,7 @@ func projectDelete(d *Daemon, r *http.Request) response.Response {
 	name := mux.Vars(r)["name"]
 
 	// Sanity checks
-	if name == "default" {
+	if name == projecthelpers.Default {
 		return response.Forbidden(fmt.Errorf("The 'default' project cannot be deleted"))
 	}
 
diff --git a/lxd/container.go b/lxd/container.go
index b399c26fa4..0a94bb4862 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -23,6 +23,7 @@ import (
 	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/instance/instancetype"
 	"github.com/lxc/lxd/lxd/operations"
+	"github.com/lxc/lxd/lxd/project"
 	"github.com/lxc/lxd/lxd/state"
 	storagePools "github.com/lxc/lxd/lxd/storage"
 	"github.com/lxc/lxd/lxd/task"
@@ -460,7 +461,7 @@ func instanceCreateAsSnapshot(s *state.State, args db.InstanceArgs, sourceInstan
 func instanceCreateInternal(s *state.State, args db.InstanceArgs) (instance.Instance, error) {
 	// Set default values.
 	if args.Project == "" {
-		args.Project = "default"
+		args.Project = project.Default
 	}
 
 	if args.Profiles == nil {
@@ -702,7 +703,7 @@ func instanceConfigureInternal(state *state.State, c instance.Instance) error {
 
 // Legacy interface.
 func instanceLoadAll(s *state.State) ([]instance.Instance, error) {
-	return instance.LoadByProject(s, "default")
+	return instance.LoadByProject(s, project.Default)
 }
 
 // Load all instances of this nodes under the given project.
diff --git a/lxd/container_snapshot.go b/lxd/container_snapshot.go
index 313f928bd5..6652cfa951 100644
--- a/lxd/container_snapshot.go
+++ b/lxd/container_snapshot.go
@@ -15,6 +15,7 @@ import (
 	"github.com/lxc/lxd/lxd/db"
 	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/operations"
+	"github.com/lxc/lxd/lxd/project"
 	"github.com/lxc/lxd/lxd/response"
 	"github.com/lxc/lxd/lxd/state"
 	"github.com/lxc/lxd/lxd/util"
@@ -29,11 +30,11 @@ func containerSnapshotsGet(d *Daemon, r *http.Request) response.Response {
 		return response.SmartError(err)
 	}
 
-	project := projectParam(r)
+	projectName := projectParam(r)
 	cname := mux.Vars(r)["name"]
 
 	// Handle requests targeted to a container on a different node
-	resp, err := ForwardedResponseIfContainerIsRemote(d, r, project, cname, instanceType)
+	resp, err := ForwardedResponseIfContainerIsRemote(d, r, projectName, cname, instanceType)
 	if err != nil {
 		return response.SmartError(err)
 	}
@@ -46,23 +47,23 @@ func containerSnapshotsGet(d *Daemon, r *http.Request) response.Response {
 	resultMap := []*api.InstanceSnapshot{}
 
 	if !recursion {
-		snaps, err := d.cluster.ContainerGetSnapshots(project, cname)
+		snaps, err := d.cluster.ContainerGetSnapshots(projectName, cname)
 		if err != nil {
 			return response.SmartError(err)
 		}
 
 		for _, snap := range snaps {
 			_, snapName, _ := shared.InstanceGetParentAndSnapshotName(snap)
-			if project == "default" {
+			if projectName == project.Default {
 				url := fmt.Sprintf("/%s/instances/%s/snapshots/%s", version.APIVersion, cname, snapName)
 				resultString = append(resultString, url)
 			} else {
-				url := fmt.Sprintf("/%s/instances/%s/snapshots/%s?project=%s", version.APIVersion, cname, snapName, project)
+				url := fmt.Sprintf("/%s/instances/%s/snapshots/%s?project=%s", version.APIVersion, cname, snapName, projectName)
 				resultString = append(resultString, url)
 			}
 		}
 	} else {
-		c, err := instance.LoadByProjectAndName(d.State(), project, cname)
+		c, err := instance.LoadByProjectAndName(d.State(), projectName, cname)
 		if err != nil {
 			return response.SmartError(err)
 		}
diff --git a/lxd/containers.go b/lxd/containers.go
index b43f67c64c..f59acb9708 100644
--- a/lxd/containers.go
+++ b/lxd/containers.go
@@ -11,6 +11,7 @@ import (
 	"github.com/lxc/lxd/lxd/db"
 	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/instance/instancetype"
+	"github.com/lxc/lxd/lxd/project"
 	"github.com/lxc/lxd/lxd/state"
 	"github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/logger"
@@ -296,17 +297,17 @@ func containersOnDisk() (map[string][]string, error) {
 
 	for _, file := range files {
 		name := file.Name()
-		project := "default"
+		projectName := project.Default
 		if strings.Contains(name, "_") {
 			fields := strings.Split(file.Name(), "_")
-			project = fields[0]
+			projectName = fields[0]
 			name = fields[1]
 		}
-		names, ok := containers[project]
+		names, ok := containers[projectName]
 		if !ok {
 			names = []string{}
 		}
-		containers[project] = append(names, name)
+		containers[projectName] = append(names, name)
 	}
 
 	return containers, nil
diff --git a/lxd/devlxd.go b/lxd/devlxd.go
index 31333b5b09..c231cdd3b2 100644
--- a/lxd/devlxd.go
+++ b/lxd/devlxd.go
@@ -339,14 +339,14 @@ func findContainerForPid(pid int32, s *state.State) (instance.Container, error)
 			parts := strings.Split(string(cmdline), " ")
 			name := strings.TrimSuffix(parts[len(parts)-1], "\x00")
 
-			project := "default"
+			projectName := project.Default
 			if strings.Contains(name, "_") {
 				fields := strings.SplitN(name, "_", 2)
-				project = fields[0]
+				projectName = fields[0]
 				name = fields[1]
 			}
 
-			inst, err := instance.LoadByProjectAndName(s, project, name)
+			inst, err := instance.LoadByProjectAndName(s, projectName, name)
 			if err != nil {
 				return nil, err
 			}
diff --git a/lxd/images.go b/lxd/images.go
index f4da10d3b1..4f74031cf6 100644
--- a/lxd/images.go
+++ b/lxd/images.go
@@ -33,6 +33,7 @@ import (
 	"github.com/lxc/lxd/lxd/instance/instancetype"
 	"github.com/lxc/lxd/lxd/node"
 	"github.com/lxc/lxd/lxd/operations"
+	"github.com/lxc/lxd/lxd/project"
 	"github.com/lxc/lxd/lxd/response"
 	"github.com/lxc/lxd/lxd/state"
 	storagePools "github.com/lxc/lxd/lxd/storage"
@@ -1352,7 +1353,7 @@ func pruneExpiredImages(ctx context.Context, d *Daemon) error {
 			}
 		}
 
-		imgID, _, err := d.cluster.ImageGet("default", fp, false, false)
+		imgID, _, err := d.cluster.ImageGet(project.Default, fp, false, false)
 		if err != nil {
 			return errors.Wrapf(err, "Error retrieving image info %s", fp)
 		}
diff --git a/lxd/instance/drivers/driver_lxc.go b/lxd/instance/drivers/driver_lxc.go
index 79a5aacb27..4e36e62836 100644
--- a/lxd/instance/drivers/driver_lxc.go
+++ b/lxd/instance/drivers/driver_lxc.go
@@ -3719,7 +3719,7 @@ func (c *lxc) VolatileSet(changes map[string]string) error {
 func (c *lxc) Update(args db.InstanceArgs, userRequested bool) error {
 	// Set sane defaults for unset keys
 	if args.Project == "" {
-		args.Project = "default"
+		args.Project = project.Default
 	}
 
 	if args.Architecture == 0 {
diff --git a/lxd/instance/drivers/driver_qemu.go b/lxd/instance/drivers/driver_qemu.go
index 8863e3fb78..3c83c55619 100644
--- a/lxd/instance/drivers/driver_qemu.go
+++ b/lxd/instance/drivers/driver_qemu.go
@@ -2288,7 +2288,7 @@ func (vm *qemu) Update(args db.InstanceArgs, userRequested bool) error {
 
 	// Set sane defaults for unset keys.
 	if args.Project == "" {
-		args.Project = "default"
+		args.Project = project.Default
 	}
 
 	if args.Architecture == 0 {
diff --git a/lxd/networks.go b/lxd/networks.go
index 44063b1a5f..57a5e71d1c 100644
--- a/lxd/networks.go
+++ b/lxd/networks.go
@@ -19,6 +19,7 @@ import (
 	"github.com/lxc/lxd/lxd/db"
 	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/network"
+	"github.com/lxc/lxd/lxd/project"
 	"github.com/lxc/lxd/lxd/response"
 	"github.com/lxc/lxd/lxd/state"
 	"github.com/lxc/lxd/lxd/util"
@@ -414,7 +415,7 @@ func doNetworkGet(d *Daemon, name string) (api.Network, error) {
 		for _, inst := range insts {
 			if network.IsInUse(inst, n.Name) {
 				uri := fmt.Sprintf("/%s/instances/%s", version.APIVersion, inst.Name())
-				if inst.Project() != "default" {
+				if inst.Project() != project.Default {
 					uri += fmt.Sprintf("?project=%s", inst.Project())
 				}
 				n.UsedBy = append(n.UsedBy, uri)
diff --git a/lxd/operations.go b/lxd/operations.go
index 4bc0ba22b3..423e466b2c 100644
--- a/lxd/operations.go
+++ b/lxd/operations.go
@@ -12,6 +12,7 @@ import (
 	"github.com/lxc/lxd/lxd/db"
 	"github.com/lxc/lxd/lxd/node"
 	"github.com/lxc/lxd/lxd/operations"
+	"github.com/lxc/lxd/lxd/project"
 	"github.com/lxc/lxd/lxd/response"
 	"github.com/lxc/lxd/lxd/util"
 	"github.com/lxc/lxd/shared"
@@ -91,12 +92,12 @@ func operationDelete(d *Daemon, r *http.Request) response.Response {
 	op, err := operations.OperationGetInternal(id)
 	if err == nil {
 		if op.Permission() != "" {
-			project := op.Project()
-			if project == "" {
-				project = "default"
+			projectName := op.Project()
+			if projectName == "" {
+				projectName = project.Default
 			}
 
-			if !d.userHasPermission(r, project, op.Permission()) {
+			if !d.userHasPermission(r, projectName, op.Permission()) {
 				return response.Forbidden(nil)
 			}
 		}
diff --git a/lxd/profiles.go b/lxd/profiles.go
index 590a8df759..9647f8cb38 100644
--- a/lxd/profiles.go
+++ b/lxd/profiles.go
@@ -17,6 +17,7 @@ import (
 	deviceConfig "github.com/lxc/lxd/lxd/device/config"
 	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/instance/instancetype"
+	"github.com/lxc/lxd/lxd/project"
 	"github.com/lxc/lxd/lxd/response"
 	"github.com/lxc/lxd/lxd/util"
 	"github.com/lxc/lxd/shared"
@@ -43,23 +44,23 @@ var profileCmd = APIEndpoint{
 
 /* This is used for both profiles post and profile put */
 func profilesGet(d *Daemon, r *http.Request) response.Response {
-	project := projectParam(r)
+	projectName := projectParam(r)
 
 	recursion := util.IsRecursionRequest(r)
 
 	var result interface{}
 	err := d.cluster.Transaction(func(tx *db.ClusterTx) error {
-		hasProfiles, err := tx.ProjectHasProfiles(project)
+		hasProfiles, err := tx.ProjectHasProfiles(projectName)
 		if err != nil {
 			return errors.Wrap(err, "Check project features")
 		}
 
 		if !hasProfiles {
-			project = "default"
+			projectName = project.Default
 		}
 
 		filter := db.ProfileFilter{
-			Project: project,
+			Project: projectName,
 		}
 		if recursion {
 			profiles, err := tx.ProfileList(filter)
@@ -85,7 +86,7 @@ func profilesGet(d *Daemon, r *http.Request) response.Response {
 }
 
 func profilesPost(d *Daemon, r *http.Request) response.Response {
-	project := projectParam(r)
+	projectName := projectParam(r)
 	req := api.ProfilesPost{}
 	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
 		return response.BadRequest(err)
@@ -117,22 +118,22 @@ func profilesPost(d *Daemon, r *http.Request) response.Response {
 
 	// Update DB entry
 	err = d.cluster.Transaction(func(tx *db.ClusterTx) error {
-		hasProfiles, err := tx.ProjectHasProfiles(project)
+		hasProfiles, err := tx.ProjectHasProfiles(projectName)
 		if err != nil {
 			return errors.Wrap(err, "Check project features")
 		}
 
 		if !hasProfiles {
-			project = "default"
+			projectName = project.Default
 		}
 
-		current, _ := tx.ProfileGet(project, req.Name)
+		current, _ := tx.ProfileGet(projectName, req.Name)
 		if current != nil {
 			return fmt.Errorf("The profile already exists")
 		}
 
 		profile := db.Profile{
-			Project:     project,
+			Project:     projectName,
 			Name:        req.Name,
 			Description: req.Description,
 			Config:      req.Config,
@@ -150,22 +151,22 @@ func profilesPost(d *Daemon, r *http.Request) response.Response {
 }
 
 func profileGet(d *Daemon, r *http.Request) response.Response {
-	project := projectParam(r)
+	projectName := projectParam(r)
 	name := mux.Vars(r)["name"]
 
 	var resp *api.Profile
 
 	err := d.cluster.Transaction(func(tx *db.ClusterTx) error {
-		hasProfiles, err := tx.ProjectHasProfiles(project)
+		hasProfiles, err := tx.ProjectHasProfiles(projectName)
 		if err != nil {
 			return errors.Wrap(err, "Check project features")
 		}
 
 		if !hasProfiles {
-			project = "default"
+			projectName = project.Default
 		}
 
-		profile, err := tx.ProfileGet(project, name)
+		profile, err := tx.ProfileGet(projectName, name)
 		if err != nil {
 			return errors.Wrap(err, "Fetch profile")
 		}
@@ -193,7 +194,7 @@ func profileGet(d *Daemon, r *http.Request) response.Response {
 
 func profilePut(d *Daemon, r *http.Request) response.Response {
 	// Get the project
-	project := projectParam(r)
+	projectName := projectParam(r)
 
 	// Get the profile
 	name := mux.Vars(r)["name"]
@@ -208,7 +209,7 @@ func profilePut(d *Daemon, r *http.Request) response.Response {
 			return response.BadRequest(err)
 		}
 
-		err = doProfileUpdateCluster(d, project, name, old)
+		err = doProfileUpdateCluster(d, projectName, name, old)
 		return response.SmartError(err)
 	}
 
@@ -216,16 +217,16 @@ func profilePut(d *Daemon, r *http.Request) response.Response {
 	var profile *api.Profile
 
 	err := d.cluster.Transaction(func(tx *db.ClusterTx) error {
-		hasProfiles, err := tx.ProjectHasProfiles(project)
+		hasProfiles, err := tx.ProjectHasProfiles(projectName)
 		if err != nil {
 			return errors.Wrap(err, "Check project features")
 		}
 
 		if !hasProfiles {
-			project = "default"
+			projectName = project.Default
 		}
 
-		current, err := tx.ProfileGet(project, name)
+		current, err := tx.ProfileGet(projectName, name)
 		if err != nil {
 			return errors.Wrapf(err, "Failed to retrieve profile='%s'", name)
 		}
@@ -251,7 +252,7 @@ func profilePut(d *Daemon, r *http.Request) response.Response {
 		return response.BadRequest(err)
 	}
 
-	err = doProfileUpdate(d, project, name, id, profile, req)
+	err = doProfileUpdate(d, projectName, name, id, profile, req)
 
 	if err == nil && !isClusterNotification(r) {
 		// Notify all other nodes. If a node is down, it will be ignored.
@@ -261,7 +262,7 @@ func profilePut(d *Daemon, r *http.Request) response.Response {
 		}
 
 		err = notifier(func(client lxd.InstanceServer) error {
-			return client.UseProject(project).UpdateProfile(name, profile.ProfilePut, "")
+			return client.UseProject(projectName).UpdateProfile(name, profile.ProfilePut, "")
 		})
 		if err != nil {
 			return response.SmartError(err)
@@ -273,7 +274,7 @@ func profilePut(d *Daemon, r *http.Request) response.Response {
 
 func profilePatch(d *Daemon, r *http.Request) response.Response {
 	// Get the project
-	project := projectParam(r)
+	projectName := projectParam(r)
 
 	// Get the profile
 	name := mux.Vars(r)["name"]
@@ -282,16 +283,16 @@ func profilePatch(d *Daemon, r *http.Request) response.Response {
 	var profile *api.Profile
 
 	err := d.cluster.Transaction(func(tx *db.ClusterTx) error {
-		hasProfiles, err := tx.ProjectHasProfiles(project)
+		hasProfiles, err := tx.ProjectHasProfiles(projectName)
 		if err != nil {
 			return errors.Wrap(err, "Check project features")
 		}
 
 		if !hasProfiles {
-			project = "default"
+			projectName = project.Default
 		}
 
-		current, err := tx.ProfileGet(project, name)
+		current, err := tx.ProfileGet(projectName, name)
 		if err != nil {
 			return errors.Wrapf(err, "Failed to retrieve profile='%s'", name)
 		}
@@ -360,12 +361,12 @@ func profilePatch(d *Daemon, r *http.Request) response.Response {
 		}
 	}
 
-	return response.SmartError(doProfileUpdate(d, project, name, id, profile, req))
+	return response.SmartError(doProfileUpdate(d, projectName, name, id, profile, req))
 }
 
 // The handler for the post operation.
 func profilePost(d *Daemon, r *http.Request) response.Response {
-	project := projectParam(r)
+	projectName := projectParam(r)
 	name := mux.Vars(r)["name"]
 
 	if name == "default" {
@@ -391,22 +392,22 @@ func profilePost(d *Daemon, r *http.Request) response.Response {
 	}
 
 	err := d.cluster.Transaction(func(tx *db.ClusterTx) error {
-		hasProfiles, err := tx.ProjectHasProfiles(project)
+		hasProfiles, err := tx.ProjectHasProfiles(projectName)
 		if err != nil {
 			return errors.Wrap(err, "Check project features")
 		}
 
 		if !hasProfiles {
-			project = "default"
+			projectName = project.Default
 		}
 
 		// Check that the name isn't already in use
-		_, err = tx.ProfileGet(project, req.Name)
+		_, err = tx.ProfileGet(projectName, req.Name)
 		if err == nil {
 			return fmt.Errorf("Name '%s' already in use", req.Name)
 		}
 
-		return tx.ProfileRename(project, name, req.Name)
+		return tx.ProfileRename(projectName, name, req.Name)
 	})
 	if err != nil {
 		return response.SmartError(err)
@@ -417,7 +418,7 @@ func profilePost(d *Daemon, r *http.Request) response.Response {
 
 // The handler for the delete operation.
 func profileDelete(d *Daemon, r *http.Request) response.Response {
-	project := projectParam(r)
+	projectName := projectParam(r)
 	name := mux.Vars(r)["name"]
 
 	if name == "default" {
@@ -425,16 +426,16 @@ func profileDelete(d *Daemon, r *http.Request) response.Response {
 	}
 
 	err := d.cluster.Transaction(func(tx *db.ClusterTx) error {
-		hasProfiles, err := tx.ProjectHasProfiles(project)
+		hasProfiles, err := tx.ProjectHasProfiles(projectName)
 		if err != nil {
 			return errors.Wrap(err, "Check project features")
 		}
 
 		if !hasProfiles {
-			project = "default"
+			projectName = project.Default
 		}
 
-		profile, err := tx.ProfileGet(project, name)
+		profile, err := tx.ProfileGet(projectName, name)
 		if err != nil {
 			return err
 		}
@@ -442,7 +443,7 @@ func profileDelete(d *Daemon, r *http.Request) response.Response {
 			return fmt.Errorf("Profile is currently in use")
 		}
 
-		return tx.ProfileDelete(project, name)
+		return tx.ProfileDelete(projectName, name)
 	})
 	if err != nil {
 		return response.SmartError(err)
diff --git a/lxd/profiles_utils.go b/lxd/profiles_utils.go
index bef9d19324..dd43fd814e 100644
--- a/lxd/profiles_utils.go
+++ b/lxd/profiles_utils.go
@@ -56,7 +56,7 @@ func doProfileUpdate(d *Daemon, project, name string, id int64, profile *api.Pro
 			// Check what profile the device comes from
 			profiles := container.Profiles
 			for i := len(profiles) - 1; i >= 0; i-- {
-				_, profile, err := d.cluster.ProfileGet("default", profiles[i])
+				_, profile, err := d.cluster.ProfileGet(projecthelpers.Default, profiles[i])
 				if err != nil {
 					return err
 				}
diff --git a/lxd/storage_volumes_utils.go b/lxd/storage_volumes_utils.go
index f478a519e9..dc42b40b1e 100644
--- a/lxd/storage_volumes_utils.go
+++ b/lxd/storage_volumes_utils.go
@@ -5,6 +5,7 @@ import (
 	"path/filepath"
 
 	"github.com/lxc/lxd/lxd/db"
+	"github.com/lxc/lxd/lxd/project"
 	"github.com/lxc/lxd/lxd/state"
 	storagePools "github.com/lxc/lxd/lxd/storage"
 	"github.com/lxc/lxd/shared"
@@ -136,13 +137,13 @@ func storagePoolVolumeUpdateUsers(d *Daemon, oldPoolName string,
 	}
 
 	// update all profiles
-	profiles, err := s.Cluster.Profiles("default")
+	profiles, err := s.Cluster.Profiles(project.Default)
 	if err != nil {
 		return err
 	}
 
 	for _, pName := range profiles {
-		id, profile, err := s.Cluster.ProfileGet("default", pName)
+		id, profile, err := s.Cluster.ProfileGet(project.Default, pName)
 		if err != nil {
 			return err
 		}
@@ -197,7 +198,7 @@ func storagePoolVolumeUpdateUsers(d *Daemon, oldPoolName string,
 		pUpdate.Config = profile.Config
 		pUpdate.Description = profile.Description
 		pUpdate.Devices = profile.Devices
-		err = doProfileUpdate(d, "default", pName, id, profile, pUpdate)
+		err = doProfileUpdate(d, project.Default, pName, id, profile, pUpdate)
 		if err != nil {
 			return err
 		}
@@ -301,13 +302,13 @@ func storagePoolVolumeUsedByGet(s *state.State, project, poolName string, volume
 func profilesUsingPoolVolumeGetNames(db *db.Cluster, volumeName string, volumeType string) ([]string, error) {
 	usedBy := []string{}
 
-	profiles, err := db.Profiles("default")
+	profiles, err := db.Profiles(project.Default)
 	if err != nil {
 		return usedBy, err
 	}
 
 	for _, pName := range profiles {
-		_, profile, err := db.ProfileGet("default", pName)
+		_, profile, err := db.ProfileGet(project.Default, pName)
 		if err != nil {
 			return usedBy, err
 		}

From 9a52d42c1eef6449b728e7c386c8670bceaef89a Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 5 Mar 2020 08:26:35 +0000
Subject: [PATCH 30/40] lxd/daemon/storage: Adds support for custom volume
 projects

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/daemon_storage.go | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/lxd/daemon_storage.go b/lxd/daemon_storage.go
index 9a59cd4bc1..8c69cd3bd3 100644
--- a/lxd/daemon_storage.go
+++ b/lxd/daemon_storage.go
@@ -15,6 +15,7 @@ import (
 	"github.com/lxc/lxd/lxd/rsync"
 	"github.com/lxc/lxd/lxd/state"
 	storagePools "github.com/lxc/lxd/lxd/storage"
+	storageDrivers "github.com/lxc/lxd/lxd/storage/drivers"
 	"github.com/lxc/lxd/shared"
 )
 
@@ -158,7 +159,8 @@ func daemonStorageValidate(s *state.State, target string) error {
 	}
 
 	// Validate volume is empty (ignore lost+found).
-	mountpoint := shared.VarPath("storage-pools", poolName, "custom", volumeName)
+	volStorageName := project.StorageVolume(project.Default, volumeName)
+	mountpoint := storageDrivers.GetVolumeMountPath(poolName, storageDrivers.VolumeTypeCustom, volStorageName)
 
 	entries, err := ioutil.ReadDir(mountpoint)
 	if err != nil {
@@ -248,9 +250,10 @@ func daemonStorageMove(s *state.State, storageType string, target string) error
 		}
 
 		// Unmount old volume.
-		_, err = pool.UnmountCustomVolume(project.Default, sourceVolume, nil)
+		projectName, sourceVolumeName := project.StorageVolumeParts(sourceVolume)
+		_, err = pool.UnmountCustomVolume(projectName, sourceVolumeName, nil)
 		if err != nil {
-			return errors.Wrapf(err, `Failed to umount storage volume "%s/%s"`, sourcePool, sourceVolume)
+			return errors.Wrapf(err, `Failed to umount storage volume "%s/%s"`, sourcePool, sourceVolumeName)
 		}
 
 		return nil
@@ -277,7 +280,8 @@ func daemonStorageMove(s *state.State, storageType string, target string) error
 	}
 
 	// Set ownership & mode.
-	mountpoint := shared.VarPath("storage-pools", poolName, "custom", volumeName)
+	volStorageName := project.StorageVolume(project.Default, volumeName)
+	mountpoint := storageDrivers.GetVolumeMountPath(poolName, storageDrivers.VolumeTypeCustom, volStorageName)
 	destPath = mountpoint
 
 	err = os.Chmod(mountpoint, 0700)

From 3116895be706bea2a3de02104663ea060207602e Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 5 Mar 2020 08:27:26 +0000
Subject: [PATCH 31/40] lxd/db/storage/pools: Comment and error msg tweaks

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/db/storage_pools.go | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/lxd/db/storage_pools.go b/lxd/db/storage_pools.go
index 49e26c0739..b7193bce59 100644
--- a/lxd/db/storage_pools.go
+++ b/lxd/db/storage_pools.go
@@ -767,18 +767,18 @@ func (c *Cluster) StoragePoolNodeVolumesGet(project string, poolID int64, volume
 // Returns all storage volumes attached to a given storage pool on the given
 // node.
 func (c *Cluster) storagePoolVolumesGet(project string, poolID, nodeID int64, volumeTypes []int) ([]*api.StorageVolume, error) {
-	// Get all storage volumes of all types attached to a given storage
-	// pool.
+	// Get all storage volumes of all types attached to a given storage pool.
 	result := []*api.StorageVolume{}
 	for _, volumeType := range volumeTypes {
 		volumeNames, err := c.storagePoolVolumesGetType(project, volumeType, poolID, nodeID)
 		if err != nil && err != sql.ErrNoRows {
-			return nil, errors.Wrap(err, "failed to fetch volume types")
+			return nil, errors.Wrap(err, "Failed to fetch volume types")
 		}
+
 		for _, volumeName := range volumeNames {
 			_, volume, err := c.storagePoolVolumeGetType(project, volumeName, volumeType, poolID, nodeID)
 			if err != nil {
-				return nil, errors.Wrap(err, "failed to fetch volume type")
+				return nil, errors.Wrap(err, "Failed to fetch volume type")
 			}
 			result = append(result, volume)
 		}
@@ -1211,7 +1211,7 @@ func storagePoolVolumeTypeToName(volumeType int) (string, error) {
 		return StoragePoolVolumeTypeNameCustom, nil
 	}
 
-	return "", fmt.Errorf("invalid storage volume type")
+	return "", fmt.Errorf("Invalid storage volume type")
 }
 
 // StoragePoolInsertZfsDriver replaces the driver of all storage pools without

From 276001aae3e58ea80197bee2dc7826fc17d5d97c Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 5 Mar 2020 08:27:56 +0000
Subject: [PATCH 32/40] lxd/db/storage/pools: Removes incorrect filter for
 project default when vol type is StoragePoolVolumeTypeCustom

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/db/storage_pools.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lxd/db/storage_pools.go b/lxd/db/storage_pools.go
index b7193bce59..a375383270 100644
--- a/lxd/db/storage_pools.go
+++ b/lxd/db/storage_pools.go
@@ -799,12 +799,12 @@ func (c *Cluster) storagePoolVolumesGetType(project string, volumeType int, pool
 SELECT storage_volumes_all.name
   FROM storage_volumes_all
   JOIN projects ON projects.id=storage_volumes_all.project_id
- WHERE (projects.name=? OR storage_volumes_all.type=?)
+ WHERE projects.name=?
    AND storage_volumes_all.storage_pool_id=?
    AND storage_volumes_all.node_id=?
    AND storage_volumes_all.type=?
 `
-	inargs := []interface{}{project, StoragePoolVolumeTypeCustom, poolID, nodeID, volumeType}
+	inargs := []interface{}{project, poolID, nodeID, volumeType}
 	outargs := []interface{}{poolName}
 
 	result, err := queryScan(c.db, query, inargs, outargs)

From aab7ba07cd5326407379587e3e97840d8e277b1e Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 5 Mar 2020 08:29:03 +0000
Subject: [PATCH 33/40] lxd/images: Comment weaks

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/images.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lxd/images.go b/lxd/images.go
index 4f74031cf6..75f97d7edc 100644
--- a/lxd/images.go
+++ b/lxd/images.go
@@ -1579,7 +1579,7 @@ func imagePut(d *Daemon, r *http.Request) response.Response {
 		info.ExpiresAt = req.ExpiresAt
 	}
 
-	// Get profile ids
+	// Get profile IDs
 	if req.Profiles == nil {
 		req.Profiles = []string{"default"}
 	}

From a6623a7f55c288be992711d9267c99ba25199bb8 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 5 Mar 2020 08:29:32 +0000
Subject: [PATCH 34/40] lxd/images: golint fixes

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/images.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lxd/images.go b/lxd/images.go
index 75f97d7edc..c05c7d6582 100644
--- a/lxd/images.go
+++ b/lxd/images.go
@@ -1585,13 +1585,13 @@ func imagePut(d *Daemon, r *http.Request) response.Response {
 	}
 	profileIds := make([]int64, len(req.Profiles))
 	for i, profile := range req.Profiles {
-		profileId, _, err := d.cluster.ProfileGet(project, profile)
+		profileID, _, err := d.cluster.ProfileGet(project, profile)
 		if err == db.ErrNoSuchObject {
 			return response.BadRequest(fmt.Errorf("Profile '%s' doesn't exist", profile))
 		} else if err != nil {
 			return response.SmartError(err)
 		}
-		profileIds[i] = profileId
+		profileIds[i] = profileID
 	}
 
 	err = d.cluster.ImageUpdate(id, info.Filename, info.Size, req.Public, req.AutoUpdate, info.Architecture, info.CreatedAt, info.ExpiresAt, req.Properties, project, profileIds)

From 55325ee60fe7d428a600134503ca27c7919ee398 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 5 Mar 2020 08:31:47 +0000
Subject: [PATCH 35/40] lxd/project/limits: Default const usage

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/project/limits.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lxd/project/limits.go b/lxd/project/limits.go
index f2df2467c6..15c72d06d1 100644
--- a/lxd/project/limits.go
+++ b/lxd/project/limits.go
@@ -292,10 +292,10 @@ func fetchProject(tx *db.ClusterTx, projectName string, skipIfNoLimits bool) (*a
 	// If the project has the profiles feature enabled, we use its own
 	// profiles to expand the instances configs, otherwise we use the
 	// profiles from the default project.
-	if projectName == "default" || project.Config["features.profiles"] == "true" {
+	if projectName == Default || project.Config["features.profiles"] == "true" {
 		profilesFilter.Project = projectName
 	} else {
-		profilesFilter.Project = "default"
+		profilesFilter.Project = Default
 	}
 
 	profiles, err := tx.ProfileList(profilesFilter)

From ecb2b3adfca95a56427e502f460020b4250f4a34 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 5 Mar 2020 08:32:03 +0000
Subject: [PATCH 36/40] lxd/project/project: Adds StorageVolumeParts function

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/project/project.go | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/lxd/project/project.go b/lxd/project/project.go
index 3a03966fd4..ef93d32808 100644
--- a/lxd/project/project.go
+++ b/lxd/project/project.go
@@ -47,6 +47,13 @@ func StorageVolume(projectName, storageVolumeName string) string {
 	return fmt.Sprintf("%s%s%s", projectName, separator, storageVolumeName)
 }
 
+// StorageVolumeParts takes a project prefixed storage volume name and returns the project and storage volume
+// name as separate variables.
+func StorageVolumeParts(projectStorageVolumeName string) (string, string) {
+	parts := strings.SplitN(projectStorageVolumeName, "_", 2)
+	return parts[0], parts[1]
+}
+
 // StorageVolumeProject returns the project name to use to for the volume.
 // If the project specified has the "features.storage.volumes" flag enabled then the project name is returned,
 // otherwise the default project name is returned.

From d624c8a7d03167c419170abeee0179ce69f6441c Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 5 Mar 2020 08:32:50 +0000
Subject: [PATCH 37/40] lxd/storage/load: Adds support for custom vol projects
 to volIDFuncMake

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/load.go | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/lxd/storage/load.go b/lxd/storage/load.go
index 9c28dcd87d..5c3c0c1d31 100644
--- a/lxd/storage/load.go
+++ b/lxd/storage/load.go
@@ -33,11 +33,13 @@ func volIDFuncMake(state *state.State, poolID int64) func(volType drivers.Volume
 		// the project is default.
 		projectName := project.Default
 
-		// Currently only Containers and VMs support project level volumes.
+		// Currently only Containers, VMs and custom volumes support project level volumes.
 		// This means that other volume types may have underscores in their names that don't
 		// indicate the project name.
 		if volType == drivers.VolumeTypeContainer || volType == drivers.VolumeTypeVM {
 			projectName, volName = project.InstanceParts(volName)
+		} else if volType == drivers.VolumeTypeCustom {
+			projectName, volName = project.StorageVolumeParts(volName)
 		}
 
 		volID, _, err := state.Cluster.StoragePoolNodeVolumeGetTypeByProject(projectName, volName, volTypeID, poolID)

From 5ae1d580363ba45a8aa22a792eb0471cac2e657e Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 5 Mar 2020 08:33:08 +0000
Subject: [PATCH 38/40] lxd/storage/load: Error msg quoting tweaks

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/load.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lxd/storage/load.go b/lxd/storage/load.go
index 5c3c0c1d31..c8d5ed83dd 100644
--- a/lxd/storage/load.go
+++ b/lxd/storage/load.go
@@ -45,7 +45,7 @@ func volIDFuncMake(state *state.State, poolID int64) func(volType drivers.Volume
 		volID, _, err := state.Cluster.StoragePoolNodeVolumeGetTypeByProject(projectName, volName, volTypeID, poolID)
 		if err != nil {
 			if err == db.ErrNoSuchObject {
-				return -1, fmt.Errorf("Failed to get volume ID for project '%s', volume '%s', type '%s': Volume doesn't exist", projectName, volName, volType)
+				return -1, fmt.Errorf("Failed to get volume ID for project %q, volume %q, type %q: Volume doesn't exist", projectName, volName, volType)
 			}
 
 			return -1, err

From b956a5ee6829d1d67d4ff34a083edaa642f591af Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 5 Mar 2020 10:22:07 +0000
Subject: [PATCH 39/40] lxd/storage/volume/utils: Error msg tweaks

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage_volumes_utils.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lxd/storage_volumes_utils.go b/lxd/storage_volumes_utils.go
index dc42b40b1e..c67e8bec32 100644
--- a/lxd/storage_volumes_utils.go
+++ b/lxd/storage_volumes_utils.go
@@ -42,7 +42,7 @@ func storagePoolVolumeTypeNameToAPIEndpoint(volumeTypeName string) (string, erro
 		return storagePoolVolumeAPIEndpointCustom, nil
 	}
 
-	return "", fmt.Errorf("invalid storage volume type name")
+	return "", fmt.Errorf("Invalid storage volume type name")
 }
 
 func storagePoolVolumeTypeToAPIEndpoint(volumeType int) (string, error) {
@@ -57,7 +57,7 @@ func storagePoolVolumeTypeToAPIEndpoint(volumeType int) (string, error) {
 		return storagePoolVolumeAPIEndpointCustom, nil
 	}
 
-	return "", fmt.Errorf("invalid storage volume type")
+	return "", fmt.Errorf("Invalid storage volume type")
 }
 
 func storagePoolVolumeUpdateUsers(d *Daemon, oldPoolName string,

From 173d32191b498053682c8b6c8df2622816d6fb0d Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 5 Mar 2020 10:22:38 +0000
Subject: [PATCH 40/40] test: Updates tests for custom storage volume projects

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 test/suites/projects.sh              | 18 +++++++++++++++++-
 test/suites/storage_volume_attach.sh |  2 +-
 2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/test/suites/projects.sh b/test/suites/projects.sh
index c8060f2d9a..4492757a74 100644
--- a/test/suites/projects.sh
+++ b/test/suites/projects.sh
@@ -428,7 +428,7 @@ test_projects_storage() {
 
   lxc storage volume create "${pool}" vol
 
-  lxc project create foo
+  lxc project create foo -c features.storage.volumes=false
   lxc project switch foo
 
   lxc storage volume list "${pool}" | grep custom | grep -q vol
@@ -439,6 +439,22 @@ test_projects_storage() {
 
   ! lxc storage volume list "${pool}" | grep custom | grep -q vol || false
 
+  lxc project set foo features.storage.volumes=true
+  lxc storage volume create "${pool}" vol
+  lxc project switch foo
+  ! lxc storage volume list "${pool}" | grep custom | grep -q vol
+
+  lxc storage volume create "${pool}" vol
+  lxc storage volume delete "${pool}" vol
+
+  lxc storage volume create "${pool}" vol2
+  lxc project switch default
+  ! lxc storage volume list "${pool}" | grep custom | grep -q vol2
+
+  lxc project switch foo
+  lxc storage volume delete "${pool}" vol2
+
+  lxc project switch default
   lxc project delete foo
 }
 
diff --git a/test/suites/storage_volume_attach.sh b/test/suites/storage_volume_attach.sh
index 3a737deb80..80b732a54a 100644
--- a/test/suites/storage_volume_attach.sh
+++ b/test/suites/storage_volume_attach.sh
@@ -47,7 +47,7 @@ test_storage_volume_attach() {
 
   # Attach to a single privileged container
   lxc storage volume attach "lxdtest-$(basename "${LXD_DIR}")" testvolume c1 testvolume
-  PATH_TO_CHECK="${LXD_DIR}/storage-pools/lxdtest-$(basename "${LXD_DIR}")/custom/testvolume"
+  PATH_TO_CHECK="${LXD_DIR}/storage-pools/lxdtest-$(basename "${LXD_DIR}")/custom/default_testvolume"
   [ "$(stat -c %u:%g "${PATH_TO_CHECK}")" = "0:0" ]
 
   # make container unprivileged


More information about the lxc-devel mailing list