The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/7552
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) ===
From 7b91d36fa35fa67a167d07842a9771d31687dc07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@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 <stgra...@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?= <stgra...@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 <stgra...@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?= <stgra...@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 <stgra...@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?= <stgra...@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 <stgra...@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?= <stgra...@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 <stgra...@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?= <stgra...@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 <stgra...@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.
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel