[lxc-devel] [lxd/master] UsedBy consistency

stgraber on Github lxc-bot at linuxcontainers.org
Thu Jun 18 23:36:01 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200618/aae2f260/attachment-0001.bin>
-------------- next part --------------
From 7b91d36fa35fa67a167d07842a9771d31687dc07 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 18 Jun 2020 17:10:14 -0400
Subject: [PATCH 1/6] lxd/storage-pools: Tweak UsedBy URLs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/db/storage_pools.go | 21 ++++++---------------
 1 file changed, 6 insertions(+), 15 deletions(-)

diff --git a/lxd/db/storage_pools.go b/lxd/db/storage_pools.go
index 72d436d6f8..294cb6e751 100644
--- a/lxd/db/storage_pools.go
+++ b/lxd/db/storage_pools.go
@@ -88,16 +88,16 @@ func (c *ClusterTx) GetStoragePoolUsedBy(name string) ([]string, error) {
 	}
 
 	for _, r := range vols {
-		// Handle the containers.
-		if r.volType == StoragePoolVolumeTypeContainer {
+		// Handle instances.
+		if r.volType == StoragePoolVolumeTypeContainer || r.volType == StoragePoolVolumeTypeVM {
 			if r.projectName == "default" {
-				usedby = append(usedby, fmt.Sprintf("/1.0/container/%s", r.volName))
+				usedby = append(usedby, fmt.Sprintf("/1.0/instances/%s", r.volName))
 			} else {
-				usedby = append(usedby, fmt.Sprintf("/1.0/container/%s?project=%s", r.volName, r.projectName))
+				usedby = append(usedby, fmt.Sprintf("/1.0/instances/%s?project=%s", r.volName, r.projectName))
 			}
 		}
 
-		// Handle the images.
+		// Handle images.
 		if r.volType == StoragePoolVolumeTypeImage {
 			// Get the projects using an image.
 			stmt := "SELECT projects.name FROM images LEFT JOIN projects ON projects.id=images.project_id WHERE fingerprint=?"
@@ -115,7 +115,7 @@ func (c *ClusterTx) GetStoragePoolUsedBy(name string) ([]string, error) {
 			}
 		}
 
-		// Handle the custom volumes.
+		// Handle custom storage volumes.
 		if r.volType == StoragePoolVolumeTypeCustom {
 			if len(nodes) > 1 {
 				if r.projectName == "default" {
@@ -131,15 +131,6 @@ func (c *ClusterTx) GetStoragePoolUsedBy(name string) ([]string, error) {
 				}
 			}
 		}
-
-		// Handle the virtual machines.
-		if r.volType == StoragePoolVolumeTypeVM {
-			if r.projectName == "default" {
-				usedby = append(usedby, fmt.Sprintf("/1.0/virtual-machine/%s", r.volName))
-			} else {
-				usedby = append(usedby, fmt.Sprintf("/1.0/virtual-machine/%s?project=%s", r.volName, r.projectName))
-			}
-		}
 	}
 
 	// Get all the profiles using the storage pool.

From bbb08bc183f4ba5b31dfde30837a403a2e1d492a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 18 Jun 2020 18:09:32 -0400
Subject: [PATCH 2/6] lxd/networks: Reports profiles in UsedBy
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/network/network.go       |  2 +-
 lxd/network/network_utils.go | 17 ++++++++++++++---
 lxd/networks.go              | 27 ++++++++++++++++++++++++++-
 3 files changed, 41 insertions(+), 5 deletions(-)

diff --git a/lxd/network/network.go b/lxd/network/network.go
index 2c5d9abad3..6e2fcd3dd6 100644
--- a/lxd/network/network.go
+++ b/lxd/network/network.go
@@ -80,7 +80,7 @@ func (n *Network) IsUsed() bool {
 	}
 
 	for _, inst := range insts {
-		if IsInUse(inst, n.name) {
+		if IsInUseByInstance(inst, n.name) {
 			return true
 		}
 	}
diff --git a/lxd/network/network_utils.go b/lxd/network/network_utils.go
index 14fe9230df..668764fe87 100644
--- a/lxd/network/network_utils.go
+++ b/lxd/network/network_utils.go
@@ -18,6 +18,7 @@ import (
 
 	"github.com/pkg/errors"
 
+	deviceConfig "github.com/lxc/lxd/lxd/device/config"
 	"github.com/lxc/lxd/lxd/dnsmasq"
 	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/instance/instancetype"
@@ -28,10 +29,20 @@ import (
 	"github.com/lxc/lxd/shared/logger"
 )
 
-// IsInUse indicates if network is reference by any instance's NIC devices.
+// IsInUseByInstance indicates if network is referenced by an instance's NIC devices.
 // Checks if the device's parent or network properties match the network name.
-func IsInUse(c instance.Instance, networkName string) bool {
-	for _, d := range c.ExpandedDevices() {
+func IsInUseByInstance(c instance.Instance, networkName string) bool {
+	return isInUseByDevices(c.ExpandedDevices(), networkName)
+}
+
+// IsInUseByProfile indicates if network is referenced by a profile's NIC devices.
+// Checks if the device's parent or network properties match the network name.
+func IsInUseByProfile(profile api.Profile, networkName string) bool {
+	return isInUseByDevices(deviceConfig.NewDevices(profile.Devices), networkName)
+}
+
+func isInUseByDevices(devices deviceConfig.Devices, networkName string) bool {
+	for _, d := range devices {
 		if d["type"] != "nic" {
 			continue
 		}
diff --git a/lxd/networks.go b/lxd/networks.go
index 20ca524815..73d40bc168 100644
--- a/lxd/networks.go
+++ b/lxd/networks.go
@@ -402,13 +402,14 @@ func doNetworkGet(d *Daemon, name string) (api.Network, error) {
 
 	// Look for containers using the interface
 	if n.Type != "loopback" {
+		// Look at instances.
 		insts, err := instance.LoadFromAllProjects(d.State())
 		if err != nil {
 			return api.Network{}, err
 		}
 
 		for _, inst := range insts {
-			if network.IsInUse(inst, n.Name) {
+			if network.IsInUseByInstance(inst, n.Name) {
 				uri := fmt.Sprintf("/%s/instances/%s", version.APIVersion, inst.Name())
 				if inst.Project() != project.Default {
 					uri += fmt.Sprintf("?project=%s", inst.Project())
@@ -416,6 +417,30 @@ func doNetworkGet(d *Daemon, name string) (api.Network, error) {
 				n.UsedBy = append(n.UsedBy, uri)
 			}
 		}
+
+		// Look for profiles.
+		var profiles []db.Profile
+		err = d.cluster.Transaction(func(tx *db.ClusterTx) error {
+			profiles, err = tx.GetProfiles(db.ProfileFilter{})
+			if err != nil {
+				return err
+			}
+
+			return nil
+		})
+		if err != nil {
+			return api.Network{}, err
+		}
+
+		for _, profile := range profiles {
+			if network.IsInUseByProfile(*db.ProfileToAPI(&profile), n.Name) {
+				uri := fmt.Sprintf("/%s/profiles/%s", version.APIVersion, profile.Name)
+				if profile.Project != project.Default {
+					uri += fmt.Sprintf("?project=%s", profile.Project)
+				}
+				n.UsedBy = append(n.UsedBy, uri)
+			}
+		}
 	}
 
 	if dbInfo != nil {

From 58c49f14870a898082338f38d8e69be0b6be858d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 18 Jun 2020 18:28:49 -0400
Subject: [PATCH 3/6] lxd/db: Tweak joins
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.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 294cb6e751..145fda4b12 100644
--- a/lxd/db/storage_pools.go
+++ b/lxd/db/storage_pools.go
@@ -77,7 +77,7 @@ func (c *ClusterTx) GetStoragePoolUsedBy(name string) ([]string, error) {
 		return []interface{}{&vols[i].volName, &vols[i].volType, &vols[i].projectName, &vols[i].nodeID}
 	}
 
-	stmt, err := c.tx.Prepare("SELECT storage_volumes.name, storage_volumes.type, projects.name, storage_volumes.node_id FROM storage_volumes LEFT JOIN projects ON projects.id=storage_volumes.project_id WHERE storage_pool_id=? AND (node_id=? OR storage_volumes.type == 2) ORDER BY storage_volumes.type ASC, projects.name ASC, storage_volumes.name ASC, storage_volumes.node_id ASC")
+	stmt, err := c.tx.Prepare("SELECT storage_volumes.name, storage_volumes.type, projects.name, storage_volumes.node_id FROM storage_volumes JOIN projects ON projects.id=storage_volumes.project_id WHERE storage_pool_id=? AND (node_id=? OR storage_volumes.type == 2) ORDER BY storage_volumes.type ASC, projects.name ASC, storage_volumes.name ASC, storage_volumes.node_id ASC")
 	if err != nil {
 		return nil, err
 	}
@@ -100,7 +100,7 @@ func (c *ClusterTx) GetStoragePoolUsedBy(name string) ([]string, error) {
 		// Handle images.
 		if r.volType == StoragePoolVolumeTypeImage {
 			// Get the projects using an image.
-			stmt := "SELECT projects.name FROM images LEFT JOIN projects ON projects.id=images.project_id WHERE fingerprint=?"
+			stmt := "SELECT projects.name FROM images JOIN projects ON projects.id=images.project_id WHERE fingerprint=?"
 			projects, err := query.SelectStrings(c.tx, stmt, r.volName)
 			if err != nil {
 				return nil, err

From fdbcb6a502b946e886769978071023cecc9a28fe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 18 Jun 2020 18:33:37 -0400
Subject: [PATCH 4/6] lxd/db: Fix UsedBy on projects
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/db/cluster/schema.go     | 14 +++++++++++---
 lxd/db/cluster/update.go     | 34 ++++++++++++++++++++++++++++++++++
 lxd/db/profiles.mapper.go    |  9 ++++++---
 lxd/db/projects.mapper.go    |  9 ++++++---
 lxd/db/storage_pools.go      |  2 +-
 shared/generate/db/method.go |  9 ++++++---
 6 files changed, 64 insertions(+), 13 deletions(-)

diff --git a/lxd/db/cluster/schema.go b/lxd/db/cluster/schema.go
index ed551c5cda..4280575b98 100644
--- a/lxd/db/cluster/schema.go
+++ b/lxd/db/cluster/schema.go
@@ -438,9 +438,17 @@ CREATE VIEW projects_used_by_ref (name,
     projects.name)
     FROM "instances" JOIN projects ON project_id=projects.id UNION
   SELECT projects.name,
-    printf('/1.0/images/%s',
-    images.fingerprint)
+    printf('/1.0/images/%s?project=%s',
+    images.fingerprint,
+    projects.name)
     FROM images JOIN projects ON project_id=projects.id UNION
+  SELECT projects.name,
+    printf('/1.0/storage-pools/%s/volumes/custom/%s?project=%s&target=%s',
+    storage_pools.name,
+    storage_volumes.name,
+    projects.name,
+    nodes.name)
+    FROM storage_volumes JOIN storage_pools ON storage_pool_id=storage_pools.id JOIN nodes ON node_id=nodes.id JOIN projects ON project_id=projects.id WHERE storage_volumes.type=2 UNION
   SELECT projects.name,
     printf('/1.0/profiles/%s?project=%s',
     profiles.name,
@@ -553,5 +561,5 @@ CREATE TABLE storage_volumes_snapshots_config (
     UNIQUE (storage_volume_snapshot_id, key)
 );
 
-INSERT INTO schema (version, updated_at) VALUES (29, strftime("%s"))
+INSERT INTO schema (version, updated_at) VALUES (30, strftime("%s"))
 `
diff --git a/lxd/db/cluster/update.go b/lxd/db/cluster/update.go
index f2bb9f8cfd..51758c5f32 100644
--- a/lxd/db/cluster/update.go
+++ b/lxd/db/cluster/update.go
@@ -66,6 +66,40 @@ var updates = map[int]schema.Update{
 	27: updateFromV26,
 	28: updateFromV27,
 	29: updateFromV28,
+	30: updateFromV29,
+}
+
+// Add storage volumes to projects references and fix images.
+func updateFromV29(tx *sql.Tx) error {
+	stmts := `
+DROP VIEW projects_used_by_ref;
+CREATE VIEW projects_used_by_ref (name,
+    value) AS
+  SELECT projects.name,
+    printf('/1.0/instances/%s?project=%s',
+    "instances".name,
+    projects.name)
+    FROM "instances" JOIN projects ON project_id=projects.id UNION
+  SELECT projects.name,
+    printf('/1.0/images/%s?project=%s',
+    images.fingerprint,
+    projects.name)
+    FROM images JOIN projects ON project_id=projects.id UNION
+  SELECT projects.name,
+    printf('/1.0/storage-pools/%s/volumes/custom/%s?project=%s&target=%s',
+    storage_pools.name,
+    storage_volumes.name,
+    projects.name,
+    nodes.name)
+    FROM storage_volumes JOIN storage_pools ON storage_pool_id=storage_pools.id JOIN nodes ON node_id=nodes.id JOIN projects ON project_id=projects.id WHERE storage_volumes.type=2 UNION
+  SELECT projects.name,
+    printf('/1.0/profiles/%s?project=%s',
+    profiles.name,
+    projects.name)
+    FROM profiles JOIN projects ON project_id=projects.id;
+`
+	_, err := tx.Exec(stmts)
+	return err
 }
 
 // Attempt to add missing project feature
diff --git a/lxd/db/profiles.mapper.go b/lxd/db/profiles.mapper.go
index 256733abfe..6df1fdcd66 100644
--- a/lxd/db/profiles.mapper.go
+++ b/lxd/db/profiles.mapper.go
@@ -278,9 +278,12 @@ func (c *ClusterTx) GetProfiles(filter ProfileFilter) ([]Profile, error) {
 		if value == nil {
 			value = []string{}
 		}
-		for j, entry := range value {
-			if len(entry) > 16 && entry[len(entry)-16:] == "?project=default" {
-				value[j] = entry[0 : len(entry)-16]
+		for j := range value {
+			if len(value[j]) > 12 && value[j][len(value[j])-12:] == "&target=none" {
+				value[j] = value[j][0 : len(value[j])-12]
+			}
+			if len(value[j]) > 16 && value[j][len(value[j])-16:] == "?project=default" {
+				value[j] = value[j][0 : len(value[j])-16]
 			}
 		}
 		objects[i].UsedBy = value
diff --git a/lxd/db/projects.mapper.go b/lxd/db/projects.mapper.go
index 01b9ef3cf5..6c8565127b 100644
--- a/lxd/db/projects.mapper.go
+++ b/lxd/db/projects.mapper.go
@@ -177,9 +177,12 @@ func (c *ClusterTx) GetProjects(filter ProjectFilter) ([]api.Project, error) {
 		if value == nil {
 			value = []string{}
 		}
-		for j, entry := range value {
-			if len(entry) > 16 && entry[len(entry)-16:] == "?project=default" {
-				value[j] = entry[0 : len(entry)-16]
+		for j := range value {
+			if len(value[j]) > 12 && value[j][len(value[j])-12:] == "&target=none" {
+				value[j] = value[j][0 : len(value[j])-12]
+			}
+			if len(value[j]) > 16 && value[j][len(value[j])-16:] == "?project=default" {
+				value[j] = value[j][0 : len(value[j])-16]
 			}
 		}
 		objects[i].UsedBy = value
diff --git a/lxd/db/storage_pools.go b/lxd/db/storage_pools.go
index 145fda4b12..e89431ad0f 100644
--- a/lxd/db/storage_pools.go
+++ b/lxd/db/storage_pools.go
@@ -117,7 +117,7 @@ func (c *ClusterTx) GetStoragePoolUsedBy(name string) ([]string, error) {
 
 		// Handle custom storage volumes.
 		if r.volType == StoragePoolVolumeTypeCustom {
-			if len(nodes) > 1 {
+			if nodesName[r.nodeID] != "none" {
 				if r.projectName == "default" {
 					usedby = append(usedby, fmt.Sprintf("/1.0/storage-pools/%s/volumes/custom/%s?target=%s", name, r.volName, nodesName[r.nodeID]))
 				} else {
diff --git a/shared/generate/db/method.go b/shared/generate/db/method.go
index acb6048121..d89b8efc5f 100644
--- a/shared/generate/db/method.go
+++ b/shared/generate/db/method.go
@@ -532,9 +532,12 @@ func (m *Method) fillSliceReferenceField(buf *file.Buffer, nk []*Field, field *F
 	buf.L("                value = %s{}", field.Type.Name)
 	buf.L("        }")
 	if field.Name == "UsedBy" {
-		buf.L("        for j, entry := range value {")
-		buf.L("                if len(entry) > 16 && entry[len(entry)-16:] == \"?project=default\" {")
-		buf.L("                         value[j] = entry[0:len(entry)-16]")
+		buf.L("        for j := range value {")
+		buf.L("                if len(value[j]) > 12 && value[j][len(value[j])-12:] == \"&target=none\" {")
+		buf.L("                         value[j] = value[j][0:len(value[j])-12]")
+		buf.L("                }")
+		buf.L("                if len(value[j]) > 16 && value[j][len(value[j])-16:] == \"?project=default\" {")
+		buf.L("                         value[j] = value[j][0:len(value[j])-16]")
 		buf.L("                }")
 		buf.L("        }")
 	}

From fe00ecde2c695a3d2fc19d990cc3af3603d5fc3a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 18 Jun 2020 19:12:42 -0400
Subject: [PATCH 5/6] lxd/storage_volumes: Fix UsedBy
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/storage_volumes.go       | 24 ++++++++++++----
 lxd/storage_volumes_utils.go | 54 +++++++++++++++++++++++-------------
 2 files changed, 53 insertions(+), 25 deletions(-)

diff --git a/lxd/storage_volumes.go b/lxd/storage_volumes.go
index f4c194fe2c..cd4ee60f7c 100644
--- a/lxd/storage_volumes.go
+++ b/lxd/storage_volumes.go
@@ -155,13 +155,25 @@ func storagePoolVolumesGet(d *Daemon, r *http.Request) response.Response {
 		if !recursion {
 			volName, snapName, ok := shared.InstanceGetParentAndSnapshotName(volume.Name)
 			if ok {
-				resultString = append(resultString,
-					fmt.Sprintf("/%s/storage-pools/%s/volumes/%s/%s/snapshots/%s",
-						version.APIVersion, poolName, apiEndpoint, volName, snapName))
+				if projectName == project.Default {
+					resultString = append(resultString,
+						fmt.Sprintf("/%s/storage-pools/%s/volumes/%s/%s/snapshots/%s",
+							version.APIVersion, poolName, apiEndpoint, volName, snapName))
+				} else {
+					resultString = append(resultString,
+						fmt.Sprintf("/%s/storage-pools/%s/volumes/%s/%s/snapshots/%s?project=%s",
+							version.APIVersion, poolName, apiEndpoint, volName, snapName, projectName))
+				}
 			} else {
-				resultString = append(resultString,
-					fmt.Sprintf("/%s/storage-pools/%s/volumes/%s/%s",
-						version.APIVersion, poolName, apiEndpoint, volume.Name))
+				if projectName == project.Default {
+					resultString = append(resultString,
+						fmt.Sprintf("/%s/storage-pools/%s/volumes/%s/%s",
+							version.APIVersion, poolName, apiEndpoint, volume.Name))
+				} else {
+					resultString = append(resultString,
+						fmt.Sprintf("/%s/storage-pools/%s/volumes/%s/%s?project=%s",
+							version.APIVersion, poolName, apiEndpoint, volume.Name, projectName))
+				}
 			}
 		} else {
 			volumeUsedBy, err := storagePoolVolumeUsedByGet(d.State(), projectName, poolName, volume.Name, volume.Type)
diff --git a/lxd/storage_volumes_utils.go b/lxd/storage_volumes_utils.go
index 7a014e13af..9de58c8cdf 100644
--- a/lxd/storage_volumes_utils.go
+++ b/lxd/storage_volumes_utils.go
@@ -203,24 +203,35 @@ func storagePoolVolumeUpdateUsers(d *Daemon, projectName string, oldPoolName str
 }
 
 // volumeUsedBy = append(volumeUsedBy, fmt.Sprintf("/%s/containers/%s", version.APIVersion, ct))
-func storagePoolVolumeUsedByGet(s *state.State, project, poolName string, volumeName string, volumeTypeName string) ([]string, error) {
-	// Handle container volumes
-	if volumeTypeName == "container" {
+func storagePoolVolumeUsedByGet(s *state.State, projectName string, poolName string, volumeName string, volumeTypeName string) ([]string, error) {
+	// Handle instance volumes.
+	if volumeTypeName == "container" || volumeTypeName == "virtual-machine" {
 		cName, sName, snap := shared.InstanceGetParentAndSnapshotName(volumeName)
-
 		if snap {
-			return []string{fmt.Sprintf("/%s/containers/%s/snapshots/%s", version.APIVersion, cName, sName)}, nil
+			if projectName == project.Default {
+				return []string{fmt.Sprintf("/%s/instances/%s/snapshots/%s", version.APIVersion, cName, sName)}, nil
+			} else {
+				return []string{fmt.Sprintf("/%s/instances/%s/snapshots/%s?project=%s", version.APIVersion, cName, sName, projectName)}, nil
+			}
 		}
 
-		return []string{fmt.Sprintf("/%s/containers/%s", version.APIVersion, cName)}, nil
+		if projectName == project.Default {
+			return []string{fmt.Sprintf("/%s/instances/%s", version.APIVersion, cName)}, nil
+		} else {
+			return []string{fmt.Sprintf("/%s/instances/%s?project=%s", version.APIVersion, cName, projectName)}, nil
+		}
 	}
 
-	// Handle image volumes
+	// Handle image volumes.
 	if volumeTypeName == "image" {
-		return []string{fmt.Sprintf("/%s/images/%s", version.APIVersion, volumeName)}, nil
+		if projectName == project.Default {
+			return []string{fmt.Sprintf("/%s/images/%s", version.APIVersion, volumeName)}, nil
+		} else {
+			return []string{fmt.Sprintf("/%s/images/%s?project=%s", version.APIVersion, volumeName, projectName)}, nil
+		}
 	}
 
-	// Check if the daemon itself is using it
+	// Check if the daemon itself is using it.
 	used, err := storagePools.VolumeUsedByDaemon(s, poolName, volumeName)
 	if err != nil {
 		return []string{}, err
@@ -230,29 +241,34 @@ func storagePoolVolumeUsedByGet(s *state.State, project, poolName string, volume
 		return []string{fmt.Sprintf("/%s", version.APIVersion)}, nil
 	}
 
-	// Look for containers using this volume
-	ctsUsingVolume, err := storagePools.VolumeUsedByInstancesGet(s, project, poolName, volumeName)
+	// Look for instances using this volume.
+	volumeUsedBy := []string{}
+
+	ctsUsingVolume, err := storagePools.VolumeUsedByInstancesGet(s, projectName, poolName, volumeName)
 	if err != nil {
 		return []string{}, err
 	}
 
-	volumeUsedBy := []string{}
 	for _, ct := range ctsUsingVolume {
-		volumeUsedBy = append(volumeUsedBy,
-			fmt.Sprintf("/%s/containers/%s", version.APIVersion, ct))
+		if projectName == project.Default {
+			volumeUsedBy = append(volumeUsedBy, fmt.Sprintf("/%s/instances/%s", version.APIVersion, ct))
+		} else {
+			volumeUsedBy = append(volumeUsedBy, fmt.Sprintf("/%s/instances/%s?project=%s", version.APIVersion, ct, projectName))
+		}
 	}
 
+	// Look for profiles using this volume.
 	profiles, err := profilesUsingPoolVolumeGetNames(s.Cluster, volumeName, volumeTypeName)
 	if err != nil {
 		return []string{}, err
 	}
 
-	if len(volumeUsedBy) == 0 && len(profiles) == 0 {
-		return []string{}, nil
-	}
-
 	for _, pName := range profiles {
-		volumeUsedBy = append(volumeUsedBy, fmt.Sprintf("/%s/profiles/%s", version.APIVersion, pName))
+		if projectName == project.Default {
+			volumeUsedBy = append(volumeUsedBy, fmt.Sprintf("/%s/profiles/%s", version.APIVersion, pName))
+		} else {
+			volumeUsedBy = append(volumeUsedBy, fmt.Sprintf("/%s/profiles/%s?project=%s", version.APIVersion, pName, projectName))
+		}
 	}
 
 	return volumeUsedBy, nil

From 6ca075cd2b56fd796477f37916019d9ce728db28 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 18 Jun 2020 19:32:07 -0400
Subject: [PATCH 6/6] api: usedby_consistency
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Closes #7518

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 doc/api-extensions.md | 11 +++++++++++
 shared/version/api.go |  1 +
 2 files changed, 12 insertions(+)

diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index a5d7c6a655..2e32afd456 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -1077,3 +1077,14 @@ Bridge:
 ## resources\_cpu\_isolated
 Add an `Isolated` property on CPU threads to indicate if the thread is
 physically `Online` but is configured not to accept tasks.
+
+## usedby\_consistency
+This extension indicates that UsedBy should now be consistent with
+suitable ?project= and ?target= when appropriate.
+
+The 5 entities that have UsedBy are:
+ - Profiles
+ - Projects
+ - Networks
+ - Storage pools
+ - Storage volumes
diff --git a/shared/version/api.go b/shared/version/api.go
index f5b80fe004..340c4389e6 100644
--- a/shared/version/api.go
+++ b/shared/version/api.go
@@ -214,6 +214,7 @@ var APIExtensions = []string{
 	"container_nic_routed_limits",
 	"instance_nic_bridged_vlan",
 	"network_state_bond_bridge",
+	"usedby_consistency",
 }
 
 // APIExtensionsCount returns the number of available API extensions.


More information about the lxc-devel mailing list