The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/6897

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) ===
- The check for ".importing" file wasn't project aware, could cause the container on storage device to be incorrectly removed.
- When using `--force` flag, the old DB volume records removal code was not project aware, preventing the container from being imported.
From 1d9e00c0bb7633d81752cec6e7d97335eaac3b6b Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 19 Feb 2020 11:05:14 +0000
Subject: [PATCH 1/6] lxd/api/internal: Removes duplicate storage package
 import

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/api_internal.go | 23 +++++++++++------------
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/lxd/api_internal.go b/lxd/api_internal.go
index 8bbcbb20c0..e514c67d00 100644
--- a/lxd/api_internal.go
+++ b/lxd/api_internal.go
@@ -25,7 +25,6 @@ import (
        "github.com/lxc/lxd/lxd/instance/instancetype"
        "github.com/lxc/lxd/lxd/project"
        "github.com/lxc/lxd/lxd/response"
-       driver "github.com/lxc/lxd/lxd/storage"
        storagePools "github.com/lxc/lxd/lxd/storage"
        storageDrivers "github.com/lxc/lxd/lxd/storage/drivers"
        "github.com/lxc/lxd/shared"
@@ -430,7 +429,7 @@ func internalImport(d *Daemon, r *http.Request) 
response.Response {
        containerMntPoints := []string{}
        containerPoolName := ""
        for _, poolName := range storagePoolNames {
-               containerMntPoint := driver.GetContainerMountPoint(projectName, 
poolName, req.Name)
+               containerMntPoint := 
storagePools.GetContainerMountPoint(projectName, poolName, req.Name)
                if shared.PathExists(containerMntPoint) {
                        containerMntPoints = append(containerMntPoints, 
containerMntPoint)
                        containerPoolName = poolName
@@ -545,7 +544,7 @@ func internalImport(d *Daemon, r *http.Request) 
response.Response {
        if len(backup.Snapshots) > 0 {
                switch backup.Pool.Driver {
                case "btrfs":
-                       snapshotsDirPath := 
driver.GetSnapshotMountPoint(projectName, poolName, req.Name)
+                       snapshotsDirPath := 
storagePools.GetSnapshotMountPoint(projectName, poolName, req.Name)
                        snapshotsDir, err := os.Open(snapshotsDirPath)
                        if err != nil {
                                return response.InternalError(err)
@@ -557,7 +556,7 @@ func internalImport(d *Daemon, r *http.Request) 
response.Response {
                        }
                        snapshotsDir.Close()
                case "dir":
-                       snapshotsDirPath := 
driver.GetSnapshotMountPoint(projectName, poolName, req.Name)
+                       snapshotsDirPath := 
storagePools.GetSnapshotMountPoint(projectName, poolName, req.Name)
                        snapshotsDir, err := os.Open(snapshotsDirPath)
                        if err != nil {
                                return response.InternalError(err)
@@ -676,7 +675,7 @@ func internalImport(d *Daemon, r *http.Request) 
response.Response {
                                onDiskPoolName = poolName
                        }
                        snapName := fmt.Sprintf("%s/%s", req.Name, od)
-                       snapPath := driver.InstancePath(instancetype.Container, 
projectName, snapName, true)
+                       snapPath := 
storagePools.InstancePath(instancetype.Container, projectName, snapName, true)
                        err = lvmContainerDeleteInternal(projectName, poolName, 
req.Name,
                                true, onDiskPoolName, snapPath)
                case "ceph":
@@ -712,15 +711,15 @@ func internalImport(d *Daemon, r *http.Request) 
response.Response {
        for _, snap := range backup.Snapshots {
                switch backup.Pool.Driver {
                case "btrfs":
-                       snpMntPt := driver.GetSnapshotMountPoint(projectName, 
backup.Pool.Name, snap.Name)
-                       if !shared.PathExists(snpMntPt) || 
!isBtrfsSubVolume(snpMntPt) {
+                       snpMntPt := 
storagePools.GetSnapshotMountPoint(projectName, backup.Pool.Name, snap.Name)
+                       if !shared.PathExists(snpMntPt) || 
!btrfsIsSubVolume(snpMntPt) {
                                if req.Force {
                                        continue
                                }
                                return response.BadRequest(needForce)
                        }
                case "dir":
-                       snpMntPt := driver.GetSnapshotMountPoint(projectName, 
backup.Pool.Name, snap.Name)
+                       snpMntPt := 
storagePools.GetSnapshotMountPoint(projectName, backup.Pool.Name, snap.Name)
                        if !shared.PathExists(snpMntPt) {
                                if req.Force {
                                        continue
@@ -903,12 +902,12 @@ func internalImport(d *Daemon, r *http.Request) 
response.Response {
                return response.SmartError(err)
        }
 
-       containerPath := driver.InstancePath(instancetype.Container, 
projectName, req.Name, false)
+       containerPath := storagePools.InstancePath(instancetype.Container, 
projectName, req.Name, false)
        isPrivileged := false
        if backup.Container.Config["security.privileged"] == "" {
                isPrivileged = true
        }
-       err = driver.CreateContainerMountpoint(containerMntPoint, containerPath,
+       err = storagePools.CreateContainerMountpoint(containerMntPoint, 
containerPath,
                isPrivileged)
        if err != nil {
                return response.InternalError(err)
@@ -1005,13 +1004,13 @@ func internalImport(d *Daemon, r *http.Request) 
response.Response {
                }
 
                // Recreate missing mountpoints and symlinks.
-               snapshotMountPoint := driver.GetSnapshotMountPoint(projectName, 
backup.Pool.Name,
+               snapshotMountPoint := 
storagePools.GetSnapshotMountPoint(projectName, backup.Pool.Name,
                        snap.Name)
                sourceName, _, _ := 
shared.InstanceGetParentAndSnapshotName(snap.Name)
                sourceName = project.Prefix(projectName, sourceName)
                snapshotMntPointSymlinkTarget := 
shared.VarPath("storage-pools", backup.Pool.Name, "containers-snapshots", 
sourceName)
                snapshotMntPointSymlink := shared.VarPath("snapshots", 
sourceName)
-               err = driver.CreateSnapshotMountpoint(snapshotMountPoint, 
snapshotMntPointSymlinkTarget, snapshotMntPointSymlink)
+               err = storagePools.CreateSnapshotMountpoint(snapshotMountPoint, 
snapshotMntPointSymlinkTarget, snapshotMntPointSymlink)
                if err != nil {
                        return response.InternalError(err)
                }

From 67bd345875735aae405e1ecd4f68cee9d876cbb3 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 19 Feb 2020 11:05:50 +0000
Subject: [PATCH 2/6] lxd/storage: Adds InstanceImportingFilePath function

This centralises the logic of generating the ".importing" file for detection of 
`lxd import` to avoid issues with the file creating logic being different to 
the file checking logic.

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/storage/storage.go | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/lxd/storage/storage.go b/lxd/storage/storage.go
index a30471982b..8a37e3ae43 100644
--- a/lxd/storage/storage.go
+++ b/lxd/storage/storage.go
@@ -26,6 +26,21 @@ func InstancePath(instanceType instancetype.Type, 
projectName, instanceName stri
        return shared.VarPath("containers", fullName)
 }
 
+// InstanceImportingFilePath returns the file path used to indicate an 
instance import is in progress.
+// This marker file is created when using `lxd import` to import an instance 
that exists on the storage device
+// but does not exist in the LXD database. The presence of this file causes 
the instance not to be removed from
+// the storage device if the import should fail for some reason.
+func InstanceImportingFilePath(instanceType instancetype.Type, poolName, 
projectName, instanceName string) string {
+       fullName := project.Prefix(projectName, instanceName)
+
+       typeDir := "containers"
+       if instanceType == instancetype.VM {
+               typeDir = "virtual-machines"
+       }
+
+       return shared.VarPath("storage-pools", poolName, typeDir, fullName, 
".importing")
+}
+
 // GetStoragePoolMountPoint returns the mountpoint of the given pool.
 // {LXD_DIR}/storage-pools/<pool>
 // Deprecated, use GetPoolMountPath in storage/drivers package.

From 4ad0c146a4bbe5bb98e6c253835992260f56b2e4 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 19 Feb 2020 11:05:35 +0000
Subject: [PATCH 3/6] lxd/api/internal: storagePools.InstanceImportingFilePath
 usage

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/api_internal.go | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lxd/api_internal.go b/lxd/api_internal.go
index e514c67d00..4d11c85d54 100644
--- a/lxd/api_internal.go
+++ b/lxd/api_internal.go
@@ -850,7 +850,8 @@ func internalImport(d *Daemon, r *http.Request) 
response.Response {
        rootDev["pool"] = containerPoolName
 
        // Mark the filesystem as going through an import
-       fd, err := os.Create(filepath.Join(containerMntPoint, ".importing"))
+       importingFilePath := 
storagePools.InstanceImportingFilePath(instancetype.Container, 
containerPoolName, projectName, req.Name)
+       fd, err := os.Create(importingFilePath)
        if err != nil {
                return response.InternalError(err)
        }

From fca9ccce6318c8b9bb46570e608dccc171f58eca Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 19 Feb 2020 11:06:48 +0000
Subject: [PATCH 4/6] lxd/container/lxc: storagePools.InstanceImportingFilePath
 usage

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/container_lxc.go | 27 ++++++++-------------------
 1 file changed, 8 insertions(+), 19 deletions(-)

diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 361ff52d6e..2fb6e0f705 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -3454,16 +3454,10 @@ func (c *containerLXC) Delete() error {
                // the creation of the instance and we are now being asked to 
delete the instance,
                // we should not remove the storage volumes themselves as this 
would cause data loss.
                isImport := false
-               poolName := pool.Name()
-               if c.IsSnapshot() {
-                       cName, _, _ := 
shared.InstanceGetParentAndSnapshotName(c.name)
-                       if shared.PathExists(shared.VarPath("storage-pools", 
poolName, "containers", cName, ".importing")) {
-                               isImport = true
-                       }
-               } else {
-                       if shared.PathExists(shared.VarPath("storage-pools", 
poolName, "containers", c.name, ".importing")) {
-                               isImport = true
-                       }
+               cName, _, _ := shared.InstanceGetParentAndSnapshotName(c.Name())
+               importingFilePath := 
storagePools.InstanceImportingFilePath(c.Type(), pool.Name(), c.Project(), 
cName)
+               if shared.PathExists(importingFilePath) {
+                       isImport = true
                }
 
                if c.IsSnapshot() {
@@ -3508,15 +3502,10 @@ func (c *containerLXC) Delete() error {
                // the creation of the instance and we are now being asked to 
delete the instance,
                // we should not remove the storage volumes themselves as this 
would cause data loss.
                isImport := false
-               if c.IsSnapshot() {
-                       cName, _, _ := 
shared.InstanceGetParentAndSnapshotName(c.name)
-                       if shared.PathExists(shared.VarPath("storage-pools", 
poolName, "containers", cName, ".importing")) {
-                               isImport = true
-                       }
-               } else {
-                       if shared.PathExists(shared.VarPath("storage-pools", 
poolName, "containers", c.name, ".importing")) {
-                               isImport = true
-                       }
+               cName, _, _ := shared.InstanceGetParentAndSnapshotName(c.Name())
+               importingFilePath := 
storagePools.InstanceImportingFilePath(c.Type(), poolName, c.Project(), cName)
+               if shared.PathExists(importingFilePath) {
+                       isImport = true
                }
 
                if c.IsSnapshot() {

From 08549f8c7b18e144d81d229c209f37c8dd883ed5 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 19 Feb 2020 11:32:41 +0000
Subject: [PATCH 5/6] lxd/api: projectParam comments

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

diff --git a/lxd/api.go b/lxd/api.go
index cdca5ae0c7..999e0fad4a 100644
--- a/lxd/api.go
+++ b/lxd/api.go
@@ -120,7 +120,7 @@ func isClusterNotification(r *http.Request) bool {
        return r.Header.Get("User-Agent") == "lxd-cluster-notifier"
 }
 
-// Extract the project query parameter from the given request.
+// 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 == "" {

From 29632577a9bfb7709ee66f87adcaf9e0bb02ba65 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 19 Feb 2020 11:33:14 +0000
Subject: [PATCH 6/6] lxd/api/internal: Uses
 StoragePoolNodeVolumeGetTypeByProject for project support

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/api_internal.go | 20 ++++++++------------
 1 file changed, 8 insertions(+), 12 deletions(-)

diff --git a/lxd/api_internal.go b/lxd/api_internal.go
index 4d11c85d54..8e6cab8f35 100644
--- a/lxd/api_internal.go
+++ b/lxd/api_internal.go
@@ -788,13 +788,13 @@ func internalImport(d *Daemon, r *http.Request) 
response.Response {
        }
 
        // Check if a storage volume entry for the container already exists.
-       _, volume, ctVolErr := d.cluster.StoragePoolNodeVolumeGetType(
-               req.Name, storagePoolVolumeTypeContainer, poolID)
+       _, volume, ctVolErr := 
d.cluster.StoragePoolNodeVolumeGetTypeByProject(projectName, req.Name, 
storagePoolVolumeTypeContainer, poolID)
        if ctVolErr != nil {
                if ctVolErr != db.ErrNoSuchObject {
                        return response.SmartError(ctVolErr)
                }
        }
+
        // If a storage volume entry exists only proceed if force was specified.
        if ctVolErr == nil && !req.Force {
                return response.BadRequest(fmt.Errorf(`Storage volume for 
instance %q already exists in the database. Set "force" to overwrite`, 
req.Name))
@@ -807,6 +807,7 @@ func internalImport(d *Daemon, r *http.Request) 
response.Response {
                        return response.SmartError(containerErr)
                }
        }
+
        // If a db entry exists only proceed if force was specified.
        if containerErr == nil && !req.Force {
                return response.BadRequest(fmt.Errorf(`Entry for instance %q 
already exists in the database. Set "force" to overwrite`, req.Name))
@@ -825,18 +826,15 @@ func internalImport(d *Daemon, r *http.Request) 
response.Response {
                        return response.BadRequest(fmt.Errorf(`The type %q of 
the storage volume is not identical to the instance's type %q`, volume.Type, 
backup.Volume.Type))
                }
 
-               // Remove the storage volume db entry for the container since
-               // force was specified.
-               err := d.cluster.StoragePoolVolumeDelete("default", req.Name,
-                       storagePoolVolumeTypeContainer, poolID)
+               // Remove the storage volume db entry for the container since 
force was specified.
+               err := d.cluster.StoragePoolVolumeDelete(projectName, req.Name, 
storagePoolVolumeTypeContainer, poolID)
                if err != nil {
                        return response.SmartError(err)
                }
        }
 
        if containerErr == nil {
-               // Remove the storage volume db entry for the container since
-               // force was specified.
+               // Remove the storage volume db entry for the container since 
force was specified.
                err := d.cluster.InstanceRemove(projectName, req.Name)
                if err != nil {
                        return response.SmartError(err)
@@ -931,8 +929,7 @@ func internalImport(d *Daemon, r *http.Request) 
response.Response {
                }
 
                // Check if a storage volume entry for the snapshot already 
exists.
-               _, _, csVolErr := 
d.cluster.StoragePoolNodeVolumeGetTypeByProject(
-                       projectName, snap.Name, storagePoolVolumeTypeContainer, 
poolID)
+               _, _, csVolErr := 
d.cluster.StoragePoolNodeVolumeGetTypeByProject(projectName, snap.Name, 
storagePoolVolumeTypeContainer, poolID)
                if csVolErr != nil {
                        if csVolErr != db.ErrNoSuchObject {
                                return response.SmartError(csVolErr)
@@ -952,8 +949,7 @@ func internalImport(d *Daemon, r *http.Request) 
response.Response {
                }
 
                if csVolErr == nil {
-                       err := d.cluster.StoragePoolVolumeDelete(projectName, 
snap.Name,
-                               storagePoolVolumeTypeContainer, poolID)
+                       err := d.cluster.StoragePoolVolumeDelete(projectName, 
snap.Name, storagePoolVolumeTypeContainer, poolID)
                        if err != nil {
                                return response.SmartError(err)
                        }
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to